From 2fb7759512bc2f0fc602a4e475468e8560a7c116 Mon Sep 17 00:00:00 2001 From: qu1ckkkk Date: Sat, 12 Apr 2014 20:23:04 +0200 Subject: [PATCH] First Public Release --- .gitattributes | 1 + .gitignore | 8 + README.md | 50 +- app/commands/.gitkeep | 0 app/commands/SeatAPIDeleteKey.php | 75 + app/commands/SeatAPIFindKeyByName.php | 69 + app/commands/SeatAPIFindNameByKey.php | 70 + app/commands/SeatAPIFindSickKeys.php | 54 + app/commands/SeatAPIUpdate.php | 86 + app/commands/SeatQueueStatus.php | 96 + app/commands/SeatReset.php | 69 + .../scheduled/EveCharacterUpdater.php | 74 + .../scheduled/EveCorporationAssetsUpdater.php | 74 + .../scheduled/EveCorporationUpdater.php | 74 + .../scheduled/EveCorporationWalletUpdater.php | 74 + app/commands/scheduled/EveEveUpdater.php | 62 + app/commands/scheduled/EveMapUpdater.php | 61 + app/commands/scheduled/EveServerUpdater.php | 63 + app/config/app.php | 179 ++ app/config/auth.php | 71 + app/config/cache.php | 89 + app/config/compile.php | 18 + app/config/database.php | 124 + app/config/mail.php | 124 + app/config/packages/.gitkeep | 0 app/config/queue.php | 82 + app/config/remote.php | 59 + app/config/seat.php | 14 + app/config/session.php | 140 + app/config/testing/cache.php | 20 + app/config/testing/session.php | 21 + app/config/view.php | 31 + app/config/workbench.php | 31 + app/controllers/.gitkeep | 0 app/controllers/ApiKeyController.php | 302 ++ app/controllers/BaseController.php | 18 + app/controllers/CharacterController.php | 200 ++ app/controllers/CorporationController.php | 280 ++ app/controllers/DashboardController.php | 14 + app/controllers/DebugController.php | 87 + app/controllers/HelperController.php | 78 + app/controllers/HomeController.php | 24 + app/controllers/MailController.php | 72 + app/controllers/QueueController.php | 101 + app/controllers/RegisterController.php | 23 + app/controllers/RemindersController.php | 81 + app/controllers/UserController.php | 70 + app/database/migrations/.gitkeep | 0 .../2014_03_19_155606_CreateUsersTable.php | 38 + .../2014_03_20_082745_CreateKeysTable.php | 40 + ..._03_20_205253_create_failed_jobs_table.php | 35 + ...2014_03_22_065049_CreateEveApiCalllist.php | 38 + ..._22_075805_CreateEveServerServerStatus.php | 37 + ...4_03_22_091556_CreateEveMapSovereignty.php | 43 + ...2014_03_22_101039_CreateEveCachedUntil.php | 44 + .../2014_03_22_144822_CreateEveMapKills.php | 38 + .../2014_03_22_162427_CreateEveMapJumps.php | 36 + ...014_03_22_193618_CreateEveEveErrorList.php | 39 + ...2014_03_23_102357_CreateEveEveRefTypes.php | 39 + ...254_CreateEveEveConquerableStationList.php | 42 + ...03_23_151953_CreateEveEveCharacterInfo.php | 62 + ...teEveEveCharacterInfoEmploymentHistory.php | 40 + ..._03_23_184711_CreateEveEveAllianceList.php | 45 + ...teEveEveAllianceListMemberCorporations.php | 39 + ...3_24_104019_CreateEveAccountAPIKeyInfo.php | 39 + ...7_CreateEveAccountAPIKeyInfoCharacters.php | 44 + ...4_122157_CreateEveAccountAccountStatus.php | 44 + ...2014_03_25_113533_CreateSeatBannedCall.php | 44 + ...3_26_045031_CreateSeatQueueInformation.php | 45 + ...61501_CreateEveCharacterAccountBalance.php | 43 + ..._27_085631_CreateEveCharacterAssetList.php | 48 + ...45_CreateEveCharacterAssetListContents.php | 47 + ...4_03_27_121947_CreateEveCharacterSheet.php | 61 + ...7_141418_CreateEveCharacterSheetSkills.php | 45 + ...8_074924_CreateEveCharacterContactList.php | 47 + ...CreateEveCharacterCorporateContactList.php | 46 + ..._CreateEveCharacterAllianceContactList.php | 46 + ...CreateEveCharacterContactNotifications.php | 46 + ..._28_114602_CreateEveCharacterContracts.php | 63 + ...24422_CreateEveCharacterContractsItems.php | 49 + ..._145406_CreateEveCharacterIndustryJobs.php | 74 + ..._163740_CreateEveCharacterMailMessages.php | 50 + ...28_173326_CreateEveCharacterMailBodies.php | 41 + ..._044308_CreateEveCharacterMailingLists.php | 41 + ..._075707_CreateEveCharacterMarketOrders.php | 53 + ...9_093955_CreateEveEveNotificationTypes.php | 36 + ...104513_CreateEveCharacterNotifications.php | 46 + ...22_CreateEveCharacterNotificationTexts.php | 39 + ...3_29_145832_CreateEveCharacterResearch.php | 43 + ...0937_CreateEveCharacterSkillInTraining.php | 46 + ...29_192807_CreateEveCharacterSkillQueue.php | 45 + ...0727_CreateEveCharacterStandingsAgents.php | 42 + ...teEveCharacterStandingsNPCCorporations.php | 42 + ...10_CreateEveCharacterStandingsFactions.php | 42 + ...eateEveCharacterUpcomingCalendarEvents.php | 49 + ...161440_CreateEveCharacterWalletJournal.php | 60 + ...7_CreateEveCharacterWalletTransactions.php | 58 + ...920_CreateEveCorporationAccountBalance.php | 43 + ...1_151652_CreateEveCorporationAssetList.php | 47 + ..._CreateEveCorporationAssetListContents.php | 45 + ...reateEveCorporationAllianceContactList.php | 44 + ...eateEveCorporationCorporateContactList.php | 44 + ...1_170702_CreateEveCorporationContracts.php | 61 + ...730_CreateEveCorporationContractsItems.php | 49 + ...04_02_110839_CreateEveCorporationSheet.php | 65 + ...815_CreateEveCorporationSheetDivisions.php | 42 + ...eateEveCorporationSheetWalletDivisions.php | 42 + ...14928_CreateEveCorporationIndustryJobs.php | 73 + ...CreateEveCorporationAssetListLocations.php | 44 + ...62945_CreateEveCorporationMarketOrders.php | 55 + ...4_02_165032_CreateEveCorporationMedals.php | 43 + ...71402_CreateEveCorporationMemberMedals.php | 44 + ...reateEveCorporationMemberSecurityRoles.php | 45 + ...orporationMemberSecurityGrantableRoles.php | 45 + ...eEveCorporationMemberSecurityRolesAtHQ.php | 45 + ...rationMemberSecurityGrantableRolesAtHQ.php | 45 + ...veCorporationMemberSecurityRolesAtBase.php | 45 + ...tionMemberSecurityGrantableRolesAtBase.php | 45 + ...eCorporationMemberSecurityRolesAtOther.php | 45 + ...ionMemberSecurityGrantableRolesAtOther.php | 45 + ...eateEveCorporationMemberSecurityTitles.php | 45 + ..._CreateEveCorporationMemberSecurityLog.php | 50 + ...EveCorporationMemberSecurityLogDetails.php | 40 + ...203_CreateEveCorporationMemberTracking.php | 53 + ...ateEveCorporationShareholderCharacters.php | 44 + ...eEveCorporationShareholderCorporations.php | 42 + ...08_CreateEveCorporationStandingsAgents.php | 42 + ...EveCorporationStandingsNPCCorporations.php | 42 + ..._CreateEveCorporationStandingsFactions.php | 42 + ...10700_CreateEveCorporationStarbaseList.php | 48 + ...920_CreateEveCorporationStarbaseDetail.php | 56 + ...5021_CreateEveCorporationWalletJournal.php | 60 + ...CreateEveCorporationWalletTransactions.php | 60 + ...orporationAssetListLocationsAddMapData.php | 36 + ...113830_create_password_reminders_table.php | 33 + app/database/seeds/.gitkeep | 0 app/database/seeds/DatabaseSeeder.php | 18 + .../seeds/EveApiCalllistTableSeeder.php | 67 + .../seeds/EveNotificationTypesSeeder.php | 141 + app/database/seeds/UserTableSeeder.php | 16 + app/eveapi/Api.php | 20 + app/eveapi/BaseAPI.php | 431 +++ app/eveapi/account/AccountAPIKeyInfo.php | 100 + app/eveapi/account/AccountAccountStatus.php | 72 + .../character/CharacterAccountBalance.php | 99 + app/eveapi/character/CharacterAssetList.php | 120 + .../character/CharacterCharacterSheet.php | 124 + app/eveapi/character/CharacterContactList.php | 134 + .../CharacterContactNotifications.php | 99 + app/eveapi/character/CharacterContracts.php | 161 + .../character/CharacterIndustryJobs.php | 127 + .../character/CharacterMailMessages.php | 149 + .../character/CharacterMailingLists.php | 98 + .../character/CharacterMarketOrders.php | 107 + .../character/CharacterNotifications.php | 147 + app/eveapi/character/CharacterResearch.php | 99 + .../character/CharacterSkillInTraining.php | 103 + app/eveapi/character/CharacterSkillQueue.php | 99 + app/eveapi/character/CharacterStandings.php | 129 + .../CharacterUpcomingCalendarEvents.php | 102 + .../character/CharacterWalletJournal.php | 140 + .../character/CharacterWalletTransactions.php | 136 + .../corporation/CorporationAccountBalance.php | 96 + .../corporation/CorporationAssetList.php | 176 ++ .../corporation/CorporationContactList.php | 117 + .../corporation/CorporationContracts.php | 162 + .../CorporationCorporationSheet.php | 142 + .../corporation/CorporationIndustryJobs.php | 126 + .../corporation/CorporationMarketOrders.php | 109 + app/eveapi/corporation/CorporationMedals.php | 97 + .../corporation/CorporationMemberMedals.php | 99 + .../corporation/CorporationMemberSecurity.php | 259 ++ .../CorporationMemberSecurityLog.php | 122 + .../corporation/CorporationMemberTracking.php | 109 + .../corporation/CorporationShareholders.php | 114 + .../corporation/CorporationStandings.php | 130 + .../corporation/CorporationStarbaseDetail.php | 111 + .../corporation/CorporationStarbaseList.php | 130 + .../corporation/CorporationWalletJournal.php | 144 + .../CorporationWalletTransactions.php | 144 + app/eveapi/eve/EveAllianceList.php | 75 + app/eveapi/eve/EveCharacterInfo.php | 100 + app/eveapi/eve/EveConquerableStationList.php | 62 + app/eveapi/eve/EveErrorList.php | 59 + app/eveapi/eve/EveRefTypes.php | 59 + app/eveapi/map/MapJumps.php | 59 + app/eveapi/map/MapKills.php | 61 + app/eveapi/map/MapSovereignty.php | 63 + app/eveapi/server/ServerServerStatus.php | 69 + app/filters.php | 95 + app/lang/en/pagination.php | 20 + app/lang/en/reminders.php | 24 + app/lang/en/validation.php | 98 + app/models/Elegant.php | 30 + app/models/EveAccountAPIKeyInfo.php | 24 + app/models/EveAccountAPIKeyInfoCharacters.php | 14 + app/models/EveAccountAccountStatus.php | 14 + app/models/EveApiCalllist.php | 9 + app/models/EveBannedCall.php | 9 + app/models/EveCachedUntil.php | 10 + app/models/EveCharacterAccountBalance.php | 9 + app/models/EveCharacterAssetList.php | 14 + app/models/EveCharacterAssetListContents.php | 14 + app/models/EveCharacterCharacterSheet.php | 14 + .../EveCharacterCharacterSheetSkills.php | 14 + app/models/EveCharacterContactList.php | 9 + .../EveCharacterContactListAlliance.php | 9 + .../EveCharacterContactListCorporate.php | 9 + .../EveCharacterContactNotifications.php | 9 + app/models/EveCharacterContracts.php | 14 + app/models/EveCharacterContractsItems.php | 14 + app/models/EveCharacterIndustryJobs.php | 9 + app/models/EveCharacterMailBodies.php | 14 + app/models/EveCharacterMailMessages.php | 14 + app/models/EveCharacterMailingLists.php | 9 + app/models/EveCharacterMarketOrders.php | 9 + app/models/EveCharacterNotificationTexts.php | 14 + app/models/EveCharacterNotifications.php | 14 + app/models/EveCharacterResearch.php | 9 + app/models/EveCharacterSkillInTraining.php | 9 + app/models/EveCharacterSkillQueue.php | 9 + app/models/EveCharacterStandingsAgents.php | 9 + app/models/EveCharacterStandingsFactions.php | 9 + .../EveCharacterStandingsNPCCorporations.php | 9 + .../EveCharacterUpcomingCalendarEvents.php | 9 + app/models/EveCharacterWalletJournal.php | 9 + app/models/EveCharacterWalletTransactions.php | 9 + app/models/EveCorporationAccountBalance.php | 9 + app/models/EveCorporationAssetList.php | 14 + .../EveCorporationAssetListContents.php | 14 + .../EveCorporationAssetListLocations.php | 9 + .../EveCorporationContactListAlliance.php | 9 + .../EveCorporationContactListCorporate.php | 9 + app/models/EveCorporationContracts.php | 14 + app/models/EveCorporationContractsItems.php | 14 + app/models/EveCorporationCorporationSheet.php | 19 + ...veCorporationCorporationSheetDivisions.php | 14 + ...orationCorporationSheetWalletDivisions.php | 14 + app/models/EveCorporationIndustryJobs.php | 9 + app/models/EveCorporationMarketOrders.php | 9 + app/models/EveCorporationMedals.php | 9 + app/models/EveCorporationMemberMedals.php | 9 + ...orporationMemberSecurityGrantableRoles.php | 9 + ...tionMemberSecurityGrantableRolesAtBase.php | 9 + ...rationMemberSecurityGrantableRolesAtHQ.php | 9 + ...ionMemberSecurityGrantableRolesAtOther.php | 9 + .../EveCorporationMemberSecurityLog.php | 14 + ...EveCorporationMemberSecurityLogDetails.php | 14 + .../EveCorporationMemberSecurityRoles.php | 9 + ...veCorporationMemberSecurityRolesAtBase.php | 9 + .../EveCorporationMemberSecurityRolesAtHQ.php | 9 + ...eCorporationMemberSecurityRolesAtOther.php | 9 + .../EveCorporationMemberSecurityTitles.php | 9 + app/models/EveCorporationMemberTracking.php | 9 + .../EveCorporationShareholderCharacters.php | 9 + .../EveCorporationShareholderCorporations.php | 9 + app/models/EveCorporationStandingsAgents.php | 9 + .../EveCorporationStandingsFactions.php | 9 + ...EveCorporationStandingsNPCCorporations.php | 9 + app/models/EveCorporationStarbaseDetail.php | 9 + app/models/EveCorporationStarbaseList.php | 9 + app/models/EveCorporationWalletJournal.php | 9 + .../EveCorporationWalletTransactions.php | 9 + app/models/EveEveAllianceList.php | 17 + .../EveEveAllianceListMemberCorporations.php | 15 + app/models/EveEveCharacterInfo.php | 15 + .../EveEveCharacterInfoEmploymentHistory.php | 15 + app/models/EveEveConquerableStationList.php | 10 + app/models/EveEveErrorList.php | 10 + app/models/EveEveNotificationTypes.php | 10 + app/models/EveEveRefTypes.php | 10 + app/models/EveMapDenormalize.php | 9 + app/models/EveMapJumps.php | 10 + app/models/EveMapKills.php | 10 + app/models/EveMapSovereignty.php | 10 + app/models/EveServerServerStatus.php | 10 + app/models/SeatKey.php | 17 + app/models/SeatQueueInformation.php | 10 + app/models/User.php | 60 + app/queues/full/EveCharacter.php | 124 + app/queues/full/EveCorporation.php | 124 + app/queues/full/EveEve.php | 65 + app/queues/full/EveMap.php | 60 + app/queues/full/EveServer.php | 53 + app/queues/partial/EveCorporation.php | 112 + app/queues/partial/EveCorporationAssets.php | 56 + app/queues/partial/EveCorporationWallet.php | 60 + app/routes.php | 38 + app/services/validators/APIKeyValidator.php | 10 + app/services/validators/Validator.php | 26 + app/start/artisan.php | 30 + app/start/global.php | 93 + app/start/local.php | 3 + app/storage/.gitignore | 1 + app/storage/cache/.gitignore | 3 + app/storage/cache/phealcache/.gitignore | 2 + app/storage/logs/.gitignore | 2 + app/storage/meta/.gitignore | 2 + app/storage/sessions/.gitignore | 2 + app/storage/views/.gitignore | 2 + app/tests/ExampleTest.php | 17 + app/tests/TestCase.php | 19 + app/views/character/all.blade.php | 59 + app/views/character/view.blade.php | 591 ++++ .../listmembertracking.blade.php | 23 + .../membertracking/membertracking.blade.php | 62 + .../starbase/liststarbase.blade.php | 23 + .../corporation/starbase/starbase.blade.php | 113 + .../walletjournal/listjournals.blade.php | 23 + .../walletjournal/walletjournal.blade.php | 61 + .../listtransactions.blade.php | 23 + .../wallettransactions.blade.php | 55 + app/views/debug/ajax/result.blade.php | 73 + app/views/debug/api.blade.php | 199 ++ app/views/emails/auth/reminder.blade.php | 13 + app/views/errors/notFound.blade.php | 18 + app/views/home.blade.php | 48 + app/views/keys/ajax/check.blade.php | 114 + app/views/keys/ajax/errors.blade.php | 2 + app/views/keys/all.blade.php | 71 + app/views/keys/detail.blade.php | 230 ++ app/views/keys/new.blade.php | 123 + app/views/layouts/components/flash.blade.php | 25 + app/views/layouts/components/footer.blade.php | 1 + app/views/layouts/components/header.blade.php | 66 + .../layouts/components/sidebar.blade.php | 72 + app/views/layouts/masterLayout.blade.php | 109 + app/views/layouts/minimalLayout.blade.php | 66 + app/views/mail/read.blade.php | 126 + app/views/mail/subjects.blade.php | 66 + app/views/mail/timeline.blade.php | 147 + app/views/password/remind.blade.php | 29 + app/views/password/reset.blade.php | 41 + app/views/queue/status.blade.php | 286 ++ app/views/register/register.blade.php | 18 + app/views/user/login.blade.php | 32 + artisan | 74 + bootstrap/autoload.php | 75 + bootstrap/paths.php | 57 + bootstrap/start.php | 72 + composer.json | 43 + docs/INSTALL_Centos.md | 129 + docs/INSTALL_short.md | 42 + docs/supervisord-sample.conf | 11 + evesde/.gitignore | 4 + evesde/required_sde | 20 + evesde/update_sde.sh | 44 + phpunit.xml | 18 + public/.htaccess | 15 + public/assets/css/app.css | 2716 +++++++++++++++++ public/assets/css/bootstrap.min.css | 7 + public/assets/css/font-awesome.min.css | 4 + public/assets/css/select2-bootstrap.css | 87 + public/assets/css/select2-spinner.gif | Bin 0 -> 1849 bytes public/assets/css/select2.css | 646 ++++ public/assets/css/select2.png | Bin 0 -> 613 bytes public/assets/fonts/FontAwesome.otf | Bin 0 -> 62856 bytes public/assets/fonts/fontawesome-webfont.eot | Bin 0 -> 38205 bytes public/assets/fonts/fontawesome-webfont.svg | 414 +++ public/assets/fonts/fontawesome-webfont.ttf | Bin 0 -> 80652 bytes public/assets/fonts/fontawesome-webfont.woff | Bin 0 -> 44432 bytes .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20290 bytes .../fonts/glyphicons-halflings-regular.svg | 229 ++ .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 41236 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23292 bytes public/assets/fonts/ionicons.eot | Bin 0 -> 86204 bytes public/assets/fonts/ionicons.svg | 1623 ++++++++++ public/assets/fonts/ionicons.ttf | Bin 0 -> 139652 bytes public/assets/fonts/ionicons.woff | Bin 0 -> 48384 bytes public/assets/js/app.js | 199 ++ public/assets/js/bootstrap.min.js | 7 + public/assets/js/jquery-2.1.0.min.js | 4 + public/assets/js/select2.min.js | 22 + public/favicon.ico | Bin 0 -> 318 bytes public/index.php | 49 + public/packages/.gitkeep | 0 public/robots.txt | 2 + server.php | 19 + 378 files changed, 25251 insertions(+), 3 deletions(-) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 app/commands/.gitkeep create mode 100644 app/commands/SeatAPIDeleteKey.php create mode 100644 app/commands/SeatAPIFindKeyByName.php create mode 100644 app/commands/SeatAPIFindNameByKey.php create mode 100644 app/commands/SeatAPIFindSickKeys.php create mode 100644 app/commands/SeatAPIUpdate.php create mode 100644 app/commands/SeatQueueStatus.php create mode 100644 app/commands/SeatReset.php create mode 100644 app/commands/scheduled/EveCharacterUpdater.php create mode 100644 app/commands/scheduled/EveCorporationAssetsUpdater.php create mode 100644 app/commands/scheduled/EveCorporationUpdater.php create mode 100644 app/commands/scheduled/EveCorporationWalletUpdater.php create mode 100644 app/commands/scheduled/EveEveUpdater.php create mode 100644 app/commands/scheduled/EveMapUpdater.php create mode 100644 app/commands/scheduled/EveServerUpdater.php create mode 100644 app/config/app.php create mode 100644 app/config/auth.php create mode 100644 app/config/cache.php create mode 100644 app/config/compile.php create mode 100644 app/config/database.php create mode 100644 app/config/mail.php create mode 100644 app/config/packages/.gitkeep create mode 100644 app/config/queue.php create mode 100644 app/config/remote.php create mode 100644 app/config/seat.php create mode 100644 app/config/session.php create mode 100644 app/config/testing/cache.php create mode 100644 app/config/testing/session.php create mode 100644 app/config/view.php create mode 100644 app/config/workbench.php create mode 100644 app/controllers/.gitkeep create mode 100644 app/controllers/ApiKeyController.php create mode 100644 app/controllers/BaseController.php create mode 100644 app/controllers/CharacterController.php create mode 100644 app/controllers/CorporationController.php create mode 100644 app/controllers/DashboardController.php create mode 100644 app/controllers/DebugController.php create mode 100644 app/controllers/HelperController.php create mode 100644 app/controllers/HomeController.php create mode 100644 app/controllers/MailController.php create mode 100644 app/controllers/QueueController.php create mode 100644 app/controllers/RegisterController.php create mode 100644 app/controllers/RemindersController.php create mode 100644 app/controllers/UserController.php create mode 100644 app/database/migrations/.gitkeep create mode 100644 app/database/migrations/2014_03_19_155606_CreateUsersTable.php create mode 100644 app/database/migrations/2014_03_20_082745_CreateKeysTable.php create mode 100644 app/database/migrations/2014_03_20_205253_create_failed_jobs_table.php create mode 100644 app/database/migrations/2014_03_22_065049_CreateEveApiCalllist.php create mode 100644 app/database/migrations/2014_03_22_075805_CreateEveServerServerStatus.php create mode 100644 app/database/migrations/2014_03_22_091556_CreateEveMapSovereignty.php create mode 100644 app/database/migrations/2014_03_22_101039_CreateEveCachedUntil.php create mode 100644 app/database/migrations/2014_03_22_144822_CreateEveMapKills.php create mode 100644 app/database/migrations/2014_03_22_162427_CreateEveMapJumps.php create mode 100644 app/database/migrations/2014_03_22_193618_CreateEveEveErrorList.php create mode 100644 app/database/migrations/2014_03_23_102357_CreateEveEveRefTypes.php create mode 100644 app/database/migrations/2014_03_23_114254_CreateEveEveConquerableStationList.php create mode 100644 app/database/migrations/2014_03_23_151953_CreateEveEveCharacterInfo.php create mode 100644 app/database/migrations/2014_03_23_153737_CreateEveEveCharacterInfoEmploymentHistory.php create mode 100644 app/database/migrations/2014_03_23_184711_CreateEveEveAllianceList.php create mode 100644 app/database/migrations/2014_03_23_190236_CreateEveEveAllianceListMemberCorporations.php create mode 100644 app/database/migrations/2014_03_24_104019_CreateEveAccountAPIKeyInfo.php create mode 100644 app/database/migrations/2014_03_24_104207_CreateEveAccountAPIKeyInfoCharacters.php create mode 100644 app/database/migrations/2014_03_24_122157_CreateEveAccountAccountStatus.php create mode 100644 app/database/migrations/2014_03_25_113533_CreateSeatBannedCall.php create mode 100644 app/database/migrations/2014_03_26_045031_CreateSeatQueueInformation.php create mode 100644 app/database/migrations/2014_03_26_161501_CreateEveCharacterAccountBalance.php create mode 100644 app/database/migrations/2014_03_27_085631_CreateEveCharacterAssetList.php create mode 100644 app/database/migrations/2014_03_27_085645_CreateEveCharacterAssetListContents.php create mode 100644 app/database/migrations/2014_03_27_121947_CreateEveCharacterSheet.php create mode 100644 app/database/migrations/2014_03_27_141418_CreateEveCharacterSheetSkills.php create mode 100644 app/database/migrations/2014_03_28_074924_CreateEveCharacterContactList.php create mode 100644 app/database/migrations/2014_03_28_074959_CreateEveCharacterCorporateContactList.php create mode 100644 app/database/migrations/2014_03_28_075041_CreateEveCharacterAllianceContactList.php create mode 100644 app/database/migrations/2014_03_28_101644_CreateEveCharacterContactNotifications.php create mode 100644 app/database/migrations/2014_03_28_114602_CreateEveCharacterContracts.php create mode 100644 app/database/migrations/2014_03_28_124422_CreateEveCharacterContractsItems.php create mode 100644 app/database/migrations/2014_03_28_145406_CreateEveCharacterIndustryJobs.php create mode 100644 app/database/migrations/2014_03_28_163740_CreateEveCharacterMailMessages.php create mode 100644 app/database/migrations/2014_03_28_173326_CreateEveCharacterMailBodies.php create mode 100644 app/database/migrations/2014_03_29_044308_CreateEveCharacterMailingLists.php create mode 100644 app/database/migrations/2014_03_29_075707_CreateEveCharacterMarketOrders.php create mode 100644 app/database/migrations/2014_03_29_093955_CreateEveEveNotificationTypes.php create mode 100644 app/database/migrations/2014_03_29_104513_CreateEveCharacterNotifications.php create mode 100644 app/database/migrations/2014_03_29_125122_CreateEveCharacterNotificationTexts.php create mode 100644 app/database/migrations/2014_03_29_145832_CreateEveCharacterResearch.php create mode 100644 app/database/migrations/2014_03_29_160937_CreateEveCharacterSkillInTraining.php create mode 100644 app/database/migrations/2014_03_29_192807_CreateEveCharacterSkillQueue.php create mode 100644 app/database/migrations/2014_03_29_200727_CreateEveCharacterStandingsAgents.php create mode 100644 app/database/migrations/2014_03_29_200745_CreateEveCharacterStandingsNPCCorporations.php create mode 100644 app/database/migrations/2014_03_29_200910_CreateEveCharacterStandingsFactions.php create mode 100644 app/database/migrations/2014_03_29_224238_CreateEveCharacterUpcomingCalendarEvents.php create mode 100644 app/database/migrations/2014_03_30_161440_CreateEveCharacterWalletJournal.php create mode 100644 app/database/migrations/2014_03_30_181437_CreateEveCharacterWalletTransactions.php create mode 100644 app/database/migrations/2014_04_01_114920_CreateEveCorporationAccountBalance.php create mode 100644 app/database/migrations/2014_04_01_151652_CreateEveCorporationAssetList.php create mode 100644 app/database/migrations/2014_04_01_151715_CreateEveCorporationAssetListContents.php create mode 100644 app/database/migrations/2014_04_01_155106_CreateEveCorporationAllianceContactList.php create mode 100644 app/database/migrations/2014_04_01_155200_CreateEveCorporationCorporateContactList.php create mode 100644 app/database/migrations/2014_04_01_170702_CreateEveCorporationContracts.php create mode 100644 app/database/migrations/2014_04_01_170730_CreateEveCorporationContractsItems.php create mode 100644 app/database/migrations/2014_04_02_110839_CreateEveCorporationSheet.php create mode 100644 app/database/migrations/2014_04_02_111815_CreateEveCorporationSheetDivisions.php create mode 100644 app/database/migrations/2014_04_02_111830_CreateEveCorporationSheetWalletDivisions.php create mode 100644 app/database/migrations/2014_04_02_114928_CreateEveCorporationIndustryJobs.php create mode 100644 app/database/migrations/2014_04_02_121216_CreateEveCorporationAssetListLocations.php create mode 100644 app/database/migrations/2014_04_02_162945_CreateEveCorporationMarketOrders.php create mode 100644 app/database/migrations/2014_04_02_165032_CreateEveCorporationMedals.php create mode 100644 app/database/migrations/2014_04_02_171402_CreateEveCorporationMemberMedals.php create mode 100644 app/database/migrations/2014_04_03_051704_CreateEveCorporationMemberSecurityRoles.php create mode 100644 app/database/migrations/2014_04_03_051747_CreateEveCorporationMemberSecurityGrantableRoles.php create mode 100644 app/database/migrations/2014_04_03_051814_CreateEveCorporationMemberSecurityRolesAtHQ.php create mode 100644 app/database/migrations/2014_04_03_051844_CreateEveCorporationMemberSecurityGrantableRolesAtHQ.php create mode 100644 app/database/migrations/2014_04_03_051919_CreateEveCorporationMemberSecurityRolesAtBase.php create mode 100644 app/database/migrations/2014_04_03_051947_CreateEveCorporationMemberSecurityGrantableRolesAtBase.php create mode 100644 app/database/migrations/2014_04_03_052029_CreateEveCorporationMemberSecurityRolesAtOther.php create mode 100644 app/database/migrations/2014_04_03_052049_CreateEveCorporationMemberSecurityGrantableRolesAtOther.php create mode 100644 app/database/migrations/2014_04_03_052111_CreateEveCorporationMemberSecurityTitles.php create mode 100644 app/database/migrations/2014_04_03_071610_CreateEveCorporationMemberSecurityLog.php create mode 100644 app/database/migrations/2014_04_03_071638_CreateEveCorporationMemberSecurityLogDetails.php create mode 100644 app/database/migrations/2014_04_03_083203_CreateEveCorporationMemberTracking.php create mode 100644 app/database/migrations/2014_04_03_084907_CreateEveCorporationShareholderCharacters.php create mode 100644 app/database/migrations/2014_04_03_085050_CreateEveCorporationShareholderCorporations.php create mode 100644 app/database/migrations/2014_04_03_095308_CreateEveCorporationStandingsAgents.php create mode 100644 app/database/migrations/2014_04_03_095335_CreateEveCorporationStandingsNPCCorporations.php create mode 100644 app/database/migrations/2014_04_03_095406_CreateEveCorporationStandingsFactions.php create mode 100644 app/database/migrations/2014_04_03_110700_CreateEveCorporationStarbaseList.php create mode 100644 app/database/migrations/2014_04_03_114920_CreateEveCorporationStarbaseDetail.php create mode 100644 app/database/migrations/2014_04_03_155021_CreateEveCorporationWalletJournal.php create mode 100644 app/database/migrations/2014_04_03_160954_CreateEveCorporationWalletTransactions.php create mode 100644 app/database/migrations/2014_04_04_080921_CreateEveCorporationAssetListLocationsAddMapData.php create mode 100644 app/database/migrations/2014_04_04_113830_create_password_reminders_table.php create mode 100644 app/database/seeds/.gitkeep create mode 100644 app/database/seeds/DatabaseSeeder.php create mode 100644 app/database/seeds/EveApiCalllistTableSeeder.php create mode 100644 app/database/seeds/EveNotificationTypesSeeder.php create mode 100644 app/database/seeds/UserTableSeeder.php create mode 100644 app/eveapi/Api.php create mode 100644 app/eveapi/BaseAPI.php create mode 100644 app/eveapi/account/AccountAPIKeyInfo.php create mode 100644 app/eveapi/account/AccountAccountStatus.php create mode 100644 app/eveapi/character/CharacterAccountBalance.php create mode 100644 app/eveapi/character/CharacterAssetList.php create mode 100644 app/eveapi/character/CharacterCharacterSheet.php create mode 100644 app/eveapi/character/CharacterContactList.php create mode 100644 app/eveapi/character/CharacterContactNotifications.php create mode 100644 app/eveapi/character/CharacterContracts.php create mode 100644 app/eveapi/character/CharacterIndustryJobs.php create mode 100644 app/eveapi/character/CharacterMailMessages.php create mode 100644 app/eveapi/character/CharacterMailingLists.php create mode 100644 app/eveapi/character/CharacterMarketOrders.php create mode 100644 app/eveapi/character/CharacterNotifications.php create mode 100644 app/eveapi/character/CharacterResearch.php create mode 100644 app/eveapi/character/CharacterSkillInTraining.php create mode 100644 app/eveapi/character/CharacterSkillQueue.php create mode 100644 app/eveapi/character/CharacterStandings.php create mode 100644 app/eveapi/character/CharacterUpcomingCalendarEvents.php create mode 100644 app/eveapi/character/CharacterWalletJournal.php create mode 100644 app/eveapi/character/CharacterWalletTransactions.php create mode 100644 app/eveapi/corporation/CorporationAccountBalance.php create mode 100644 app/eveapi/corporation/CorporationAssetList.php create mode 100644 app/eveapi/corporation/CorporationContactList.php create mode 100644 app/eveapi/corporation/CorporationContracts.php create mode 100644 app/eveapi/corporation/CorporationCorporationSheet.php create mode 100644 app/eveapi/corporation/CorporationIndustryJobs.php create mode 100644 app/eveapi/corporation/CorporationMarketOrders.php create mode 100644 app/eveapi/corporation/CorporationMedals.php create mode 100644 app/eveapi/corporation/CorporationMemberMedals.php create mode 100644 app/eveapi/corporation/CorporationMemberSecurity.php create mode 100644 app/eveapi/corporation/CorporationMemberSecurityLog.php create mode 100644 app/eveapi/corporation/CorporationMemberTracking.php create mode 100644 app/eveapi/corporation/CorporationShareholders.php create mode 100644 app/eveapi/corporation/CorporationStandings.php create mode 100644 app/eveapi/corporation/CorporationStarbaseDetail.php create mode 100644 app/eveapi/corporation/CorporationStarbaseList.php create mode 100644 app/eveapi/corporation/CorporationWalletJournal.php create mode 100644 app/eveapi/corporation/CorporationWalletTransactions.php create mode 100644 app/eveapi/eve/EveAllianceList.php create mode 100644 app/eveapi/eve/EveCharacterInfo.php create mode 100644 app/eveapi/eve/EveConquerableStationList.php create mode 100644 app/eveapi/eve/EveErrorList.php create mode 100644 app/eveapi/eve/EveRefTypes.php create mode 100644 app/eveapi/map/MapJumps.php create mode 100644 app/eveapi/map/MapKills.php create mode 100644 app/eveapi/map/MapSovereignty.php create mode 100644 app/eveapi/server/ServerServerStatus.php create mode 100644 app/filters.php create mode 100644 app/lang/en/pagination.php create mode 100644 app/lang/en/reminders.php create mode 100644 app/lang/en/validation.php create mode 100644 app/models/Elegant.php create mode 100644 app/models/EveAccountAPIKeyInfo.php create mode 100644 app/models/EveAccountAPIKeyInfoCharacters.php create mode 100644 app/models/EveAccountAccountStatus.php create mode 100644 app/models/EveApiCalllist.php create mode 100644 app/models/EveBannedCall.php create mode 100644 app/models/EveCachedUntil.php create mode 100644 app/models/EveCharacterAccountBalance.php create mode 100644 app/models/EveCharacterAssetList.php create mode 100644 app/models/EveCharacterAssetListContents.php create mode 100644 app/models/EveCharacterCharacterSheet.php create mode 100644 app/models/EveCharacterCharacterSheetSkills.php create mode 100644 app/models/EveCharacterContactList.php create mode 100644 app/models/EveCharacterContactListAlliance.php create mode 100644 app/models/EveCharacterContactListCorporate.php create mode 100644 app/models/EveCharacterContactNotifications.php create mode 100644 app/models/EveCharacterContracts.php create mode 100644 app/models/EveCharacterContractsItems.php create mode 100644 app/models/EveCharacterIndustryJobs.php create mode 100644 app/models/EveCharacterMailBodies.php create mode 100644 app/models/EveCharacterMailMessages.php create mode 100644 app/models/EveCharacterMailingLists.php create mode 100644 app/models/EveCharacterMarketOrders.php create mode 100644 app/models/EveCharacterNotificationTexts.php create mode 100644 app/models/EveCharacterNotifications.php create mode 100644 app/models/EveCharacterResearch.php create mode 100644 app/models/EveCharacterSkillInTraining.php create mode 100644 app/models/EveCharacterSkillQueue.php create mode 100644 app/models/EveCharacterStandingsAgents.php create mode 100644 app/models/EveCharacterStandingsFactions.php create mode 100644 app/models/EveCharacterStandingsNPCCorporations.php create mode 100644 app/models/EveCharacterUpcomingCalendarEvents.php create mode 100644 app/models/EveCharacterWalletJournal.php create mode 100644 app/models/EveCharacterWalletTransactions.php create mode 100644 app/models/EveCorporationAccountBalance.php create mode 100644 app/models/EveCorporationAssetList.php create mode 100644 app/models/EveCorporationAssetListContents.php create mode 100644 app/models/EveCorporationAssetListLocations.php create mode 100644 app/models/EveCorporationContactListAlliance.php create mode 100644 app/models/EveCorporationContactListCorporate.php create mode 100644 app/models/EveCorporationContracts.php create mode 100644 app/models/EveCorporationContractsItems.php create mode 100644 app/models/EveCorporationCorporationSheet.php create mode 100644 app/models/EveCorporationCorporationSheetDivisions.php create mode 100644 app/models/EveCorporationCorporationSheetWalletDivisions.php create mode 100644 app/models/EveCorporationIndustryJobs.php create mode 100644 app/models/EveCorporationMarketOrders.php create mode 100644 app/models/EveCorporationMedals.php create mode 100644 app/models/EveCorporationMemberMedals.php create mode 100644 app/models/EveCorporationMemberSecurityGrantableRoles.php create mode 100644 app/models/EveCorporationMemberSecurityGrantableRolesAtBase.php create mode 100644 app/models/EveCorporationMemberSecurityGrantableRolesAtHQ.php create mode 100644 app/models/EveCorporationMemberSecurityGrantableRolesAtOther.php create mode 100644 app/models/EveCorporationMemberSecurityLog.php create mode 100644 app/models/EveCorporationMemberSecurityLogDetails.php create mode 100644 app/models/EveCorporationMemberSecurityRoles.php create mode 100644 app/models/EveCorporationMemberSecurityRolesAtBase.php create mode 100644 app/models/EveCorporationMemberSecurityRolesAtHQ.php create mode 100644 app/models/EveCorporationMemberSecurityRolesAtOther.php create mode 100644 app/models/EveCorporationMemberSecurityTitles.php create mode 100644 app/models/EveCorporationMemberTracking.php create mode 100644 app/models/EveCorporationShareholderCharacters.php create mode 100644 app/models/EveCorporationShareholderCorporations.php create mode 100644 app/models/EveCorporationStandingsAgents.php create mode 100644 app/models/EveCorporationStandingsFactions.php create mode 100644 app/models/EveCorporationStandingsNPCCorporations.php create mode 100644 app/models/EveCorporationStarbaseDetail.php create mode 100644 app/models/EveCorporationStarbaseList.php create mode 100644 app/models/EveCorporationWalletJournal.php create mode 100644 app/models/EveCorporationWalletTransactions.php create mode 100644 app/models/EveEveAllianceList.php create mode 100644 app/models/EveEveAllianceListMemberCorporations.php create mode 100644 app/models/EveEveCharacterInfo.php create mode 100644 app/models/EveEveCharacterInfoEmploymentHistory.php create mode 100644 app/models/EveEveConquerableStationList.php create mode 100644 app/models/EveEveErrorList.php create mode 100644 app/models/EveEveNotificationTypes.php create mode 100644 app/models/EveEveRefTypes.php create mode 100644 app/models/EveMapDenormalize.php create mode 100644 app/models/EveMapJumps.php create mode 100644 app/models/EveMapKills.php create mode 100644 app/models/EveMapSovereignty.php create mode 100644 app/models/EveServerServerStatus.php create mode 100644 app/models/SeatKey.php create mode 100644 app/models/SeatQueueInformation.php create mode 100644 app/models/User.php create mode 100644 app/queues/full/EveCharacter.php create mode 100644 app/queues/full/EveCorporation.php create mode 100644 app/queues/full/EveEve.php create mode 100644 app/queues/full/EveMap.php create mode 100644 app/queues/full/EveServer.php create mode 100644 app/queues/partial/EveCorporation.php create mode 100644 app/queues/partial/EveCorporationAssets.php create mode 100644 app/queues/partial/EveCorporationWallet.php create mode 100644 app/routes.php create mode 100644 app/services/validators/APIKeyValidator.php create mode 100644 app/services/validators/Validator.php create mode 100644 app/start/artisan.php create mode 100644 app/start/global.php create mode 100644 app/start/local.php create mode 100644 app/storage/.gitignore create mode 100644 app/storage/cache/.gitignore create mode 100644 app/storage/cache/phealcache/.gitignore create mode 100644 app/storage/logs/.gitignore create mode 100644 app/storage/meta/.gitignore create mode 100644 app/storage/sessions/.gitignore create mode 100644 app/storage/views/.gitignore create mode 100644 app/tests/ExampleTest.php create mode 100644 app/tests/TestCase.php create mode 100644 app/views/character/all.blade.php create mode 100644 app/views/character/view.blade.php create mode 100644 app/views/corporation/membertracking/listmembertracking.blade.php create mode 100644 app/views/corporation/membertracking/membertracking.blade.php create mode 100644 app/views/corporation/starbase/liststarbase.blade.php create mode 100644 app/views/corporation/starbase/starbase.blade.php create mode 100644 app/views/corporation/walletjournal/listjournals.blade.php create mode 100644 app/views/corporation/walletjournal/walletjournal.blade.php create mode 100644 app/views/corporation/wallettransactions/listtransactions.blade.php create mode 100644 app/views/corporation/wallettransactions/wallettransactions.blade.php create mode 100644 app/views/debug/ajax/result.blade.php create mode 100644 app/views/debug/api.blade.php create mode 100644 app/views/emails/auth/reminder.blade.php create mode 100644 app/views/errors/notFound.blade.php create mode 100644 app/views/home.blade.php create mode 100644 app/views/keys/ajax/check.blade.php create mode 100644 app/views/keys/ajax/errors.blade.php create mode 100644 app/views/keys/all.blade.php create mode 100644 app/views/keys/detail.blade.php create mode 100644 app/views/keys/new.blade.php create mode 100644 app/views/layouts/components/flash.blade.php create mode 100644 app/views/layouts/components/footer.blade.php create mode 100644 app/views/layouts/components/header.blade.php create mode 100644 app/views/layouts/components/sidebar.blade.php create mode 100644 app/views/layouts/masterLayout.blade.php create mode 100644 app/views/layouts/minimalLayout.blade.php create mode 100644 app/views/mail/read.blade.php create mode 100644 app/views/mail/subjects.blade.php create mode 100644 app/views/mail/timeline.blade.php create mode 100644 app/views/password/remind.blade.php create mode 100644 app/views/password/reset.blade.php create mode 100644 app/views/queue/status.blade.php create mode 100644 app/views/register/register.blade.php create mode 100644 app/views/user/login.blade.php create mode 100755 artisan create mode 100644 bootstrap/autoload.php create mode 100644 bootstrap/paths.php create mode 100644 bootstrap/start.php create mode 100644 composer.json create mode 100644 docs/INSTALL_Centos.md create mode 100644 docs/INSTALL_short.md create mode 100644 docs/supervisord-sample.conf create mode 100644 evesde/.gitignore create mode 100644 evesde/required_sde create mode 100644 evesde/update_sde.sh create mode 100644 phpunit.xml create mode 100644 public/.htaccess create mode 100755 public/assets/css/app.css create mode 100755 public/assets/css/bootstrap.min.css create mode 100755 public/assets/css/font-awesome.min.css create mode 100644 public/assets/css/select2-bootstrap.css create mode 100644 public/assets/css/select2-spinner.gif create mode 100644 public/assets/css/select2.css create mode 100644 public/assets/css/select2.png create mode 100755 public/assets/fonts/FontAwesome.otf create mode 100755 public/assets/fonts/fontawesome-webfont.eot create mode 100755 public/assets/fonts/fontawesome-webfont.svg create mode 100755 public/assets/fonts/fontawesome-webfont.ttf create mode 100755 public/assets/fonts/fontawesome-webfont.woff create mode 100755 public/assets/fonts/glyphicons-halflings-regular.eot create mode 100755 public/assets/fonts/glyphicons-halflings-regular.svg create mode 100755 public/assets/fonts/glyphicons-halflings-regular.ttf create mode 100755 public/assets/fonts/glyphicons-halflings-regular.woff create mode 100755 public/assets/fonts/ionicons.eot create mode 100755 public/assets/fonts/ionicons.svg create mode 100755 public/assets/fonts/ionicons.ttf create mode 100755 public/assets/fonts/ionicons.woff create mode 100755 public/assets/js/app.js create mode 100755 public/assets/js/bootstrap.min.js create mode 100644 public/assets/js/jquery-2.1.0.min.js create mode 100644 public/assets/js/select2.min.js create mode 100644 public/favicon.ico create mode 100644 public/index.php create mode 100644 public/packages/.gitkeep create mode 100644 public/robots.txt create mode 100644 server.php diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..21256661 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..59c90b76 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +/bootstrap/compiled.php +/vendor +composer.phar +composer.lock +.env.local.php +.env.php +.DS_Store +Thumbs.db \ No newline at end of file diff --git a/README.md b/README.md index f52838a0..da09e3da 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,48 @@ -seat -==== +## SeAT - Simple (or Stupid) EVE Online API Tool ## -Simple (or Stupid) EVE Online API Tool +# *This is very much BETA software with a ton of things not yet implemented. USE AT YOUR OWN RISK* # + +### Introduction ### +SeAT attempts to be a EVE Onlineā„¢ Corporation Management Tool written in PHP using the [Laravel][1] Framework driven by a MySQL database. +The SeAT backend is *highly* influenced by YAPEAL. SeAT itself is the result of a rewrite of the original Corporation Management Tool that I wrote for our corp and figured there may be others out there that may need similar tools. + +### Features ### +SeAT allows corporation CEO's and directors to manage member API keys, store member wallet & mail history, monitor corporaton poses, wallets, transactions, account ledgers etc. + +### Technical Summary ### +API Keys are stored in the backend database and get updated as the schedule is configured. A cronjob gets kicked off every minute that checks which jobs need to be scheduled and actions as required. +A 'job' can be defined as a set of categorized API calls to update certains part of a Character, Corporation, Eve or Map related information in the backend. More than 55 API Endpoints have been implemented and form part of these jobs. + +### Screenshots ### + +Character View +![Character View](http://i.imgur.com/yhsfWrb.png) + +Starbase Details View +![Starbase Details View](http://i.imgur.com/2OOmKkI.png) + +### Installation ### +Refer to the `docs/` directory for installation instructions + +### Todo ### +There really is a TON of stuff that still needs to be done: + +- Corporation Wallet Ledger +- Asset Search +- Skill Search +- Clone Overview +- Character Interactions (ie Player Tradings, Mails etc.) +- Starbase Fuel Time Left calculations as well as Silo input/output end etas. +- Corporation Sheets with Member Security Roles view + +There is a metric ton of information pulled via the API that is not yet exposed on the web front end... so *lots* to do still :) + +A much longer term goal would be to get the system to such a state where corporation members are able to register and view thier own keys and administrators are able to deletegate roles such as recruiters etc. + +### Contact ### +You can get hold of me via Twitter [@qu1ckkkk](https://twitter.com/qu1ckkkk), ingame character [qu1ckkkk](http://evewho.com/pilot/qu1ckkkk) or on [IRC](https://kiwiirc.com/client/irc.coldfront.net/?nick=seat_user|?#wcs-pub) at #wcs-pub on irc.coldfront.net + + [1]: http://laravel.com/ + +### Legal ### +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 DOTLAN EveMaps to use EVE Online and all associated logos and designs for promotional and information purposes on its website but does not endorse, and is not in any way affiliated with, DOTLAN EveMaps. 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. diff --git a/app/commands/.gitkeep b/app/commands/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/app/commands/SeatAPIDeleteKey.php b/app/commands/SeatAPIDeleteKey.php new file mode 100644 index 00000000..f0da3e91 --- /dev/null +++ b/app/commands/SeatAPIDeleteKey.php @@ -0,0 +1,75 @@ +argument('keyID'); + $this->info('Searching for key: ' . $keyID); + + $key = \SeatKey::where('keyID', '=', $keyID)->first(); + + if (count($key) == 1) { + + if ($this->confirm('Are you sure you want to delete this key? [yes|no] ', true)) { + + $key = \SeatKey::where('keyID', '=', $keyID)->delete(); + $this->comment('Key deleted!'); + return; + } else { + + $this->info('Not doing antything'); + } + } else { + + $this->error('Key not found.'); + } + } + + /** + * Get the console command arguments. + * + * @return array + */ + protected function getArguments() + { + return array( + array('keyID', InputArgument::REQUIRED, 'The keyID to delete.'), + ); + } +} diff --git a/app/commands/SeatAPIFindKeyByName.php b/app/commands/SeatAPIFindKeyByName.php new file mode 100644 index 00000000..fa12ed1e --- /dev/null +++ b/app/commands/SeatAPIFindKeyByName.php @@ -0,0 +1,69 @@ +argument('name'); + $this->info('Searching for term: ' . $name); + + $characters = \EveAccountAPIKeyInfoCharacters::where('characterName', 'like', '%' . $name . '%')->get(); + + if (count($characters) > 0) { + + foreach ($characters as $character) { + $this->info('Found match: ' . $character->characterName . ' with keyID: ' . $character->keyID); + } + } else { + + $this->error('No matches found.'); + } + } + + /** + * Get the console command arguments. + * + * @return array + */ + protected function getArguments() + { + return array( + array('name', InputArgument::REQUIRED, 'The name of the character to search the key for.'), + ); + } +} diff --git a/app/commands/SeatAPIFindNameByKey.php b/app/commands/SeatAPIFindNameByKey.php new file mode 100644 index 00000000..10788379 --- /dev/null +++ b/app/commands/SeatAPIFindNameByKey.php @@ -0,0 +1,70 @@ +argument('keyID'); + $this->info('Searching for key: ' . $keyID); + + $characters = \EveAccountAPIKeyInfoCharacters::where('keyID', 'like', '%' . $keyID . '%')->get(); + + if (count($characters) > 0) { + + foreach ($characters as $character) { + $this->info('Found match: ' . $character->characterName . ' with keyID: ' . $character->keyID); + } + } else { + + $this->error('No matches found.'); + } + } + + /** + * Get the console command arguments. + * + * @return array + */ + protected function getArguments() + { + return array( + array('keyID', InputArgument::REQUIRED, 'The keyID to search for.'), + ); + } + +} diff --git a/app/commands/SeatAPIFindSickKeys.php b/app/commands/SeatAPIFindSickKeys.php new file mode 100644 index 00000000..85b80d6f --- /dev/null +++ b/app/commands/SeatAPIFindSickKeys.php @@ -0,0 +1,54 @@ +info('Finding keys that are not ok.'); + foreach (\SeatKey::where('isOk', '=', 0)->get() as $key) { + + $this->comment('Key ' . $key->keyID . ' is not ok.'); + $this->line('Characters on this key:'); + + foreach (\EveAccountAPIKeyInfoCharacters::where('keyID', '=', $key->keyID)->get() as $character) { + $this->line($characterName); + } + } + } +} diff --git a/app/commands/SeatAPIUpdate.php b/app/commands/SeatAPIUpdate.php new file mode 100644 index 00000000..84078028 --- /dev/null +++ b/app/commands/SeatAPIUpdate.php @@ -0,0 +1,86 @@ + $jobID, 'ownerID' => 0, 'api' => 'ServerStatus', 'scope' => 'Server', 'status' => 'Queued')); + + // Map APIs + $jobID = \Queue::push('Seat\EveQueues\Full\Map', array()); + \SeatQueueInformation::create(array('jobID' => $jobID, 'ownerID' => 0, 'api' => 'Map', 'scope' => 'Eve', 'status' => 'Queued')); + + // Eve APIs + $jobID = \Queue::push('Seat\EveQueues\Full\Eve', array()); + \SeatQueueInformation::create(array('jobID' => $jobID, 'ownerID' => 0, 'api' => 'Eve', 'scope' => 'Eve', 'status' => 'Queued')); + + // Get the keys, and process them + foreach (\SeatKey::where('isOk', '=', 1)->get() as $key) { + + $access = EveApi\BaseApi::determineAccess($key->keyID); + if (!isset($access['type'])) { + print 'Unable to determine type for key ' . $key->keyID . PHP_EOL; + continue; + } + + $type = $access['type']; + + switch ($access['type']) { + case 'Character': + $jobID = \Queue::push('Seat\EveQueues\Full\Character', array('keyID' => $key->keyID, 'vCode' => $key->vCode)); + \SeatQueueInformation::create(array('jobID' => $jobID, 'ownerID' => $key->keyID, 'api' => 'Character', 'scope' => 'Eve', 'status' => 'Queued')); + break; + + case 'Corporation': + $jobID = \Queue::push('Seat\EveQueues\Full\Corporation', array('keyID' => $key->keyID, 'vCode' => $key->vCode)); + \SeatQueueInformation::create(array('jobID' => $jobID, 'ownerID' => $key->keyID, 'api' => 'Corporation', 'scope' => 'Eve', 'status' => 'Queued')); + break; + + default: + # code... + break; + } + } + } +} diff --git a/app/commands/SeatQueueStatus.php b/app/commands/SeatQueueStatus.php new file mode 100644 index 00000000..c3dffe69 --- /dev/null +++ b/app/commands/SeatQueueStatus.php @@ -0,0 +1,96 @@ + \Config::get('database.redis.default.host'), 'port' => \Config::get('database.redis.default.port'))); + $redis_count = count($redis->lrange('queues:default', 0, -1)); + $this->line('Redis reports ' . $redis_count . ' jobs in the queue (queues:default)'); + + // Get the Queue information from the database + $db_info = \SeatQueueInformation::where('status', '=', 'Queued')->count(); + $this->line('The database reports ' . $db_info . ' queued jobs'); + if ($db_info <> $redis_count) + $this->info('[!] The redis & db queued counts are not the same. This is not always a bad thing'); + + $db_info = \SeatQueueInformation::where('status', '=', 'Done')->count(); + $this->line('The database reports ' . $db_info . ' done jobs'); + + $db_info = \SeatQueueInformation::where('status', '=', 'Error')->count(); + if ($db_info > 0) { + + $this->comment('Current error-state jobs (' . $db_info . '):'); + + foreach (\SeatQueueInformation::where('status', '=', 'Error')->get() as $row) { + + $this->line( + 'OwnerID: ' . $row->ownerID . ' | Scope: ' . $row->scope . + ' | API: ' . $row->api . ' | Status: "' . $row->output . + '" | Created: ' . Carbon::parse($row->created_at)->diffForHumans() . + ' | Last updated: ' . Carbon::parse($row->updated_at)->diffForHumans() + ); + } + } else { + $this->line('The database reports ' . $db_info . ' error jobs'); + } + + $db_info = \SeatQueueInformation::where('status', '=', 'Working')->count(); + if ($db_info > 0) { + + $this->comment('Current working-state jobs (' . $db_info . '):'); + + foreach (\SeatQueueInformation::where('status', '=', 'Working')->get() as $row) { + + $this->line( + 'OwnerID: ' . $row->ownerID . ' | Scope: ' . $row->scope . + ' | API: ' . $row->api . ' | Status: "' . $row->output . + '" | Created: ' . Carbon::parse($row->created_at)->diffForHumans() . + ' | Last updated: ' . Carbon::parse($row->updated_at)->diffForHumans() + ); + } + } else { + + $this->line('The database reports ' . $db_info . ' working jobs'); + } + } +} diff --git a/app/commands/SeatReset.php b/app/commands/SeatReset.php new file mode 100644 index 00000000..772251dd --- /dev/null +++ b/app/commands/SeatReset.php @@ -0,0 +1,69 @@ +error('WARNING!!! This will RESET the current Administrator password!'); + $this->line(''); + + $password = $this->secret('What is the new password to use for the admin user? : '); + $password2 = $this->secret('Retype that password please: '); + + if ($password <> $password2) { + + $this->error('The passwords do not match. Not resetting'); + return; + } + + $this->info('The passwords match. Resetting to the new ' . strlen($password) . ' char one.'); + + $admin = \User::where('username', '=', 'admin')->first(); + + if (!isset($admin)) { + + $this->error('The admin user could not be found... Have you run db:seed ?'); + return; + } + + $admin->password = \Hash::make($password); + $admin->save(); + + $this->info('Password has been changed successfully.'); + } +} diff --git a/app/commands/scheduled/EveCharacterUpdater.php b/app/commands/scheduled/EveCharacterUpdater.php new file mode 100644 index 00000000..6e879d9b --- /dev/null +++ b/app/commands/scheduled/EveCharacterUpdater.php @@ -0,0 +1,74 @@ +hourly(); + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function fire() + { + // Get the keys, and process them + foreach (\SeatKey::where('isOk', '=', 1)->get() as $key) { + + $access = EveApi\BaseApi::determineAccess($key->keyID); + if (!isset($access['type'])) { + //TODO: Log this key's problems and disable it + continue; + } + + // Only process Character keys here + if ($access['type'] == 'Character') { + $jobID = \Queue::push('Seat\EveQueues\Full\Character', array('keyID' => $key->keyID, 'vCode' => $key->vCode)); + \SeatQueueInformation::create(array('jobID' => $jobID, 'ownerID' => $key->keyID, 'api' => 'Character', 'scope' => 'Eve', 'status' => 'Queued')); + } + } + } +} diff --git a/app/commands/scheduled/EveCorporationAssetsUpdater.php b/app/commands/scheduled/EveCorporationAssetsUpdater.php new file mode 100644 index 00000000..a560df04 --- /dev/null +++ b/app/commands/scheduled/EveCorporationAssetsUpdater.php @@ -0,0 +1,74 @@ +setSchedule('*', '*/8', '*', '*', '*'); + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function fire() + { + // Get the keys, and process them + foreach (\SeatKey::where('isOk', '=', 1)->get() as $key) { + + $access = EveApi\BaseApi::determineAccess($key->keyID); + if (!isset($access['type'])) { + //TODO: Log this key's problems and disable it + continue; + } + + // Only process Corporation keys and only update the Assets from Partial\ + if ($access['type'] == 'Corporation') { + $jobID = \Queue::push('Seat\EveQueues\Partial\CorporationAssets', array('keyID' => $key->keyID, 'vCode' => $key->vCode)); + \SeatQueueInformation::create(array('jobID' => $jobID, 'ownerID' => $key->keyID, 'api' => 'CorporationAssets', 'scope' => 'Eve', 'status' => 'Queued')); + } + } + } +} diff --git a/app/commands/scheduled/EveCorporationUpdater.php b/app/commands/scheduled/EveCorporationUpdater.php new file mode 100644 index 00000000..a7d9d862 --- /dev/null +++ b/app/commands/scheduled/EveCorporationUpdater.php @@ -0,0 +1,74 @@ +hourly(); + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function fire() + { + // Get the keys, and process them + foreach (\SeatKey::where('isOk', '=', 1)->get() as $key) { + + $access = EveApi\BaseApi::determineAccess($key->keyID); + if (!isset($access['type'])) { + //TODO: Log this key's problems and disable it + continue; + } + + // Only process Corporation keys and only update the the endpoints that are not Wallet || Assets + if ($access['type'] == 'Corporation') { + $jobID = \Queue::push('Seat\EveQueues\Partial\Corporation', array('keyID' => $key->keyID, 'vCode' => $key->vCode)); + \SeatQueueInformation::create(array('jobID' => $jobID, 'ownerID' => $key->keyID, 'api' => 'Corporation', 'scope' => 'Eve', 'status' => 'Queued')); + } + } + } +} diff --git a/app/commands/scheduled/EveCorporationWalletUpdater.php b/app/commands/scheduled/EveCorporationWalletUpdater.php new file mode 100644 index 00000000..fc2b970b --- /dev/null +++ b/app/commands/scheduled/EveCorporationWalletUpdater.php @@ -0,0 +1,74 @@ +setSchedule('*/30', '*', '*', '*', '*'); + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function fire() + { + // Get the keys, and process them + foreach (\SeatKey::where('isOk', '=', 1)->get() as $key) { + + $access = EveApi\BaseApi::determineAccess($key->keyID); + if (!isset($access['type'])) { + //TODO: Log this key's problems and disable it + continue; + } + + // Only process Corporation keys and only update the Assets from Partial\ + if ($access['type'] == 'Corporation') { + $jobID = \Queue::push('Seat\EveQueues\Partial\CorporationWallet', array('keyID' => $key->keyID, 'vCode' => $key->vCode)); + \SeatQueueInformation::create(array('jobID' => $jobID, 'ownerID' => $key->keyID, 'api' => 'CorporationWallet', 'scope' => 'Eve', 'status' => 'Queued')); + } + } + } +} diff --git a/app/commands/scheduled/EveEveUpdater.php b/app/commands/scheduled/EveEveUpdater.php new file mode 100644 index 00000000..be35889b --- /dev/null +++ b/app/commands/scheduled/EveEveUpdater.php @@ -0,0 +1,62 @@ +daily(); + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function fire() + { + // Eve APIs + $jobID = \Queue::push('Seat\EveQueues\Full\Eve', array()); + \SeatQueueInformation::create(array('jobID' => $jobID, 'ownerID' => 0, 'api' => 'Eve', 'scope' => 'Eve', 'status' => 'Queued')); + } +} diff --git a/app/commands/scheduled/EveMapUpdater.php b/app/commands/scheduled/EveMapUpdater.php new file mode 100644 index 00000000..9c3b867d --- /dev/null +++ b/app/commands/scheduled/EveMapUpdater.php @@ -0,0 +1,61 @@ +daily(); + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function fire() + { + $jobID = \Queue::push('Seat\EveQueues\Full\Map', array()); + \SeatQueueInformation::create(array('jobID' => $jobID, 'ownerID' => 0, 'api' => 'Map', 'scope' => 'Eve', 'status' => 'Queued')); + } +} diff --git a/app/commands/scheduled/EveServerUpdater.php b/app/commands/scheduled/EveServerUpdater.php new file mode 100644 index 00000000..7e71a275 --- /dev/null +++ b/app/commands/scheduled/EveServerUpdater.php @@ -0,0 +1,63 @@ +setSchedule('*/5', '*', '*', '*', '*'); + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function fire() + { + + // Server APIs + $jobID = \Queue::push('Seat\EveQueues\Full\Server', array()); + \SeatQueueInformation::create(array('jobID' => $jobID, 'ownerID' => 0, 'api' => 'ServerStatus', 'scope' => 'Server', 'status' => 'Queued')); + } +} diff --git a/app/config/app.php b/app/config/app.php new file mode 100644 index 00000000..ff549f11 --- /dev/null +++ b/app/config/app.php @@ -0,0 +1,179 @@ + false, + + /* + |-------------------------------------------------------------------------- + | Application URL + |-------------------------------------------------------------------------- + | + | This URL is used by the console to properly generate URLs when using + | the Artisan command line tool. You should set this to the root of + | your application so that it is used when running Artisan tasks. + | + */ + + 'url' => 'http://localhost', + + /* + |-------------------------------------------------------------------------- + | Application Timezone + |-------------------------------------------------------------------------- + | + | Here you may specify the default timezone for your application, which + | will be used by the PHP date and date-time functions. We have gone + | ahead and set this to a sensible default for you out of the box. + | + */ + + 'timezone' => 'UTC', + + /* + |-------------------------------------------------------------------------- + | Application Locale Configuration + |-------------------------------------------------------------------------- + | + | The application locale determines the default locale that will be used + | by the translation service provider. You are free to set this value + | to any of the locales which will be supported by the application. + | + */ + + 'locale' => 'en', + + /* + |-------------------------------------------------------------------------- + | Encryption Key + |-------------------------------------------------------------------------- + | + | This key is used by the Illuminate encrypter service and should be set + | to a random, 32 character string, otherwise these encrypted strings + | will not be safe. Please do this before deploying an application! + | + */ + + 'key' => '69rtXrU4OFoWBR5oEIf2JpwopmfhQCRO', + + /* + |-------------------------------------------------------------------------- + | Autoloaded Service Providers + |-------------------------------------------------------------------------- + | + | The service providers listed here will be automatically loaded on the + | request to your application. Feel free to add your own services to + | this array to grant expanded functionality to your applications. + | + */ + + 'providers' => array( + + 'Illuminate\Foundation\Providers\ArtisanServiceProvider', + 'Illuminate\Auth\AuthServiceProvider', + 'Illuminate\Cache\CacheServiceProvider', + 'Illuminate\Session\CommandsServiceProvider', + 'Illuminate\Foundation\Providers\ConsoleSupportServiceProvider', + 'Illuminate\Routing\ControllerServiceProvider', + 'Illuminate\Cookie\CookieServiceProvider', + 'Illuminate\Database\DatabaseServiceProvider', + 'Illuminate\Encryption\EncryptionServiceProvider', + 'Illuminate\Filesystem\FilesystemServiceProvider', + 'Illuminate\Hashing\HashServiceProvider', + 'Illuminate\Html\HtmlServiceProvider', + 'Illuminate\Log\LogServiceProvider', + 'Illuminate\Mail\MailServiceProvider', + 'Illuminate\Database\MigrationServiceProvider', + 'Illuminate\Pagination\PaginationServiceProvider', + 'Illuminate\Queue\QueueServiceProvider', + 'Illuminate\Redis\RedisServiceProvider', + 'Illuminate\Remote\RemoteServiceProvider', + 'Illuminate\Auth\Reminders\ReminderServiceProvider', + 'Illuminate\Database\SeedServiceProvider', + 'Illuminate\Session\SessionServiceProvider', + 'Illuminate\Translation\TranslationServiceProvider', + 'Illuminate\Validation\ValidationServiceProvider', + 'Illuminate\View\ViewServiceProvider', + 'Illuminate\Workbench\WorkbenchServiceProvider', + 'Indatus\Dispatcher\ServiceProvider', // Schedules + + ), + + /* + |-------------------------------------------------------------------------- + | Service Provider Manifest + |-------------------------------------------------------------------------- + | + | The service provider manifest is used by Laravel to lazy load service + | providers which are not needed for each request, as well to keep a + | list of all of the services. Here, you may set its storage spot. + | + */ + + 'manifest' => storage_path().'/meta', + + /* + |-------------------------------------------------------------------------- + | Class Aliases + |-------------------------------------------------------------------------- + | + | This array of class aliases will be registered when this application + | is started. However, feel free to register as many as you wish as + | the aliases are "lazy" loaded so they don't hinder performance. + | + */ + + 'aliases' => array( + + 'App' => 'Illuminate\Support\Facades\App', + 'Artisan' => 'Illuminate\Support\Facades\Artisan', + 'Auth' => 'Illuminate\Support\Facades\Auth', + 'Blade' => 'Illuminate\Support\Facades\Blade', + 'Cache' => 'Illuminate\Support\Facades\Cache', + 'ClassLoader' => 'Illuminate\Support\ClassLoader', + 'Config' => 'Illuminate\Support\Facades\Config', + 'Controller' => 'Illuminate\Routing\Controller', + 'Cookie' => 'Illuminate\Support\Facades\Cookie', + 'Crypt' => 'Illuminate\Support\Facades\Crypt', + 'DB' => 'Illuminate\Support\Facades\DB', + 'Eloquent' => 'Illuminate\Database\Eloquent\Model', + 'Event' => 'Illuminate\Support\Facades\Event', + 'File' => 'Illuminate\Support\Facades\File', + 'Form' => 'Illuminate\Support\Facades\Form', + 'Hash' => 'Illuminate\Support\Facades\Hash', + 'HTML' => 'Illuminate\Support\Facades\HTML', + 'Input' => 'Illuminate\Support\Facades\Input', + 'Lang' => 'Illuminate\Support\Facades\Lang', + 'Log' => 'Illuminate\Support\Facades\Log', + 'Mail' => 'Illuminate\Support\Facades\Mail', + 'Paginator' => 'Illuminate\Support\Facades\Paginator', + 'Password' => 'Illuminate\Support\Facades\Password', + 'Queue' => 'Illuminate\Support\Facades\Queue', + 'Redirect' => 'Illuminate\Support\Facades\Redirect', + 'Redis' => 'Illuminate\Support\Facades\Redis', + 'Request' => 'Illuminate\Support\Facades\Request', + 'Response' => 'Illuminate\Support\Facades\Response', + 'Route' => 'Illuminate\Support\Facades\Route', + 'Schema' => 'Illuminate\Support\Facades\Schema', + 'Seeder' => 'Illuminate\Database\Seeder', + 'Session' => 'Illuminate\Support\Facades\Session', + 'SSH' => 'Illuminate\Support\Facades\SSH', + 'Str' => 'Illuminate\Support\Str', + 'URL' => 'Illuminate\Support\Facades\URL', + 'Validator' => 'Illuminate\Support\Facades\Validator', + 'View' => 'Illuminate\Support\Facades\View', + + ), + +); diff --git a/app/config/auth.php b/app/config/auth.php new file mode 100644 index 00000000..a3f1e19c --- /dev/null +++ b/app/config/auth.php @@ -0,0 +1,71 @@ + 'eloquent', + + /* + |-------------------------------------------------------------------------- + | Authentication Model + |-------------------------------------------------------------------------- + | + | When using the "Eloquent" authentication driver, we need to know which + | Eloquent model should be used to retrieve your users. Of course, it + | is often just the "User" model but you may use whatever you like. + | + */ + + 'model' => 'User', + + /* + |-------------------------------------------------------------------------- + | Authentication Table + |-------------------------------------------------------------------------- + | + | When using the "Database" authentication driver, we need to know which + | table should be used to retrieve your users. We have chosen a basic + | default value but you may easily change it to any table you like. + | + */ + + 'table' => 'seat_users', + + /* + |-------------------------------------------------------------------------- + | Password Reminder Settings + |-------------------------------------------------------------------------- + | + | Here you may set the settings for password reminders, including a view + | that should be used as your password reminder e-mail. You will also + | be able to set the name of the table that holds the reset tokens. + | + | The "expire" time is the number of minutes that the reminder should be + | considered valid. This security feature keeps tokens short-lived so + | they have less time to be guessed. You may change this as needed. + | + */ + + 'reminder' => array( + + 'email' => 'emails.auth.reminder', + + 'table' => 'password_reminders', + + 'expire' => 60, + + ), + +); diff --git a/app/config/cache.php b/app/config/cache.php new file mode 100644 index 00000000..76053ab3 --- /dev/null +++ b/app/config/cache.php @@ -0,0 +1,89 @@ + 'redis', + + /* + |-------------------------------------------------------------------------- + | File Cache Location + |-------------------------------------------------------------------------- + | + | When using the "file" cache driver, we need a location where the cache + | files may be stored. A sensible default has been specified, but you + | are free to change it to any other place on disk that you desire. + | + */ + + 'path' => storage_path().'/cache', + + /* + |-------------------------------------------------------------------------- + | Database Cache Connection + |-------------------------------------------------------------------------- + | + | When using the "database" cache driver you may specify the connection + | that should be used to store the cached items. When this option is + | null the default database connection will be utilized for cache. + | + */ + + 'connection' => null, + + /* + |-------------------------------------------------------------------------- + | Database Cache Table + |-------------------------------------------------------------------------- + | + | When using the "database" cache driver we need to know the table that + | should be used to store the cached items. A default table name has + | been provided but you're free to change it however you deem fit. + | + */ + + 'table' => 'cache', + + /* + |-------------------------------------------------------------------------- + | Memcached Servers + |-------------------------------------------------------------------------- + | + | Now you may specify an array of your Memcached servers that should be + | used when utilizing the Memcached cache driver. All of the servers + | should contain a value for "host", "port", and "weight" options. + | + */ + + 'memcached' => array( + + array('host' => '127.0.0.1', 'port' => 11211, 'weight' => 100), + + ), + + /* + |-------------------------------------------------------------------------- + | Cache Key Prefix + |-------------------------------------------------------------------------- + | + | When utilizing a RAM based store such as APC or Memcached, there might + | be other applications utilizing the same cache. So, we'll specify a + | value to get prefixed to all our keys so we can avoid collisions. + | + */ + + 'prefix' => 'laravel', + +); diff --git a/app/config/compile.php b/app/config/compile.php new file mode 100644 index 00000000..54d7185b --- /dev/null +++ b/app/config/compile.php @@ -0,0 +1,18 @@ + PDO::FETCH_CLASS, + + /* + |-------------------------------------------------------------------------- + | Default Database Connection Name + |-------------------------------------------------------------------------- + | + | Here you may specify which of the database connections below you wish + | to use as your default connection for all database work. Of course + | you may use many connections at once using the Database library. + | + */ + + 'default' => 'mysql', + + /* + |-------------------------------------------------------------------------- + | Database Connections + |-------------------------------------------------------------------------- + | + | Here are each of the database connections setup for your application. + | Of course, examples of configuring each database platform that is + | supported by Laravel is shown below to make development simple. + | + | + | All database work in Laravel is done through the PHP PDO facilities + | so make sure you have the driver for your particular database of + | choice installed on your machine before you begin development. + | + */ + + 'connections' => array( + + 'sqlite' => array( + 'driver' => 'sqlite', + 'database' => __DIR__.'/../database/production.sqlite', + 'prefix' => '', + ), + + 'mysql' => array( + 'driver' => 'mysql', + 'host' => '127.0.0.1', + 'database' => 'seat', + 'username' => 'root', + 'password' => '', + 'charset' => 'utf8', + 'collation' => 'utf8_unicode_ci', + 'prefix' => '', + ), + + 'pgsql' => array( + 'driver' => 'pgsql', + 'host' => 'localhost', + 'database' => 'database', + 'username' => 'root', + 'password' => '', + 'charset' => 'utf8', + 'prefix' => '', + 'schema' => 'public', + ), + + 'sqlsrv' => array( + 'driver' => 'sqlsrv', + 'host' => 'localhost', + 'database' => 'database', + 'username' => 'root', + 'password' => '', + 'prefix' => '', + ), + + ), + + /* + |-------------------------------------------------------------------------- + | Migration Repository Table + |-------------------------------------------------------------------------- + | + | This table keeps track of all the migrations that have already run for + | your application. Using this information, we can determine which of + | the migrations on disk haven't actually been run in the database. + | + */ + + 'migrations' => 'migrations', + + /* + |-------------------------------------------------------------------------- + | Redis Databases + |-------------------------------------------------------------------------- + | + | Redis is an open source, fast, and advanced key-value store that also + | provides a richer set of commands than a typical key-value systems + | such as APC or Memcached. Laravel makes it easy to dig right in. + | + */ + + 'redis' => array( + + 'cluster' => false, + + 'default' => array( + 'host' => '127.0.0.1', + 'port' => 6379, + 'database' => 0, + ), + + ), + +); diff --git a/app/config/mail.php b/app/config/mail.php new file mode 100644 index 00000000..64a350cf --- /dev/null +++ b/app/config/mail.php @@ -0,0 +1,124 @@ + 'sendmail', + + /* + |-------------------------------------------------------------------------- + | SMTP Host Address + |-------------------------------------------------------------------------- + | + | Here you may provide the host address of the SMTP server used by your + | applications. A default option is provided that is compatible with + | the Postmark mail service, which will provide reliable delivery. + | + */ + + 'host' => 'smtp.mailgun.org', + + /* + |-------------------------------------------------------------------------- + | SMTP Host Port + |-------------------------------------------------------------------------- + | + | This is the SMTP port used by your application to delivery e-mails to + | users of your application. Like the host we have set this value to + | stay compatible with the Postmark e-mail application by default. + | + */ + + 'port' => 587, + + /* + |-------------------------------------------------------------------------- + | Global "From" Address + |-------------------------------------------------------------------------- + | + | You may wish for all e-mails sent by your application to be sent from + | the same address. Here, you may specify a name and address that is + | used globally for all e-mails that are sent by your application. + | + */ + + 'from' => array('address' => 'seatadmin@localhost', 'name' => 'SeAT Admin'), + + /* + |-------------------------------------------------------------------------- + | E-Mail Encryption Protocol + |-------------------------------------------------------------------------- + | + | Here you may specify the encryption protocol that should be used when + | the application send e-mail messages. A sensible default using the + | transport layer security protocol should provide great security. + | + */ + + 'encryption' => 'tls', + + /* + |-------------------------------------------------------------------------- + | SMTP Server Username + |-------------------------------------------------------------------------- + | + | If your SMTP server requires a username for authentication, you should + | set it here. This will get used to authenticate with your server on + | connection. You may also set the "password" value below this one. + | + */ + + 'username' => null, + + /* + |-------------------------------------------------------------------------- + | SMTP Server Password + |-------------------------------------------------------------------------- + | + | Here you may set the password required by your SMTP server to send out + | messages from your application. This will be given to the server on + | connection so that the application will be able to send messages. + | + */ + + 'password' => null, + + /* + |-------------------------------------------------------------------------- + | Sendmail System Path + |-------------------------------------------------------------------------- + | + | When using the "sendmail" driver to send e-mails, we will need to know + | the path to where Sendmail lives on this server. A default path has + | been provided here, which will work well on most of your systems. + | + */ + + 'sendmail' => '/usr/sbin/sendmail -bs', + + /* + |-------------------------------------------------------------------------- + | Mail "Pretend" + |-------------------------------------------------------------------------- + | + | When this option is enabled, e-mail will not actually be sent over the + | web and will instead be written to your application's logs files so + | you may inspect the message. This is great for local development. + | + */ + + 'pretend' => false, + +); \ No newline at end of file diff --git a/app/config/packages/.gitkeep b/app/config/packages/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/app/config/queue.php b/app/config/queue.php new file mode 100644 index 00000000..6cfa0c89 --- /dev/null +++ b/app/config/queue.php @@ -0,0 +1,82 @@ + 'redis', + + /* + |-------------------------------------------------------------------------- + | Queue Connections + |-------------------------------------------------------------------------- + | + | Here you may configure the connection information for each server that + | is used by your application. A default configuration has been added + | for each back-end shipped with Laravel. You are free to add more. + | + */ + + 'connections' => array( + + 'sync' => array( + 'driver' => 'sync', + ), + + 'beanstalkd' => array( + 'driver' => 'beanstalkd', + 'host' => '127.0.0.1', + 'queue' => 'default', + ), + + 'sqs' => array( + 'driver' => 'sqs', + 'key' => 'your-public-key', + 'secret' => 'your-secret-key', + 'queue' => 'your-queue-url', + 'region' => 'us-east-1', + ), + + 'iron' => array( + 'driver' => 'iron', + 'project' => 'your-project-id', + 'token' => 'your-token', + 'queue' => 'your-queue-name', + ), + + 'redis' => array( + 'driver' => 'redis', + 'queue' => 'default', + ), + + ), + + /* + |-------------------------------------------------------------------------- + | Failed Queue Jobs + |-------------------------------------------------------------------------- + | + | These options configure the behavior of failed queue job logging so you + | can control which database and table are used to store the jobs that + | have failed. You may change them to any database / table you wish. + | + */ + + 'failed' => array( + + 'database' => 'mysql', 'table' => 'failed_jobs', + + ), + +); diff --git a/app/config/remote.php b/app/config/remote.php new file mode 100644 index 00000000..ea960e03 --- /dev/null +++ b/app/config/remote.php @@ -0,0 +1,59 @@ + 'production', + + /* + |-------------------------------------------------------------------------- + | Remote Server Connections + |-------------------------------------------------------------------------- + | + | These are the servers that will be accessible via the SSH task runner + | facilities of Laravel. This feature radically simplifies executing + | tasks on your servers, such as deploying out these applications. + | + */ + + 'connections' => array( + + 'production' => array( + 'host' => '', + 'username' => '', + 'password' => '', + 'key' => '', + 'keyphrase' => '', + 'root' => '/var/www', + ), + + ), + + /* + |-------------------------------------------------------------------------- + | Remote Server Groups + |-------------------------------------------------------------------------- + | + | Here you may list connections under a single group name, which allows + | you to easily access all of the servers at once using a short name + | that is extremely easy to remember, such as "web" or "database". + | + */ + + 'groups' => array( + + 'web' => array('production') + + ), + +); \ No newline at end of file diff --git a/app/config/seat.php b/app/config/seat.php new file mode 100644 index 00000000..01f7c8a0 --- /dev/null +++ b/app/config/seat.php @@ -0,0 +1,14 @@ + '0.1', + +); \ No newline at end of file diff --git a/app/config/session.php b/app/config/session.php new file mode 100644 index 00000000..45f1069f --- /dev/null +++ b/app/config/session.php @@ -0,0 +1,140 @@ + 'file', + + /* + |-------------------------------------------------------------------------- + | Session Lifetime + |-------------------------------------------------------------------------- + | + | Here you may specify the number of minutes that you wish the session + | to be allowed to remain idle before it expires. If you want them + | to immediately expire on the browser closing, set that option. + | + */ + + 'lifetime' => 120, + + 'expire_on_close' => false, + + /* + |-------------------------------------------------------------------------- + | Session File Location + |-------------------------------------------------------------------------- + | + | When using the native session driver, we need a location where session + | files may be stored. A default has been set for you but a different + | location may be specified. This is only needed for file sessions. + | + */ + + 'files' => storage_path().'/sessions', + + /* + |-------------------------------------------------------------------------- + | Session Database Connection + |-------------------------------------------------------------------------- + | + | When using the "database" or "redis" session drivers, you may specify a + | connection that should be used to manage these sessions. This should + | correspond to a connection in your database configuration options. + | + */ + + 'connection' => null, + + /* + |-------------------------------------------------------------------------- + | Session Database Table + |-------------------------------------------------------------------------- + | + | When using the "database" session driver, you may specify the table we + | should use to manage the sessions. Of course, a sensible default is + | provided for you; however, you are free to change this as needed. + | + */ + + 'table' => 'sessions', + + /* + |-------------------------------------------------------------------------- + | Session Sweeping Lottery + |-------------------------------------------------------------------------- + | + | Some session drivers must manually sweep their storage location to get + | rid of old sessions from storage. Here are the chances that it will + | happen on a given request. By default, the odds are 2 out of 100. + | + */ + + 'lottery' => array(2, 100), + + /* + |-------------------------------------------------------------------------- + | Session Cookie Name + |-------------------------------------------------------------------------- + | + | Here you may change the name of the cookie used to identify a session + | instance by ID. The name specified here will get used every time a + | new session cookie is created by the framework for every driver. + | + */ + + 'cookie' => 'seat_session', + + /* + |-------------------------------------------------------------------------- + | Session Cookie Path + |-------------------------------------------------------------------------- + | + | The session cookie path determines the path for which the cookie will + | be regarded as available. Typically, this will be the root path of + | your application but you are free to change this when necessary. + | + */ + + 'path' => '/', + + /* + |-------------------------------------------------------------------------- + | Session Cookie Domain + |-------------------------------------------------------------------------- + | + | Here you may change the domain of the cookie used to identify a session + | in your application. This will determine which domains the cookie is + | available to in your application. A sensible default has been set. + | + */ + + 'domain' => null, + + /* + |-------------------------------------------------------------------------- + | HTTPS Only Cookies + |-------------------------------------------------------------------------- + | + | By setting this option to true, session cookies will only be sent back + | to the server if the browser has a HTTPS connection. This will keep + | the cookie from being sent to you if it can not be done securely. + | + */ + + 'secure' => false, + +); diff --git a/app/config/testing/cache.php b/app/config/testing/cache.php new file mode 100644 index 00000000..16d3ae2f --- /dev/null +++ b/app/config/testing/cache.php @@ -0,0 +1,20 @@ + 'array', + +); \ No newline at end of file diff --git a/app/config/testing/session.php b/app/config/testing/session.php new file mode 100644 index 00000000..a18c1b9f --- /dev/null +++ b/app/config/testing/session.php @@ -0,0 +1,21 @@ + 'array', + +); \ No newline at end of file diff --git a/app/config/view.php b/app/config/view.php new file mode 100644 index 00000000..34b8f387 --- /dev/null +++ b/app/config/view.php @@ -0,0 +1,31 @@ + array(__DIR__.'/../views'), + + /* + |-------------------------------------------------------------------------- + | Pagination View + |-------------------------------------------------------------------------- + | + | This view will be used to render the pagination link output, and can + | be easily customized here to show any view you like. A clean view + | compatible with Twitter's Bootstrap is given to you by default. + | + */ + + 'pagination' => 'pagination::slider-3', + +); diff --git a/app/config/workbench.php b/app/config/workbench.php new file mode 100644 index 00000000..56bee526 --- /dev/null +++ b/app/config/workbench.php @@ -0,0 +1,31 @@ + '', + + /* + |-------------------------------------------------------------------------- + | Workbench Author E-Mail Address + |-------------------------------------------------------------------------- + | + | Like the option above, your e-mail address is used when generating new + | workbench packages. The e-mail is placed in your composer.json file + | automatically after the package is created by the workbench tool. + | + */ + + 'email' => '', + +); \ No newline at end of file diff --git a/app/controllers/.gitkeep b/app/controllers/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/app/controllers/ApiKeyController.php b/app/controllers/ApiKeyController.php new file mode 100644 index 00000000..f198ae8c --- /dev/null +++ b/app/controllers/ApiKeyController.php @@ -0,0 +1,302 @@ +beforeFilter('csrf', array('on' => 'post')); + } + + /* + |-------------------------------------------------------------------------- + | getAll() + |-------------------------------------------------------------------------- + | + | Get all of the API keys in the database together with the characters that + | are currently associated with it + | + */ + + public function getAll() + { + + $keys = DB::table('seat_keys') + ->select('seat_keys.keyID', 'seat_keys.isOk', 'account_apikeyinfo.accessMask', 'account_apikeyinfo.type', 'account_apikeyinfo.expires') + ->leftJoin('account_apikeyinfo', 'seat_keys.keyID', '=', 'account_apikeyinfo.keyID') + ->get(); + + // Prepare the key information and characters for the view + $key_information = array(); + foreach ($keys as $key) { + + $key_information[$key->keyID] = array( + + 'keyID' => $key->keyID, + 'isOk' => $key->isOk, + 'accessMask' => $key->accessMask, + 'type' => $key->type, + 'expires' => $key->expires, + 'expires_human' => (is_null($key->expires) ? 'Never' : \Carbon\Carbon::parse($key->expires)->diffForHumans()), + ); + + // Add the key characters + foreach (EveAccountAPIKeyInfoCharacters::where('keyID', $key->keyID)->get() as $character) { + + $key_information[$key->keyID]['characters'][] = array( + 'characterID' => $character->characterID, + 'characterName' => $character->characterName + ); + } + } + + return View::make('keys.all') + ->with(array('key_info' => $key_information)); + } + + /* + |-------------------------------------------------------------------------- + | getNewKey() + |-------------------------------------------------------------------------- + | + | Return a view to add new keys + | + */ + + public function getNewKey() + { + return View::make('keys.new'); + } + + /* + |-------------------------------------------------------------------------- + | postNewKey() + |-------------------------------------------------------------------------- + | + | Check a keyID and vCode for validity and return information about its + | existance in the database & information retreived from the EVE API + | + */ + + public function postNewKey() + { + if (Request::ajax()) { + + // We will validate the key pais as we dont want to cause unneeded errors + $validation = new APIKeyValidator; + + if ($validation->passes()) { + + // Setup a pheal instance and get some API data :D + BaseApi::bootstrap(); + $pheal = new Pheal(Input::get('keyID'), Input::get('vCode')); + + // Get API Key Information + try { + $key_info = $pheal->accountScope->APIKeyInfo(); + + } catch (\Pheal\Exceptions\PhealException $e) { + $key_info = array('error' => $e->getCode() . ': ' . $e->getMessage()); + } + + // Get API Account Status Information + try { + $status_info = $pheal->accountScope->AccountStatus(); + + } catch (\Pheal\Exceptions\PhealException $e) { + $status_info = array('error' => $e->getCode() . ': ' . $e->getMessage()); + } + + // TODO: Think about adding a entry to the cache to mark a particular key as + // valid + + // Return the view + return View::make('keys.ajax.check') + ->with('keyID', Input::get('keyID')) + ->with('vCode', Input::get('vCode')) + ->with('key_info', $key_info) + ->with('status_info', $status_info) + ->with('existance', SeatKey::where('keyID', Input::get('keyID'))->count()); + + } else { + + return View::make('keys.ajax.errors') + ->withErrors($validation->errors); + } + } + } + + /* + |-------------------------------------------------------------------------- + | getAdd() + |-------------------------------------------------------------------------- + | + | Check a keyID & vCode for validity and add it to the database. If the + | keyID already exists, it will be set to enabled and updated to the + | received vCode. + | + */ + + public function getAdd($keyID, $vCode) + { + + $validation = new APIKeyValidator(array('keyID' => $keyID, 'vCode' => $vCode)); + + if ($validation->passes()) { + + // Check if we have this key in the db, even those that are soft deleted + $key_data = SeatKey::withTrashed()->where('keyID', $keyID)->first(); + + if (!$key_data) + $key_data = new SeatKey; + + $key_data->keyID = $keyID; + $key_data->vCode = $vCode; + $key_data->isOk = 1; + $key_data->lastError = null; + $key_data->deleted_at = null; + $key_data->user_id = 1; // TODO: Fix this when the proper user management occurs + $key_data->save(); + + // Queue a job to update this API **now** + $access = EveApi\BaseApi::determineAccess($keyID); + if (!isset($access['type'])) { + + return Redirect::action('ApiKeyController@getAll') + ->with('warning', 'Key was successfully added, but a update job was not submitted.'); + } + + // Based in the key type, push a update job + switch ($access['type']) { + case 'Character': + $jobID = \Queue::push('Seat\EveQueues\Full\Character', array('keyID' => $keyID, 'vCode' => $vCode)); + \SeatQueueInformation::create(array('jobID' => $jobID, 'ownerID' => $keyID, 'api' => 'Character', 'scope' => 'Eve', 'status' => 'Queued')); + break; + + case 'Corporation': + $jobID = \Queue::push('Seat\EveQueues\Full\Corporation', array('keyID' => $keyID, 'vCode' => $vCode)); + \SeatQueueInformation::create(array('jobID' => $jobID, 'ownerID' => $keyID, 'api' => 'Corporation', 'scope' => 'Eve', 'status' => 'Queued')); + break; + + default: + $jobID = 'Unknown'; + break; + } + + return Redirect::action('ApiKeyController@getAll') + ->with('success', 'Key was successfully added and job ' . $jobID . ' was queued to update it.'); + + } else { + + return Redirect::action('ApiKeyController@getNewKey') + ->withErrors($validation->errors); + } + } + + /* + |-------------------------------------------------------------------------- + | getDetail() + |-------------------------------------------------------------------------- + | + | Find all of the keyID related details stored in the database, along with + | queue information for it. + | + */ + + public function getDetail($keyID) + { + + $key_information = DB::table('seat_keys') + ->select('seat_keys.keyID', 'seat_keys.isOk', 'account_apikeyinfo.accessMask', 'account_apikeyinfo.type', 'account_apikeyinfo.expires') + ->leftJoin('account_apikeyinfo', 'seat_keys.keyID', '=', 'account_apikeyinfo.keyID') + ->where('seat_keys.keyID', $keyID) + ->first(); + + $key_characters = DB::table('account_apikeyinfo_characters') + ->where('keyID', $keyID) + ->get(); + + $key_bans = DB::table('banned_calls') + ->where('ownerID', $keyID) + ->get(); + + $recent_jobs = DB::table('queue_information') + ->where('ownerID', $keyID) + ->orderBy('created_at', 'desc') + ->take(25) + ->get(); + + //TODO: Cached untill for the characerID's + + return View::make('keys.detail') + ->with('key_information', $key_information) + ->with('key_characters', $key_characters) + ->with('key_bans', $key_bans) + ->with('recent_jobs', $recent_jobs); + } + + /* + |-------------------------------------------------------------------------- + | getUpdateJob() + |-------------------------------------------------------------------------- + | + | Checks for the existance of a key and submits a job to update it. Only + | character keys will be processed, and a new job will only be submitted + | if an existing one is not already waiting + | + */ + + public function getUpdateJob($keyID) + { + + // Get the full key and vCode + $key = SeatKey::where('keyID', $keyID)->first(); + + if (!$key) + App::abord(404); + + // Check that there is not already an outstanding job for this keyID + $queue_check = DB::table('queue_information') + ->where('status', 'Queued') + ->where('ownerID', $key->keyID) + ->first(); + + if ($queue_check) + return Response::json(array('state' => 'existing', 'jobID' => $queue_check->jobID)); + + // Else, queue a job for this + $access = EveApi\BaseApi::determineAccess($key->keyID); + + if (!isset($access['type'])) + return Response::json(array('state' => 'error', 'jobID' => null)); + + // Only process Character keys here + if ($access['type'] == 'Character') { + $jobID = \Queue::push('Seat\EveQueues\Full\Character', array('keyID' => $key->keyID, 'vCode' => $key->vCode)); + \SeatQueueInformation::create(array('jobID' => $jobID, 'ownerID' => $key->keyID, 'api' => 'Character', 'scope' => 'Eve', 'status' => 'Queued')); + + return Response::json(array('state' => 'new', 'jobID' => $jobID)); + } else { + + return Response::json(array('state' => 'error', 'jobID' => null)); + } + + } +} \ No newline at end of file diff --git a/app/controllers/BaseController.php b/app/controllers/BaseController.php new file mode 100644 index 00000000..097e161a --- /dev/null +++ b/app/controllers/BaseController.php @@ -0,0 +1,18 @@ +layout)) + { + $this->layout = View::make($this->layout); + } + } + +} \ No newline at end of file diff --git a/app/controllers/CharacterController.php b/app/controllers/CharacterController.php new file mode 100644 index 00000000..6dda2637 --- /dev/null +++ b/app/controllers/CharacterController.php @@ -0,0 +1,200 @@ +leftJoin('seat_keys', 'account_apikeyinfo_characters.keyID', '=', 'seat_keys.keyID') + ->join('character_charactersheet', 'account_apikeyinfo_characters.characterID', '=', 'character_charactersheet.characterID') + ->join('character_skillintraining', 'account_apikeyinfo_characters.characterID', '=', 'character_skillintraining.characterID') + ->get(); + + return View::make('character.all') + ->with('characters', $characters); + } + + /* + |-------------------------------------------------------------------------- + | getView() + |-------------------------------------------------------------------------- + | + | Get all of the information that we possibly have for a specific + | characterID. This includes a character sheet, skill sheet, skill queue, + | wallet journal, mail, notifications & assets + | + | Outstanding information for this function is still: + | Wallet Transactions, Attribute Enhancers, Contact Lists, Industry Jobs + | Standings + | + */ + + public function getView($characterID) + { + + $character = DB::table('account_apikeyinfo_characters') + ->leftJoin('account_apikeyinfo', 'account_apikeyinfo_characters.keyID', '=', 'account_apikeyinfo.keyID') + ->leftJoin('seat_keys', 'account_apikeyinfo_characters.keyID', '=', 'seat_keys.keyID') + ->join('account_accountstatus', 'account_apikeyinfo_characters.keyID', '=', 'account_accountstatus.keyID') + ->join('character_charactersheet', 'account_apikeyinfo_characters.characterID', '=', 'character_charactersheet.characterID') + ->join('character_skillintraining', 'account_apikeyinfo_characters.characterID', '=', 'character_skillintraining.characterID') + ->leftJoin('invTypes', 'character_skillintraining.trainingTypeID', '=', 'invTypes.typeID') + ->where('character_charactersheet.characterID', $characterID) + ->first(); + + if(count($character) <= 0) + return Redirect::action('CharacterController@getAll') + ->withErrors('Invalid Character ID'); + + $other_characters = DB::table('account_apikeyinfo_characters') + ->join('character_charactersheet', 'account_apikeyinfo_characters.characterID', '=', 'character_charactersheet.characterID') + ->join('character_skillintraining', 'account_apikeyinfo_characters.characterID', '=', 'character_skillintraining.characterID') + ->where('account_apikeyinfo_characters.keyID', $character->keyID) + ->where('account_apikeyinfo_characters.characterID', '<>', $character->characterID) + ->get(); + + $skillpoints = DB::table('character_charactersheet_skills') + ->where('characterID', $characterID) + ->sum('skillpoints'); + + $skill_queue = DB::table('character_skillqueue') + ->join('invTypes', 'character_skillqueue.typeID', '=', 'invTypes.typeID') + ->where('characterID', $characterID) + ->get(); + + // Thanks to the db being pretty WTF, we will just do some thingsā„¢ and get an + // array ready for all the skills. Essentially, we will use this as the main + // loop for our skill presentation in the view + $skill_groups = DB::table('invGroups') + ->where('categoryID', 16) + ->where('groupID', '<>', 505) + ->orderBy('groupName') + ->get(); + + // Now that we have all the groups, get the characters skills and info + $character_skills_information = DB::table('character_charactersheet_skills') + ->join('invTypes', 'character_charactersheet_skills.typeID', '=', 'invTypes.typeID') + ->join('invGroups', 'invTypes.groupID', '=', 'invGroups.groupID') + ->where('character_charactersheet_skills.characterID', $characterID) + ->orderBy('invTypes.typeName') + ->get(); + + // Lastly, create an array that is easy to loop over in the template to display + // the data + // TODO: Look at the possibility of lists() and specifying the groupID as key + $character_skills = array(); + foreach ($character_skills_information as $key => $value) { + + $character_skills[$value->groupID][] = array( + 'typeID' => $value->typeID, + 'groupName' => $value->groupName, + 'typeName' => $value->typeName, + 'description' => $value->description, + 'skillpoints' => $value->skillpoints, + 'level' => $value->level + ); + } + + $wallet_journal = DB::table('character_walletjournal') + ->join('eve_reftypes', 'character_walletjournal.refTypeID', '=', 'eve_reftypes.refTypeID') + ->where('characterID', $characterID) + ->orderBy('date', 'desc') + ->take(25) + ->get(); + + $wallet_transactions = DB::table('character_wallettransactions') + ->where('characterID', $characterID) + ->orderBy('transactionDateTime', 'desc') + ->take(25) + ->get(); + + $mail = DB::table('character_mailmessages') + ->where('characterID', $characterID) + ->orderBy('sentDate', 'desc') + ->take(25) + ->get(); + + $notifications = DB::table('character_notifications') + ->join('eve_notification_types', 'character_notifications.typeID', '=', 'eve_notification_types.typeID') + ->join('character_notification_texts', 'character_notifications.notificationID', '=', 'character_notification_texts.notificationID') + ->where('character_notifications.characterID', $characterID) + ->orderBy('sentDate', 'desc') + ->take(25) + ->get(); + + // Now, this query for the assets relative to their locations.. dunno if I want to + // try and move this shit to a query builder / eloquent version... :< + $assets = DB::select( + 'SELECT *, CASE + when a.locationID BETWEEN 66000000 AND 66014933 then + (SELECT s.stationName FROM staStations AS s + WHERE s.stationID=a.locationID-6000001) + when a.locationID BETWEEN 66014934 AND 67999999 then + (SELECT c.stationName FROM `eve_conquerablestationlist` AS c + WHERE c.stationID=a.locationID-6000000) + when a.locationID BETWEEN 60014861 AND 60014928 then + (SELECT c.stationName FROM `eve_conquerablestationlist` AS c + WHERE c.stationID=a.locationID) + when a.locationID BETWEEN 60000000 AND 61000000 then + (SELECT s.stationName FROM staStations AS s + WHERE s.stationID=a.locationID) + when a.locationID>=61000000 then + (SELECT c.stationName FROM `eve_conquerablestationlist` AS c + WHERE c.stationID=a.locationID) + else (SELECT m.itemName FROM mapDenormalize AS m + WHERE m.itemID=a.locationID) end + AS location,a.locationId AS locID FROM `character_assetlist` AS a + LEFT JOIN `invTypes` ON a.`typeID` = `invTypes`.`typeID` + WHERE a.`characterID` = ? ORDER BY location', + array($characterID) + ); + + + // Finally, give all this to the view to handle + return View::make('character.view') + ->with('character', $character) + ->with('other_characters', $other_characters) + ->with('skillpoints', $skillpoints) + ->with('skill_queue', $skill_queue) + ->with('skill_groups', $skill_groups) + ->with('character_skills', $character_skills) + ->with('wallet_transactions', $wallet_transactions) + ->with('wallet_journal', $wallet_journal) + ->with('mail', $mail) + ->with('notifications', $notifications) + ->with('assets', $assets); + } + + /* + |-------------------------------------------------------------------------- + | getWalletDelta() + |-------------------------------------------------------------------------- + | + | Calculate the daily wallet balance delta for the last 30 days and return + | the results as a json response + | + */ + + public function getWalletDelta($characterID) + { + + $wallet_daily_delta = DB::table('character_walletjournal') + ->select(DB::raw('DATE(`date`) as day, IFNULL( SUM( amount ), 0 ) AS daily_delta')) + ->whereRaw('date BETWEEN DATE_SUB(NOW(), INTERVAL 30 DAY) and NOW()') + ->where('characterID', $characterID) + ->groupBy('day') + ->get(); + + return Response::json($wallet_daily_delta); + } +} diff --git a/app/controllers/CorporationController.php b/app/controllers/CorporationController.php new file mode 100644 index 00000000..3298dd06 --- /dev/null +++ b/app/controllers/CorporationController.php @@ -0,0 +1,280 @@ +join('account_apikeyinfo_characters', 'account_apikeyinfo.keyID', '=', 'account_apikeyinfo_characters.keyID') + ->where('account_apikeyinfo.type', 'Corporation') + ->get(); + + return View::make('corporation.walletjournal.listjournals') + ->with('corporations', $corporations); + } + + /* + |-------------------------------------------------------------------------- + | getJournal() + |-------------------------------------------------------------------------- + | + | Display a worporation Wallet Journal + | + */ + + public function getJournal($corporationID) + { + + $corporation_name = DB::table('account_apikeyinfo_characters') + ->where('corporationID', $corporationID) + ->first(); + + $wallet_journal = DB::table('corporation_walletjournal') + ->join('eve_reftypes', 'corporation_walletjournal.refTypeID', '=', 'eve_reftypes.refTypeID') + ->join('corporation_corporationsheet_walletdivisions', 'corporation_walletjournal.accountKey', '=', 'corporation_corporationsheet_walletdivisions.accountKey') + ->where('corporation_walletjournal.corporationID', $corporationID) + ->where('corporation_corporationsheet_walletdivisions.corporationID', $corporationID) + ->orderBy('date', 'desc') + ->paginate(50); + + return View::make('corporation.walletjournal.walletjournal') + ->with('wallet_journal', $wallet_journal) + ->with('corporation_name', $corporation_name); + } + + /* + |-------------------------------------------------------------------------- + | getListTransactions() + |-------------------------------------------------------------------------- + | + | Get a list of the corporations that we can display wallet Journals for + | + */ + + public function getListTransactions() + { + + $corporations = DB::table('account_apikeyinfo') + ->join('account_apikeyinfo_characters', 'account_apikeyinfo.keyID', '=', 'account_apikeyinfo_characters.keyID') + ->where('account_apikeyinfo.type', 'Corporation') + ->get(); + + return View::make('corporation.wallettransactions.listtransactions') + ->with('corporations', $corporations); + } + + /* + |-------------------------------------------------------------------------- + | getTransactions() + |-------------------------------------------------------------------------- + | + | Display a worporation Wallet Journal + | + */ + + public function getTransactions($corporationID) + { + + $corporation_name = DB::table('account_apikeyinfo_characters') + ->where('corporationID', $corporationID) + ->first(); + + $wallet_transactions = DB::table('corporation_wallettransactions') + ->join('corporation_corporationsheet_walletdivisions', 'corporation_wallettransactions.accountKey', '=', 'corporation_corporationsheet_walletdivisions.accountKey') + ->where('corporation_wallettransactions.corporationID', $corporationID) + ->where('corporation_corporationsheet_walletdivisions.corporationID', $corporationID) + ->orderBy('transactionDateTime', 'desc') + ->paginate(50); + + return View::make('corporation.wallettransactions.wallettransactions') + ->with('wallet_transactions', $wallet_transactions) + ->with('corporation_name', $corporation_name); + } + + /* + |-------------------------------------------------------------------------- + | getListMemberTracking() + |-------------------------------------------------------------------------- + | + | Get a list of the corporations that we can display Member Tracking for + | + */ + + public function getListMemberTracking() + { + + $corporations = DB::table('account_apikeyinfo') + ->join('account_apikeyinfo_characters', 'account_apikeyinfo.keyID', '=', 'account_apikeyinfo_characters.keyID') + ->where('account_apikeyinfo.type', 'Corporation') + ->get(); + + return View::make('corporation.membertracking.listmembertracking') + ->with('corporations', $corporations); + } + + /* + |-------------------------------------------------------------------------- + | getMemberTracking() + |-------------------------------------------------------------------------- + | + | Display a corporations Members and related API Key Information + | + */ + + public function getMemberTracking($corporationID) + { + + $members = DB::table(DB::raw('corporation_member_tracking as cmt')) + ->select(DB::raw('cmt.characterID, cmt.name, cmt.startDateTime, cmt.title, cmt.logonDateTime, cmt.logoffDateTime, cmt.location, cmt.shipType, k.keyID, k.isOk')) + ->leftJoin(DB::raw('account_apikeyinfo_characters'), 'cmt.characterID', '=', 'account_apikeyinfo_characters.characterID') + ->leftJoin(DB::raw('seat_keys as k'), 'account_apikeyinfo_characters.keyID', '=', 'k.keyID') + ->leftJoin(DB::raw('account_apikeyinfo as ap'), 'k.keyID', '=', 'ap.keyID') + ->where('cmt.corporationID', $corporationID) + ->orderBy('cmt.name', 'asc') + ->get(); + + return View::make('corporation.membertracking.membertracking') + ->with('members', $members); + } + + /* + |-------------------------------------------------------------------------- + | getListStarBase() + |-------------------------------------------------------------------------- + | + | Get a list of the corporations that we can display Member Tracking for + | + */ + + public function getListStarBase() + { + + $corporations = DB::table('account_apikeyinfo') + ->join('account_apikeyinfo_characters', 'account_apikeyinfo.keyID', '=', 'account_apikeyinfo_characters.keyID') + ->where('account_apikeyinfo.type', 'Corporation') + ->get(); + + return View::make('corporation.starbase.liststarbase') + ->with('corporations', $corporations); + } + + /* + |-------------------------------------------------------------------------- + | getStarBase() + |-------------------------------------------------------------------------- + | + | List Corporation Starbase details. + | + | TODO: Lots of calculations and information is still needed to be moved + | so that we can determine the amount of time left to in silos etc. + | + */ + + public function getStarBase($corporationID) + { + + // The very first thing we should be doing is getting all of the starbases for the corporationID + $starbases = DB::table('corporation_starbaselist') + ->select( + 'corporation_starbaselist.itemID', + 'corporation_starbaselist.moonID', + 'corporation_starbaselist.state', + 'corporation_starbaselist.stateTimeStamp', + 'corporation_starbaselist.onlineTimeStamp', + 'corporation_starbaselist.onlineTimeStamp', + 'corporation_starbasedetail.allowCorporationMembers', + 'corporation_starbasedetail.allowAllianceMembers', + 'corporation_starbasedetail.fuelBlocks', + 'corporation_starbasedetail.strontium', + 'invTypes.typeID', + 'invTypes.typeName', + 'mapDenormalize.itemName', + 'invNames.itemName', + 'map_sovereignty.solarSystemName' + ) + ->join('corporation_starbasedetail', 'corporation_starbaselist.itemID', '=', 'corporation_starbasedetail.itemID') + ->join('mapDenormalize', 'corporation_starbaselist.locationID', '=', 'mapDenormalize.itemID') + ->join('invNames', 'corporation_starbaselist.moonID', '=', 'invNames.itemID') + ->join('invTypes', 'corporation_starbaselist.typeID', '=', 'invTypes.typeID') + ->leftJoin('map_sovereignty', 'corporation_starbaselist.locationID', '=', 'map_sovereignty.solarSystemID') + ->where('corporation_starbaselist.corporationID', $corporationID) + ->orderBy('invNames.itemName', 'asc') + ->get(); + + // With the list of starbases with us, lets get some meta information about the bay sizes for towers + // for some calculations later in the view + $bay_sizes = DB::table('invTypes') + ->select('invTypes.typeID', 'invTypes.typeName', 'invTypes.capacity', 'dgmTypeAttributes.valueFloat') + ->join('dgmTypeAttributes', 'invTypes.typeID', '=', 'dgmTypeAttributes.typeID') + ->where('dgmTypeAttributes.attributeID', 1233) + ->where('invTypes.groupID', 365) + ->get(); + + // We need an array with the typeID as the key to easily determine the bay size. Shuffle it + $shuffled_bays = array(); + foreach ($bay_sizes as $bay) + $shuffled_bays[$bay->typeID] = array('fuelBay' => $bay->capacity, 'strontBay' => $bay->valueFloat); + + // Next, lets see which of this corporations' towers appear to be anchored in sov holding systems. + // TODO: Check that the sov holder is actually the alliance the corporation is in + $sov_towers = array_flip(DB::table('corporation_starbaselist') + ->select('itemID') + ->whereIn('locationID', function($location) { + $location->select('solarSystemID') + ->from('map_sovereignty') + ->where('factionID', 0); + })->where('corporationID', $corporationID) + ->lists('itemID')); + + // Lets get all of the item locations for this corporation and sort it out into a workable + // array that can just be referenced and looped in the view. We will use the mapID as the + // key in the resulting array to be able to associate the item to a tower + $item_locations = DB::table('corporation_assetlist_locations') + ->where('corporationID', $corporationID) + ->get(); + + // Shuffle the results + $shuffled_locations = array(); + foreach ($item_locations as $location) + $shuffled_locations[$location->mapID][] = array('itemID' => $location->itemID, 'itemName' => $location->itemName, 'mapName' => $location->mapName); + + // We will do a similar shuffle for the assetlist contents. First get them, and shuffle. + // The key for this array will be the itemID as there may be multiple 'things' in a 'thing' + $item_contents = DB::table('corporation_assetlist_contents') + ->join('invTypes', 'corporation_assetlist_contents.typeID', '=', 'invTypes.typeID') + ->where('corporationID', $corporationID) + ->get(); + + // Shuffle the results + $shuffled_contents = array(); + foreach ($item_contents as $contents) + $shuffled_contents[$contents->itemID][] = array('quantity' => $contents->quantity, 'name' => $contents->typeName); + + // Define the tower states. See http://3rdpartyeve.net/eveapi/APIv2_Corp_StarbaseList_XML + $tower_states = array( + '0' => 'Unanchored', + '1' => 'Anchored / Offline', + '2' => 'Onlining', + '3' => 'Reinforced', + '4' => 'Online' + ); + + return View::make('corporation.starbase.starbase') + ->with('starbases', $starbases) + ->with('bay_sizes', $shuffled_bays) + ->with('sov_towers', $sov_towers) + ->with('item_locations', $shuffled_locations) + ->with('item_contents', $shuffled_contents) + ->with('tower_states', $tower_states); + } +} diff --git a/app/controllers/DashboardController.php b/app/controllers/DashboardController.php new file mode 100644 index 00000000..ed549381 --- /dev/null +++ b/app/controllers/DashboardController.php @@ -0,0 +1,14 @@ +beforeFilter('csrf', array('on' => 'post')); + } + + public function getDashboard() + { + return View::make('home'); + } +} \ No newline at end of file diff --git a/app/controllers/DebugController.php b/app/controllers/DebugController.php new file mode 100644 index 00000000..2df1ed89 --- /dev/null +++ b/app/controllers/DebugController.php @@ -0,0 +1,87 @@ +groupBy('name'); + return View::make('debug.api') + ->with('call_list', $call_list); + } + + /* + |-------------------------------------------------------------------------- + | postQuery() + |-------------------------------------------------------------------------- + | + | Work with the received information to prepare a API call to the server + | and display its end result + | + */ + + public function postQuery() + { + + // We will validate the key pairs as we dont want to cause unneeded errors + $validation = new APIKeyValidator; + + if ($validation->passes()) { + + // Bootstrap the Pheal Instance + BaseApi::bootstrap(); + $pheal = new Pheal(Input::get('keyID'), Input::get('vCode')); + $pheal->scope = strtolower(Input::get('api')); + + // Prepare an array with the arguements that we have received. + // first the character + $arguements = array(); + if (strlen(Input::get('characterid')) > 0) + $arguements = array('characterid' => Input::get('characterid')); + // Next, process the option arrays + if (strlen(Input::get('optional1')) > 0) + $arguements[Input::get('optional1')] = Input::get('optional1value'); + if (strlen(Input::get('optional2')) > 0) + $arguements[Input::get('optional2')] = Input::get('optional2value'); + + // Compute the array for the view to sample the pheal call that will be made + $call_sample = array('keyID' => Input::get('keyID'), 'vCode' => Input::get('vCode'), 'scope' => Input::get('api'), 'call' => Input::get('call'), 'args' => $arguements); + + try { + + $method = Input::get('call'); + $response = $pheal->$method($arguements); + + } catch (Exception $e) { + + return View::make('debug.ajax.result') + ->with('call_sample', $call_sample) + ->with('exception', $e); + } + + return View::make('debug.ajax.result') + ->with('call_sample', $call_sample) + ->with('response', $response->toArray()); + + } else { + + return View::make('debug.ajax.result') + ->withErrors($validation->errors); + } + + } +} \ No newline at end of file diff --git a/app/controllers/HelperController.php b/app/controllers/HelperController.php new file mode 100644 index 00000000..b30cba5a --- /dev/null +++ b/app/controllers/HelperController.php @@ -0,0 +1,78 @@ + 0) { + + // Get pheal ready + BaseApi::bootstrap(); + $pheal = new Pheal(); + + // Loop over the ids for a max of 30 ids, and resolve the names + foreach (array_chunk($ids, 30) as $resolvable) { + + // Attempt actual API lookups + try { + + $names = $pheal->eveScope->CharacterName(array('ids' => implode(',', $resolvable))); + + } catch (Exception $e) { + + throw $e; + } + + // Add the results to the cache and the $return array + foreach ($names->characters as $lookup_result) { + + Cache::forever('nameid_' . $lookup_result->characterID, $lookup_result->name); + $return[$lookup_result->characterID] = $lookup_result->name; + } + } + } + + // With all the work out of the way, return the $return array as Json + return Response::json($return); + } +} \ No newline at end of file diff --git a/app/controllers/HomeController.php b/app/controllers/HomeController.php new file mode 100644 index 00000000..20dcdbd4 --- /dev/null +++ b/app/controllers/HomeController.php @@ -0,0 +1,24 @@ +with('server', EveServerServerStatus::find(1)); + } +} \ No newline at end of file diff --git a/app/controllers/MailController.php b/app/controllers/MailController.php new file mode 100644 index 00000000..01d56bda --- /dev/null +++ b/app/controllers/MailController.php @@ -0,0 +1,72 @@ +join('character_mailbodies', 'character_mailmessages.messageID', '=', 'character_mailbodies.messageID') + ->orderBy('character_mailmessages.sentDate', 'desc') + ->paginate(100); + + return View::make('mail.subjects') + ->with('mail', $mail); + } + + /* + |-------------------------------------------------------------------------- + | getTimeline() + |-------------------------------------------------------------------------- + | + | Display all of the mails in the system with the full body, sorted by + | sent date. + | + */ + + public function getTimeline() + { + + $mail = DB::table('character_mailmessages') + ->join('character_mailbodies', 'character_mailmessages.messageID', '=', 'character_mailbodies.messageID') + ->groupby('character_mailmessages.messageID') + ->orderBy('character_mailmessages.sentDate', 'desc') + ->paginate(30); + + return View::make('mail.timeline') + ->with('mail', $mail); + } + + /* + |-------------------------------------------------------------------------- + | getRead() + |-------------------------------------------------------------------------- + | + | Display a single mail message + | + */ + + public function getRead($messageID = 0) + { + $message = DB::table('character_mailmessages') + ->join('character_mailbodies', 'character_mailmessages.messageID', '=', 'character_mailbodies.messageID') + ->where('character_mailmessages.messageID', $messageID) + ->first(); + + if(count($message) <= 0) + return Redirect::action('MailController@getSubjects') + ->withErrors('Invalid Message ID'); + + return View::make('mail.read') + ->with('message', $message); + } +} \ No newline at end of file diff --git a/app/controllers/QueueController.php b/app/controllers/QueueController.php new file mode 100644 index 00000000..7ae9615a --- /dev/null +++ b/app/controllers/QueueController.php @@ -0,0 +1,101 @@ + Config::get('database.redis.default.host'), 'port' => Config::get('database.redis.default.port'))); + $redis_count = count($redis->lrange('queues:default', 0, -1)); // Run LRANGE queues:default 0 -1. Laravel deletes done jobs from the queue + + $redis_status = 'OK'; + + } catch (Exception $e) { + + $redis_count = 0; + $redis_status = $e->getmessage(); + } + + // Get the Queue information from the database + $db_done_count = \SeatQueueInformation::where('status', '=', 'Done')->count(); + + $db_queue_count = \SeatQueueInformation::where('status', '=', 'Queued')->count(); + $db_queue = \SeatQueueInformation::where('status', '=', 'Queued')->get(); + + $db_error_count = \SeatQueueInformation::where('status', '=', 'Error')->count(); + $db_errors = \SeatQueueInformation::where('status', '=', 'Error')->get(); + + $db_working_count = \SeatQueueInformation::where('status', '=', 'Working')->count(); + $db_working = \SeatQueueInformation::where('status', '=', 'Working')->get(); + + + + return View::make('queue.status') + ->with('redis_count', $redis_count) + ->with('redis_status', $redis_status) + ->with('db_queue_count', $db_queue_count) + ->with('db_queue', $db_queue) + ->with('db_done_count', $db_done_count) + ->with('db_error_count', $db_error_count) + ->with('db_errors', $db_errors) + ->with('db_working_count', $db_working_count) + ->with('db_working', $db_working); + } + + /* + |-------------------------------------------------------------------------- + | getShortStatus() + |-------------------------------------------------------------------------- + | + | Return the current error, working and queued job counts as json + | + */ + + public function getShortStatus() + { + + // Get the Queue information from the database + $db_queue_count = \SeatQueueInformation::where('status', '=', 'Queued')->count(); + $db_working_count = \SeatQueueInformation::where('status', '=', 'Working')->count(); + $db_error_count = \SeatQueueInformation::where('status', '=', 'Error')->count(); + + $response = array( + 'queue_count' => $db_queue_count, + 'working_count' => $db_working_count, + 'error_count' => $db_error_count + ); + + return Response::json($response); + } + + /* + |-------------------------------------------------------------------------- + | getDeleteError() + |-------------------------------------------------------------------------- + | + | Removes a Job record that is in a error state + | + */ + + public function getDeleteError($id) + { + + \SeatQueueInformation::where('status','Error') + ->where('id', $id) + ->delete(); + + return Response::json(); + } +} diff --git a/app/controllers/RegisterController.php b/app/controllers/RegisterController.php new file mode 100644 index 00000000..24af880f --- /dev/null +++ b/app/controllers/RegisterController.php @@ -0,0 +1,23 @@ +beforeFilter('csrf', array('on' => 'post')); + } + + /* + |-------------------------------------------------------------------------- + | getNew() + |-------------------------------------------------------------------------- + | + | Return a view for a new registration + | + */ + + public function getNew() + { + return View::make('register.register'); + } +} \ No newline at end of file diff --git a/app/controllers/RemindersController.php b/app/controllers/RemindersController.php new file mode 100644 index 00000000..51907df5 --- /dev/null +++ b/app/controllers/RemindersController.php @@ -0,0 +1,81 @@ +subject('SeAT Password Reset'); })) + { + case Password::INVALID_USER: + return Redirect::back() + ->withErrors(Lang::get($response)); + + case Password::REMINDER_SENT: + return Redirect::action('UserController@getSignIn') + ->with('success', Lang::get($response)); + } + } + + /** + * Display the password reset view for the given token. + * + * @param string $token + * @return Response + */ + public function getReset($token = null) + { + if (is_null($token)) App::abort(404); + + return View::make('password.reset')->with('token', $token); + } + + /** + * Handle a POST request to reset a user's password. + * + * @return Response + */ + public function postReset() + { + $credentials = Input::only( + 'email', 'password', 'password_confirmation', 'token' + ); + + $response = Password::reset($credentials, function($user, $password) + { + $user->password = Hash::make($password); + + $user->save(); + }); + + switch ($response) + { + case Password::INVALID_PASSWORD: + case Password::INVALID_TOKEN: + case Password::INVALID_USER: + return Redirect::back() + ->withErrors(Lang::get($response)); + + case Password::PASSWORD_RESET: + return Redirect::action('UserController@getSignIn') + ->with('success', 'Your password has been successfully reset'); + } + } + +} \ No newline at end of file diff --git a/app/controllers/UserController.php b/app/controllers/UserController.php new file mode 100644 index 00000000..44883c42 --- /dev/null +++ b/app/controllers/UserController.php @@ -0,0 +1,70 @@ +beforeFilter('csrf', array('on' => 'post')); + } + + /* + |-------------------------------------------------------------------------- + | getSignIn() + |-------------------------------------------------------------------------- + | + | Check if a user can be signed_in with a remember me, else, show a view + | to allow for a new sign in. + | + */ + + public function getSignIn() + { + if (Auth::viaRemember()) { + return Redirect::intended('/') + ->with('success', 'Welcome back' . Auth::user()->username); + } + + return View::make('user.login'); + } + + /* + |-------------------------------------------------------------------------- + | postSignIn() + |-------------------------------------------------------------------------- + | + | Process a signin attempt + | + */ + + public function postSignIn() + { + $username = Input::get('username'); + $password = Input::get('password'); + $remember = Input::get('remember_me'); + + if (Auth::attempt(array('username' => $username, 'password' => $password), $remember == 'yes'? true : false)) { + + return Redirect::intended('/'); + } + + return Redirect::back() + ->withInput() + ->withErrors('Authentication Failure'); + } + + /* + |-------------------------------------------------------------------------- + | getSignOut() + |-------------------------------------------------------------------------- + | + | Sign out a user session + | + */ + + public function getSignOut() + { + Auth::logout(); + return Redirect::action('UserController@getSignIn') + ->with('success', 'Successfully signed out'); + } +} \ No newline at end of file diff --git a/app/database/migrations/.gitkeep b/app/database/migrations/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/app/database/migrations/2014_03_19_155606_CreateUsersTable.php b/app/database/migrations/2014_03_19_155606_CreateUsersTable.php new file mode 100644 index 00000000..d2c2ff03 --- /dev/null +++ b/app/database/migrations/2014_03_19_155606_CreateUsersTable.php @@ -0,0 +1,38 @@ +increments('id'); + + $table->string('username', 16); + $table->string('password', 64); + $table->string('email', 96)->unique(); + + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('seat_users'); + } + +} diff --git a/app/database/migrations/2014_03_20_082745_CreateKeysTable.php b/app/database/migrations/2014_03_20_082745_CreateKeysTable.php new file mode 100644 index 00000000..9b01ee18 --- /dev/null +++ b/app/database/migrations/2014_03_20_082745_CreateKeysTable.php @@ -0,0 +1,40 @@ +increments('id'); + + $table->integer('user_id'); + $table->integer('keyID')->unsigned(); + $table->string('vCode', 64); + $table->tinyInteger('isOk')->default(1); + $table->string('lastError')->nullable(); + + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('seat_keys'); + } + +} \ No newline at end of file diff --git a/app/database/migrations/2014_03_20_205253_create_failed_jobs_table.php b/app/database/migrations/2014_03_20_205253_create_failed_jobs_table.php new file mode 100644 index 00000000..61efc17d --- /dev/null +++ b/app/database/migrations/2014_03_20_205253_create_failed_jobs_table.php @@ -0,0 +1,35 @@ +increments('id'); + $table->text('connection'); + $table->text('queue'); + $table->text('payload'); + $table->timestamp('failed_at'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('failed_jobs'); + } + +} diff --git a/app/database/migrations/2014_03_22_065049_CreateEveApiCalllist.php b/app/database/migrations/2014_03_22_065049_CreateEveApiCalllist.php new file mode 100644 index 00000000..6446dde8 --- /dev/null +++ b/app/database/migrations/2014_03_22_065049_CreateEveApiCalllist.php @@ -0,0 +1,38 @@ +increments('id'); + + $table->string('type'); + $table->string('name'); + $table->integer('accessMask'); + $table->string('description'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('api_calllist'); + } + +} diff --git a/app/database/migrations/2014_03_22_075805_CreateEveServerServerStatus.php b/app/database/migrations/2014_03_22_075805_CreateEveServerServerStatus.php new file mode 100644 index 00000000..e75d789e --- /dev/null +++ b/app/database/migrations/2014_03_22_075805_CreateEveServerServerStatus.php @@ -0,0 +1,37 @@ +increments('id'); + + $table->dateTime('currentTime'); + $table->string('serverOpen'); + $table->integer('onlinePlayers'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('server_serverstatus'); + } + +} diff --git a/app/database/migrations/2014_03_22_091556_CreateEveMapSovereignty.php b/app/database/migrations/2014_03_22_091556_CreateEveMapSovereignty.php new file mode 100644 index 00000000..7e5b8ec5 --- /dev/null +++ b/app/database/migrations/2014_03_22_091556_CreateEveMapSovereignty.php @@ -0,0 +1,43 @@ +increments('id'); + + $table->integer('solarSystemID')->unique(); + $table->integer('allianceID'); + $table->integer('factionID'); + $table->string('solarSystemName'); + $table->integer('corporationID'); + + // Indexes + $table->index('allianceID'); + $table->index('solarSystemName'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('map_sovereignty'); + } + +} diff --git a/app/database/migrations/2014_03_22_101039_CreateEveCachedUntil.php b/app/database/migrations/2014_03_22_101039_CreateEveCachedUntil.php new file mode 100644 index 00000000..e2283929 --- /dev/null +++ b/app/database/migrations/2014_03_22_101039_CreateEveCachedUntil.php @@ -0,0 +1,44 @@ +increments('id'); + + $table->integer('ownerID'); + $table->string('api'); + $table->string('scope'); + $table->string('hash', 32); + $table->dateTime('cached_until'); + + // Indexes + $table->index('ownerID'); + $table->index('api'); + $table->index('hash'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('cached_until'); + } + +} diff --git a/app/database/migrations/2014_03_22_144822_CreateEveMapKills.php b/app/database/migrations/2014_03_22_144822_CreateEveMapKills.php new file mode 100644 index 00000000..1755c612 --- /dev/null +++ b/app/database/migrations/2014_03_22_144822_CreateEveMapKills.php @@ -0,0 +1,38 @@ +increments('id'); + + $table->integer('solarSystemID')->unique(); + $table->integer('shipKills'); + $table->integer('factionKills'); + $table->integer('podKills'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('map_kills'); + } + +} diff --git a/app/database/migrations/2014_03_22_162427_CreateEveMapJumps.php b/app/database/migrations/2014_03_22_162427_CreateEveMapJumps.php new file mode 100644 index 00000000..0deea4b0 --- /dev/null +++ b/app/database/migrations/2014_03_22_162427_CreateEveMapJumps.php @@ -0,0 +1,36 @@ +increments('id'); + + $table->integer('solarSystemID')->unique(); + $table->integer('shipJumps'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('map_jumps'); + } + +} diff --git a/app/database/migrations/2014_03_22_193618_CreateEveEveErrorList.php b/app/database/migrations/2014_03_22_193618_CreateEveEveErrorList.php new file mode 100644 index 00000000..f07ac865 --- /dev/null +++ b/app/database/migrations/2014_03_22_193618_CreateEveEveErrorList.php @@ -0,0 +1,39 @@ +increments('id'); + + $table->integer('errorCode')->unique(); + $table->text('errorText'); + + // Index + $table->index('errorCode'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('eve_errorlist'); + } + +} diff --git a/app/database/migrations/2014_03_23_102357_CreateEveEveRefTypes.php b/app/database/migrations/2014_03_23_102357_CreateEveEveRefTypes.php new file mode 100644 index 00000000..9412699e --- /dev/null +++ b/app/database/migrations/2014_03_23_102357_CreateEveEveRefTypes.php @@ -0,0 +1,39 @@ +increments('id'); + + $table->integer('refTypeID')->unique(); + $table->text('refTypeName'); + + // Index + $table->index('refTypeID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('eve_reftypes'); + } + +} diff --git a/app/database/migrations/2014_03_23_114254_CreateEveEveConquerableStationList.php b/app/database/migrations/2014_03_23_114254_CreateEveEveConquerableStationList.php new file mode 100644 index 00000000..04b24566 --- /dev/null +++ b/app/database/migrations/2014_03_23_114254_CreateEveEveConquerableStationList.php @@ -0,0 +1,42 @@ +increments('id'); + + $table->integer('stationID')->unique(); + $table->string('stationName'); + $table->integer('stationTypeID'); + $table->integer('solarSystemID'); + $table->integer('corporationID'); + $table->string('corporationName'); + + // Index + $table->index('stationID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('eve_conquerablestationlist'); + } +} diff --git a/app/database/migrations/2014_03_23_151953_CreateEveEveCharacterInfo.php b/app/database/migrations/2014_03_23_151953_CreateEveEveCharacterInfo.php new file mode 100644 index 00000000..a9ff139e --- /dev/null +++ b/app/database/migrations/2014_03_23_151953_CreateEveEveCharacterInfo.php @@ -0,0 +1,62 @@ +increments('id'); + + $table->integer('characterID')->unique(); + $table->string('characterName'); + $table->string('race'); + $table->string('bloodline'); + + // Some columns will only be filled if a key/vcode pair is provided and valid, + // so make them nullable + $table->decimal('accountBalance', 22,2)->nullable(); // Some rich bastards out there + $table->integer('skillPoints')->nullable(); + $table->dateTime('nextTrainingEnds')->nullable(); + $table->string('shipName')->nullable(); + $table->integer('shipTypeID')->nullable(); + $table->string('shipTypeName')->nullable(); + + $table->integer('corporationID'); + $table->string('corporation'); + $table->dateTime('corporationDate'); + $table->integer('allianceID')->nullable(); + $table->string('alliance')->nullable(); + $table->dateTime('allianceDate')->nullable(); + + $table->string('lastKnownLocation')->nullable(); + + $table->decimal('securityStatus', 20, 13); + + // Index + $table->index('characterID'); + $table->index('characterName'); + $table->index('securityStatus'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('eve_characterinfo'); + } +} diff --git a/app/database/migrations/2014_03_23_153737_CreateEveEveCharacterInfoEmploymentHistory.php b/app/database/migrations/2014_03_23_153737_CreateEveEveCharacterInfoEmploymentHistory.php new file mode 100644 index 00000000..434f0d29 --- /dev/null +++ b/app/database/migrations/2014_03_23_153737_CreateEveEveCharacterInfoEmploymentHistory.php @@ -0,0 +1,40 @@ +increments('id'); + + // Id for the many to one relationship from class + // EveEveCharacterInfo + $table->integer('characterID'); + + $table->integer('recordID'); + $table->integer('corporationID'); + $table->dateTime('startDate'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('eve_characterinfo_employmenthistory'); + } +} diff --git a/app/database/migrations/2014_03_23_184711_CreateEveEveAllianceList.php b/app/database/migrations/2014_03_23_184711_CreateEveEveAllianceList.php new file mode 100644 index 00000000..3b0ee838 --- /dev/null +++ b/app/database/migrations/2014_03_23_184711_CreateEveEveAllianceList.php @@ -0,0 +1,45 @@ +increments('id'); + + $table->string('name'); + $table->string('shortName'); + $table->integer('allianceID'); + $table->integer('executorCorpID'); + $table->integer('memberCount'); + $table->dateTime('startDate'); + + // Indexes + $table->index('allianceID'); + + $table->timestamps(); + }); + } + + // name,shortName,allianceID,executorCorpID,memberCount,startDate + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('eve_alliancelist'); + } + +} diff --git a/app/database/migrations/2014_03_23_190236_CreateEveEveAllianceListMemberCorporations.php b/app/database/migrations/2014_03_23_190236_CreateEveEveAllianceListMemberCorporations.php new file mode 100644 index 00000000..dd681645 --- /dev/null +++ b/app/database/migrations/2014_03_23_190236_CreateEveEveAllianceListMemberCorporations.php @@ -0,0 +1,39 @@ +increments('id'); + + // Id for the many to one relationship from class + // EveEveAllianceList + $table->integer('allianceID'); + + $table->integer('corporationID'); + $table->dateTime('startDate'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('eve_alliancelist_membercorporations'); + } +} diff --git a/app/database/migrations/2014_03_24_104019_CreateEveAccountAPIKeyInfo.php b/app/database/migrations/2014_03_24_104019_CreateEveAccountAPIKeyInfo.php new file mode 100644 index 00000000..e18fa364 --- /dev/null +++ b/app/database/migrations/2014_03_24_104019_CreateEveAccountAPIKeyInfo.php @@ -0,0 +1,39 @@ +increments('id'); + + $table->integer('keyID'); + $table->integer('accessMask'); + $table->enum('type', array('Account','Character','Corporation')); + $table->dateTime('expires')->nullable(); + + $table->index('keyID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('account_apikeyinfo'); + } +} diff --git a/app/database/migrations/2014_03_24_104207_CreateEveAccountAPIKeyInfoCharacters.php b/app/database/migrations/2014_03_24_104207_CreateEveAccountAPIKeyInfoCharacters.php new file mode 100644 index 00000000..e23865c7 --- /dev/null +++ b/app/database/migrations/2014_03_24_104207_CreateEveAccountAPIKeyInfoCharacters.php @@ -0,0 +1,44 @@ +increments('id'); + + // Id for the many to one relationship from class + // EveAccountAPIKeyInfo + $table->integer('keyID'); + + $table->integer('characterID'); + $table->string('characterName'); + $table->integer('corporationID'); + $table->string('corporationName'); + + $table->index('characterID'); + $table->index('characterName'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('account_apikeyinfo_characters'); + } +} diff --git a/app/database/migrations/2014_03_24_122157_CreateEveAccountAccountStatus.php b/app/database/migrations/2014_03_24_122157_CreateEveAccountAccountStatus.php new file mode 100644 index 00000000..4766165c --- /dev/null +++ b/app/database/migrations/2014_03_24_122157_CreateEveAccountAccountStatus.php @@ -0,0 +1,44 @@ +increments('id'); + + // Id for the one to one relationship from class + // EveAccountAPIKeyInfo + $table->integer('keyID'); + + $table->dateTime('paidUntil'); + $table->dateTime('createDate'); + $table->integer('logonCount'); + $table->integer('logonMinutes'); + + $table->index('keyID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('account_accountstatus'); + } + +} diff --git a/app/database/migrations/2014_03_25_113533_CreateSeatBannedCall.php b/app/database/migrations/2014_03_25_113533_CreateSeatBannedCall.php new file mode 100644 index 00000000..8c65597b --- /dev/null +++ b/app/database/migrations/2014_03_25_113533_CreateSeatBannedCall.php @@ -0,0 +1,44 @@ +increments('id'); + + $table->integer('ownerID'); + $table->string('api'); + $table->string('scope'); + $table->string('hash', 32); + $table->integer('accessMask')->default(0)->nullable(); + $table->string('reason')->nullable(); + + // Indexes + $table->index('ownerID'); + $table->index('api'); + $table->index('hash'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('banned_calls'); + } +} diff --git a/app/database/migrations/2014_03_26_045031_CreateSeatQueueInformation.php b/app/database/migrations/2014_03_26_045031_CreateSeatQueueInformation.php new file mode 100644 index 00000000..f9467714 --- /dev/null +++ b/app/database/migrations/2014_03_26_045031_CreateSeatQueueInformation.php @@ -0,0 +1,45 @@ +increments('id'); + + $table->string('jobID')->unique(); + $table->integer('ownerID'); + $table->string('api'); + $table->string('scope'); + $table->string('output')->default(null)->nullable(); + $table->enum('status', array('Queued','Working','Done', 'Error')); + + // Indexes + $table->index('jobID'); + $table->index('ownerID'); + $table->index('status'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('queue_information'); + } + +} diff --git a/app/database/migrations/2014_03_26_161501_CreateEveCharacterAccountBalance.php b/app/database/migrations/2014_03_26_161501_CreateEveCharacterAccountBalance.php new file mode 100644 index 00000000..7b0fb9ec --- /dev/null +++ b/app/database/migrations/2014_03_26_161501_CreateEveCharacterAccountBalance.php @@ -0,0 +1,43 @@ +increments('id'); + + // Id for the many to one relationship from class + // EveEveCharacterInfo + $table->integer('characterID'); + + $table->integer('accountID'); + $table->integer('accountKey'); + $table->decimal('balance', 22,2)->nullable(); // Some rich bastards out there + + $table->index('characterID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_accountbalance'); + } + +} diff --git a/app/database/migrations/2014_03_27_085631_CreateEveCharacterAssetList.php b/app/database/migrations/2014_03_27_085631_CreateEveCharacterAssetList.php new file mode 100644 index 00000000..d311fbe2 --- /dev/null +++ b/app/database/migrations/2014_03_27_085631_CreateEveCharacterAssetList.php @@ -0,0 +1,48 @@ +increments('id'); + + // Id for the many to one relationship from class + // EveEveCharacterInfo + $table->integer('characterID'); + + $table->bigInteger('itemID'); + $table->bigInteger('locationID'); + $table->bigInteger('typeID'); + $table->integer('quantity'); + $table->integer('flag'); + $table->boolean('singleton'); + $table->integer('rawQuantity')->default(0); + + $table->index('characterID'); + $table->index('locationID'); + $table->index('typeID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_assetlist'); + } +} diff --git a/app/database/migrations/2014_03_27_085645_CreateEveCharacterAssetListContents.php b/app/database/migrations/2014_03_27_085645_CreateEveCharacterAssetListContents.php new file mode 100644 index 00000000..6e3d1e44 --- /dev/null +++ b/app/database/migrations/2014_03_27_085645_CreateEveCharacterAssetListContents.php @@ -0,0 +1,47 @@ +increments('id'); + + // Id for the many to one relationship from class + // EveEveCharacterInfo + $table->integer('characterID'); + + $table->bigInteger('itemID'); + $table->bigInteger('typeID'); + $table->integer('quantity'); + $table->integer('flag'); + $table->boolean('singleton'); + $table->integer('rawQuantity')->default(0); + + $table->index('characterID'); + $table->index('typeID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_assetlist_contents'); + } + +} diff --git a/app/database/migrations/2014_03_27_121947_CreateEveCharacterSheet.php b/app/database/migrations/2014_03_27_121947_CreateEveCharacterSheet.php new file mode 100644 index 00000000..d3fcb12c --- /dev/null +++ b/app/database/migrations/2014_03_27_121947_CreateEveCharacterSheet.php @@ -0,0 +1,61 @@ +increments('id'); + + // Id for the many to one relationship from class + // EveEveCharacterInfo + $table->integer('characterID'); + + $table->string('name'); + $table->dateTime('DoB'); + $table->string('race'); + $table->string('bloodLine'); + $table->string('ancestry'); + $table->string('gender'); + $table->string('corporationName'); + $table->integer('corporationID'); + $table->string('cloneName'); + $table->integer('cloneSkillPoints'); + $table->decimal('balance', 22,2)->nullable(); // Some rich bastards out there + + // Really dont see why we need to make another table just for these attribs. + // Soooo, just gonna slap 'em in here. + $table->integer('intelligence'); + $table->integer('memory'); + $table->integer('charisma'); + $table->integer('perception'); + $table->integer('willpower'); + + // Indexes + $table->index('characterID'); + $table->index('name'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_charactersheet'); + } + +} diff --git a/app/database/migrations/2014_03_27_141418_CreateEveCharacterSheetSkills.php b/app/database/migrations/2014_03_27_141418_CreateEveCharacterSheetSkills.php new file mode 100644 index 00000000..a89e77ec --- /dev/null +++ b/app/database/migrations/2014_03_27_141418_CreateEveCharacterSheetSkills.php @@ -0,0 +1,45 @@ +increments('id'); + + // Id for the many to one relationship from class + // EveEveCharacterInfo + $table->integer('characterID'); + + $table->integer('typeID'); + $table->integer('skillpoints'); + $table->integer('level'); + $table->integer('published'); + + // Indexes + $table->index('characterID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_charactersheet_skills'); + } + +} diff --git a/app/database/migrations/2014_03_28_074924_CreateEveCharacterContactList.php b/app/database/migrations/2014_03_28_074924_CreateEveCharacterContactList.php new file mode 100644 index 00000000..1fe45bba --- /dev/null +++ b/app/database/migrations/2014_03_28_074924_CreateEveCharacterContactList.php @@ -0,0 +1,47 @@ +increments('id'); + + // Id for the many to one relationship from class + // EveEveCharacterInfo + $table->integer('characterID'); + + $table->integer('contactID'); + $table->string('contactName'); + $table->boolean('inWatchlist')->nullable(); + $table->integer('standing'); + $table->integer('contactTypeID'); + + // Indexes + $table->index('characterID'); + $table->index('contactID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_contactlist'); + } + +} diff --git a/app/database/migrations/2014_03_28_074959_CreateEveCharacterCorporateContactList.php b/app/database/migrations/2014_03_28_074959_CreateEveCharacterCorporateContactList.php new file mode 100644 index 00000000..e4db3bbd --- /dev/null +++ b/app/database/migrations/2014_03_28_074959_CreateEveCharacterCorporateContactList.php @@ -0,0 +1,46 @@ +increments('id'); + + // Id for the many to one relationship from class + // EveEveCharacterInfo + $table->integer('characterID'); + + $table->integer('contactID'); + $table->string('contactName'); + $table->integer('standing'); + $table->integer('contactTypeID'); + + // Indexes + $table->index('characterID'); + $table->index('contactID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_contactlist_corporate'); + } + +} diff --git a/app/database/migrations/2014_03_28_075041_CreateEveCharacterAllianceContactList.php b/app/database/migrations/2014_03_28_075041_CreateEveCharacterAllianceContactList.php new file mode 100644 index 00000000..90bf9da4 --- /dev/null +++ b/app/database/migrations/2014_03_28_075041_CreateEveCharacterAllianceContactList.php @@ -0,0 +1,46 @@ +increments('id'); + + // Id for the many to one relationship from class + // EveEveCharacterInfo + $table->integer('characterID'); + + $table->integer('contactID'); + $table->string('contactName'); + $table->integer('standing'); + $table->integer('contactTypeID'); + + // Indexes + $table->index('characterID'); + $table->index('contactID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_contactlist_alliance'); + } + +} diff --git a/app/database/migrations/2014_03_28_101644_CreateEveCharacterContactNotifications.php b/app/database/migrations/2014_03_28_101644_CreateEveCharacterContactNotifications.php new file mode 100644 index 00000000..e38afad2 --- /dev/null +++ b/app/database/migrations/2014_03_28_101644_CreateEveCharacterContactNotifications.php @@ -0,0 +1,46 @@ +increments('id'); + + // Id for the many to one relationship from class + // EveEveCharacterInfo + $table->integer('characterID'); + + $table->integer('notificationID'); + $table->integer('senderID'); + $table->string('senderName'); + $table->dateTime('sentDate'); + $table->string('messageData'); + + // Indexes + $table->index('characterID'); + $table->index('notificationID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_contactnotifications'); + } +} diff --git a/app/database/migrations/2014_03_28_114602_CreateEveCharacterContracts.php b/app/database/migrations/2014_03_28_114602_CreateEveCharacterContracts.php new file mode 100644 index 00000000..ff569c7a --- /dev/null +++ b/app/database/migrations/2014_03_28_114602_CreateEveCharacterContracts.php @@ -0,0 +1,63 @@ +increments('id'); + + // Id for the many to one relationship from class + // EveEveCharacterInfo + $table->integer('characterID'); + + $table->integer('contractID'); + $table->integer('issuerID'); + $table->integer('issuerCorpID'); + $table->integer('acceptorID'); + $table->integer('startStationID'); + $table->integer('endStationID'); + $table->string('type'); + $table->string('status'); + $table->string('title')->nullable(); + $table->integer('forCorp'); + $table->string('availability'); + $table->dateTime('dateIssued'); + $table->dateTime('dateExpired')->nullable(); + $table->dateTime('dateAccepted')->nullable(); + $table->integer('numDays'); + $table->dateTime('dateCompleted')->nullable(); + $table->decimal('price', 22,2); + $table->decimal('reward', 22,2); + $table->decimal('collateral', 22,2); + $table->decimal('buyout', 22,2); + $table->integer('volume'); + + // Indexes + $table->index('characterID'); + $table->index('contractID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_contracts'); + } + +} diff --git a/app/database/migrations/2014_03_28_124422_CreateEveCharacterContractsItems.php b/app/database/migrations/2014_03_28_124422_CreateEveCharacterContractsItems.php new file mode 100644 index 00000000..1c7f0287 --- /dev/null +++ b/app/database/migrations/2014_03_28_124422_CreateEveCharacterContractsItems.php @@ -0,0 +1,49 @@ +increments('id'); + + // Id for the many to one relationship from class + // EveEveCharacterInfo + $table->integer('characterID'); + $table->integer('contractID'); + + $table->integer('recordID'); + $table->integer('typeID'); + $table->integer('quantity'); + $table->integer('rawQuantity')->nullable(); + $table->integer('singleton'); + $table->string('included'); + + // Indexes + $table->index('characterID'); + $table->index('contractID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_contracts_items'); + } + +} diff --git a/app/database/migrations/2014_03_28_145406_CreateEveCharacterIndustryJobs.php b/app/database/migrations/2014_03_28_145406_CreateEveCharacterIndustryJobs.php new file mode 100644 index 00000000..6fdbbf4d --- /dev/null +++ b/app/database/migrations/2014_03_28_145406_CreateEveCharacterIndustryJobs.php @@ -0,0 +1,74 @@ +increments('id'); + + // Id for the many to one relationship from class + // EveEveCharacterInfo + $table->integer('characterID'); + $table->integer('jobID'); + $table->integer('assemblyLineID'); + $table->bigInteger('containerID'); + $table->bigInteger('installedItemID'); + $table->bigInteger('installedItemLocationID'); + $table->integer('installedItemQuantity'); + $table->integer('installedItemProductivityLevel'); + $table->integer('installedItemMaterialLevel'); + $table->integer('installedItemLicensedProductionRunsRemaining'); + $table->bigInteger('outputLocationID'); + $table->integer('installerID'); + $table->integer('runs'); + $table->integer('licensedProductionRuns'); + $table->integer('installedInSolarSystemID'); + $table->integer('containerLocationID'); + $table->float('materialMultiplier'); + $table->float('charMaterialMultiplier'); + $table->float('timeMultiplier'); + $table->float('charTimeMultiplier'); + $table->integer('installedItemTypeID'); + $table->integer('outputTypeID'); + $table->integer('containerTypeID'); + $table->boolean('installedItemCopy'); + $table->boolean('completed'); + $table->boolean('completedSuccessfully'); + $table->integer('installedItemFlag'); + $table->integer('outputFlag'); + $table->integer('activityID'); + $table->integer('completedStatus'); + $table->dateTime('installTime'); + $table->dateTime('beginProductionTime'); + $table->dateTime('endProductionTime'); + $table->dateTime('pauseProductionTime'); + + // Indexes + $table->index('characterID'); + $table->index('jobID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_industryjobs'); + } + +} diff --git a/app/database/migrations/2014_03_28_163740_CreateEveCharacterMailMessages.php b/app/database/migrations/2014_03_28_163740_CreateEveCharacterMailMessages.php new file mode 100644 index 00000000..160dad04 --- /dev/null +++ b/app/database/migrations/2014_03_28_163740_CreateEveCharacterMailMessages.php @@ -0,0 +1,50 @@ +increments('id'); + + // Id for the many to one relationship from class + // EveEveCharacterInfo + $table->integer('characterID'); + $table->integer('messageID'); + + $table->integer('senderID'); + $table->string('senderName'); + $table->dateTime('sentDate'); + $table->string('title'); + $table->integer('toCorpOrAllianceID')->nullable(); + $table->text('toCharacterIDs')->nullable(); + $table->integer('toListID')->nullable(); + + // Indexes + $table->index('characterID'); + $table->index('messageID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_mailmessages'); + } + +} diff --git a/app/database/migrations/2014_03_28_173326_CreateEveCharacterMailBodies.php b/app/database/migrations/2014_03_28_173326_CreateEveCharacterMailBodies.php new file mode 100644 index 00000000..c6083afb --- /dev/null +++ b/app/database/migrations/2014_03_28_173326_CreateEveCharacterMailBodies.php @@ -0,0 +1,41 @@ +increments('id'); + + // Id for the many to one relationship from class + // EveEveCharacterInfo + $table->integer('messageID')->unique(); + + $table->text('body'); + + // Indexes + $table->index('messageID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_mailbodies'); + } +} diff --git a/app/database/migrations/2014_03_29_044308_CreateEveCharacterMailingLists.php b/app/database/migrations/2014_03_29_044308_CreateEveCharacterMailingLists.php new file mode 100644 index 00000000..5b5d7516 --- /dev/null +++ b/app/database/migrations/2014_03_29_044308_CreateEveCharacterMailingLists.php @@ -0,0 +1,41 @@ +increments('id'); + + $table->integer('characterID'); + $table->integer('listID'); + $table->string('displayName'); + + // Indexes + $table->index('characterID'); + $table->index('listID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_mailinglists'); + } + +} diff --git a/app/database/migrations/2014_03_29_075707_CreateEveCharacterMarketOrders.php b/app/database/migrations/2014_03_29_075707_CreateEveCharacterMarketOrders.php new file mode 100644 index 00000000..70acac10 --- /dev/null +++ b/app/database/migrations/2014_03_29_075707_CreateEveCharacterMarketOrders.php @@ -0,0 +1,53 @@ +increments('id'); + + $table->integer('characterID'); + $table->bigInteger('orderID'); + $table->integer('charID'); + $table->integer('stationID'); + $table->integer('volEntered'); + $table->integer('volRemaining'); + $table->integer('minVolume'); + $table->integer('orderState'); + $table->integer('typeID'); + $table->integer('range'); + $table->integer('duration'); + $table->decimal('escrow', 22,2); + $table->decimal('price', 22,2); + $table->integer('bid'); + $table->dateTime('issued'); + + // Indexes + $table->index('characterID'); + $table->index('orderID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_marketorders'); + } + +} diff --git a/app/database/migrations/2014_03_29_093955_CreateEveEveNotificationTypes.php b/app/database/migrations/2014_03_29_093955_CreateEveEveNotificationTypes.php new file mode 100644 index 00000000..4572b2ce --- /dev/null +++ b/app/database/migrations/2014_03_29_093955_CreateEveEveNotificationTypes.php @@ -0,0 +1,36 @@ +increments('id'); + + $table->integer('typeID')->unique(); + $table->string('description'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('eve_notification_types'); + } + +} diff --git a/app/database/migrations/2014_03_29_104513_CreateEveCharacterNotifications.php b/app/database/migrations/2014_03_29_104513_CreateEveCharacterNotifications.php new file mode 100644 index 00000000..89552dee --- /dev/null +++ b/app/database/migrations/2014_03_29_104513_CreateEveCharacterNotifications.php @@ -0,0 +1,46 @@ +increments('id'); + + $table->integer('characterID'); + $table->integer('notificationID'); + + $table->integer('typeID'); + $table->integer('senderID'); + $table->string('senderName'); + $table->dateTime('sentDate'); + $table->integer('read'); + + // Indexes + $table->index('characterID'); + $table->index('notificationID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_notifications'); + } + +} diff --git a/app/database/migrations/2014_03_29_125122_CreateEveCharacterNotificationTexts.php b/app/database/migrations/2014_03_29_125122_CreateEveCharacterNotificationTexts.php new file mode 100644 index 00000000..0258497b --- /dev/null +++ b/app/database/migrations/2014_03_29_125122_CreateEveCharacterNotificationTexts.php @@ -0,0 +1,39 @@ +increments('id'); + + $table->integer('notificationID'); + $table->text('text'); + + // Indexes + $table->index('notificationID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_notification_texts'); + } + +} diff --git a/app/database/migrations/2014_03_29_145832_CreateEveCharacterResearch.php b/app/database/migrations/2014_03_29_145832_CreateEveCharacterResearch.php new file mode 100644 index 00000000..5c1a9e7a --- /dev/null +++ b/app/database/migrations/2014_03_29_145832_CreateEveCharacterResearch.php @@ -0,0 +1,43 @@ +increments('id'); + + $table->integer('characterID'); + $table->integer('agentID'); + $table->integer('skillTypeID'); + $table->dateTime('researchStartDate'); + $table->float('pointsPerDay'); + $table->float('remainderPoints'); + + // Indexes + $table->index('characterID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_research'); + } + +} diff --git a/app/database/migrations/2014_03_29_160937_CreateEveCharacterSkillInTraining.php b/app/database/migrations/2014_03_29_160937_CreateEveCharacterSkillInTraining.php new file mode 100644 index 00000000..b644f2b0 --- /dev/null +++ b/app/database/migrations/2014_03_29_160937_CreateEveCharacterSkillInTraining.php @@ -0,0 +1,46 @@ +increments('id'); + + $table->integer('characterID'); + $table->dateTime('currentTQTime')->nullable(); + $table->dateTime('trainingEndTime')->nullable(); + $table->dateTime('trainingStartTime')->nullable(); + $table->integer('trainingTypeID')->nullable(); + $table->integer('trainingStartSP')->nullable(); + $table->integer('trainingDestinationSP')->nullable(); + $table->integer('trainingToLevel')->nullable(); + $table->integer('skillInTraining'); + + // Indexes + $table->index('characterID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_skillintraining'); + } + +} diff --git a/app/database/migrations/2014_03_29_192807_CreateEveCharacterSkillQueue.php b/app/database/migrations/2014_03_29_192807_CreateEveCharacterSkillQueue.php new file mode 100644 index 00000000..3daa03dd --- /dev/null +++ b/app/database/migrations/2014_03_29_192807_CreateEveCharacterSkillQueue.php @@ -0,0 +1,45 @@ +increments('id'); + + $table->integer('characterID'); + $table->integer('queuePosition'); + $table->integer('typeID'); + $table->integer('level'); + $table->integer('startSP'); + $table->integer('endSP'); + $table->dateTime('startTime')->nullable(); // If current queue is paused this will be null + $table->dateTime('endTime')->nullable(); // If current queue is paused this will be null + + // Indexes + $table->index('characterID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_skillqueue'); + } + +} diff --git a/app/database/migrations/2014_03_29_200727_CreateEveCharacterStandingsAgents.php b/app/database/migrations/2014_03_29_200727_CreateEveCharacterStandingsAgents.php new file mode 100644 index 00000000..04a291aa --- /dev/null +++ b/app/database/migrations/2014_03_29_200727_CreateEveCharacterStandingsAgents.php @@ -0,0 +1,42 @@ +increments('id'); + + $table->integer('characterID'); + + $table->integer('fromID'); + $table->string('fromName'); + $table->float('standing'); + + // Indexes + $table->index('characterID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_standings_agents'); + } + +} diff --git a/app/database/migrations/2014_03_29_200745_CreateEveCharacterStandingsNPCCorporations.php b/app/database/migrations/2014_03_29_200745_CreateEveCharacterStandingsNPCCorporations.php new file mode 100644 index 00000000..2f25dcd5 --- /dev/null +++ b/app/database/migrations/2014_03_29_200745_CreateEveCharacterStandingsNPCCorporations.php @@ -0,0 +1,42 @@ +increments('id'); + + $table->integer('characterID'); + + $table->integer('fromID'); + $table->string('fromName'); + $table->float('standing'); + + // Indexes + $table->index('characterID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_standings_npccorporations'); + } + +} diff --git a/app/database/migrations/2014_03_29_200910_CreateEveCharacterStandingsFactions.php b/app/database/migrations/2014_03_29_200910_CreateEveCharacterStandingsFactions.php new file mode 100644 index 00000000..aa4e9a20 --- /dev/null +++ b/app/database/migrations/2014_03_29_200910_CreateEveCharacterStandingsFactions.php @@ -0,0 +1,42 @@ +increments('id'); + + $table->integer('characterID'); + + $table->integer('fromID'); + $table->string('fromName'); + $table->float('standing'); + + // Indexes + $table->index('characterID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_standings_factions'); + } + +} diff --git a/app/database/migrations/2014_03_29_224238_CreateEveCharacterUpcomingCalendarEvents.php b/app/database/migrations/2014_03_29_224238_CreateEveCharacterUpcomingCalendarEvents.php new file mode 100644 index 00000000..699520ec --- /dev/null +++ b/app/database/migrations/2014_03_29_224238_CreateEveCharacterUpcomingCalendarEvents.php @@ -0,0 +1,49 @@ +increments('id'); + + $table->integer('characterID'); + + $table->bigInteger('eventID'); + $table->bigInteger('ownerID'); + $table->string('ownerName')->nullable(); + $table->dateTime('eventDate'); + $table->string('eventTitle'); + $table->integer('duration'); + $table->boolean('importance'); + $table->enum('response', array('Undecided','Accepted','Declined', 'Tentative')); + $table->text('eventText'); + $table->integer('ownerTypeID'); + + // Indexes + $table->index('characterID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_upcomingcalendarevents'); + } + +} diff --git a/app/database/migrations/2014_03_30_161440_CreateEveCharacterWalletJournal.php b/app/database/migrations/2014_03_30_161440_CreateEveCharacterWalletJournal.php new file mode 100644 index 00000000..ea0c8a4a --- /dev/null +++ b/app/database/migrations/2014_03_30_161440_CreateEveCharacterWalletJournal.php @@ -0,0 +1,60 @@ +increments('id'); + + $table->integer('characterID'); + + // Hash for transaction uniqueness as it appears that + // refID's may cycle... + $table->string('hash')->unique(); + + $table->bigInteger('refID'); + $table->dateTime('date'); + $table->integer('refTypeID'); + $table->string('ownerName1'); + $table->integer('ownerID1'); + $table->string('ownerName2'); + $table->integer('ownerID2'); + $table->string('argName1'); + $table->integer('argID1'); + $table->decimal('amount', 22,2); + $table->decimal('balance', 22,2); + $table->string('reason'); + $table->integer('taxReceiverID'); + $table->decimal('taxAmount', 22,2); + $table->integer('owner1TypeID'); + $table->integer('owner2TypeID'); + + // Indexes + $table->index('characterID'); + $table->index('refID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_walletjournal'); + } + +} diff --git a/app/database/migrations/2014_03_30_181437_CreateEveCharacterWalletTransactions.php b/app/database/migrations/2014_03_30_181437_CreateEveCharacterWalletTransactions.php new file mode 100644 index 00000000..c7c60862 --- /dev/null +++ b/app/database/migrations/2014_03_30_181437_CreateEveCharacterWalletTransactions.php @@ -0,0 +1,58 @@ +increments('id'); + + $table->integer('characterID'); + + // Hash for transaction uniqueness as it appears that + // refID's may cycle... + $table->string('hash')->unique(); + + $table->bigInteger('transactionID'); + $table->dateTime('transactionDateTime'); + $table->integer('quantity'); + $table->string('typeName'); + $table->integer('typeID'); + $table->decimal('price', 22,2); + $table->integer('clientID'); + $table->string('clientName'); + $table->integer('stationID'); + $table->string('stationName'); + $table->enum('transactionType', array('buy','sell')); + $table->enum('transactionFor', array('personal','corporation')); + $table->bigInteger('journalTransactionID'); + $table->integer('clientTypeID'); + + // Indexes + $table->index('characterID'); + $table->index('transactionID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('character_wallettransactions'); + } + +} diff --git a/app/database/migrations/2014_04_01_114920_CreateEveCorporationAccountBalance.php b/app/database/migrations/2014_04_01_114920_CreateEveCorporationAccountBalance.php new file mode 100644 index 00000000..c6dec1b2 --- /dev/null +++ b/app/database/migrations/2014_04_01_114920_CreateEveCorporationAccountBalance.php @@ -0,0 +1,43 @@ +increments('id'); + + $table->bigInteger('corporationID'); + + $table->integer('accountID'); + $table->integer('accountKey'); + $table->decimal('balance', 22,2); + + // Indexes + $table->index('corporationID'); + $table->index('accountKey'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('corporation_accountbalance'); + } + +} diff --git a/app/database/migrations/2014_04_01_151652_CreateEveCorporationAssetList.php b/app/database/migrations/2014_04_01_151652_CreateEveCorporationAssetList.php new file mode 100644 index 00000000..72f4f3c2 --- /dev/null +++ b/app/database/migrations/2014_04_01_151652_CreateEveCorporationAssetList.php @@ -0,0 +1,47 @@ +increments('id'); + + $table->integer('corporationID'); + + $table->bigInteger('itemID'); + $table->bigInteger('locationID'); + $table->bigInteger('typeID'); + $table->integer('quantity'); + $table->integer('flag'); + $table->boolean('singleton'); + $table->integer('rawQuantity')->default(0); + + $table->index('corporationID'); + $table->index('locationID'); + $table->index('typeID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('corporation_assetlist'); + } + +} diff --git a/app/database/migrations/2014_04_01_151715_CreateEveCorporationAssetListContents.php b/app/database/migrations/2014_04_01_151715_CreateEveCorporationAssetListContents.php new file mode 100644 index 00000000..dbfbcc60 --- /dev/null +++ b/app/database/migrations/2014_04_01_151715_CreateEveCorporationAssetListContents.php @@ -0,0 +1,45 @@ +increments('id'); + + $table->integer('corporationID'); + + $table->bigInteger('itemID'); + $table->bigInteger('typeID'); + $table->integer('quantity'); + $table->integer('flag'); + $table->boolean('singleton'); + $table->integer('rawQuantity')->default(0); + + $table->index('corporationID'); + $table->index('typeID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('corporation_assetlist_contents'); + } + +} diff --git a/app/database/migrations/2014_04_01_155106_CreateEveCorporationAllianceContactList.php b/app/database/migrations/2014_04_01_155106_CreateEveCorporationAllianceContactList.php new file mode 100644 index 00000000..76a032ed --- /dev/null +++ b/app/database/migrations/2014_04_01_155106_CreateEveCorporationAllianceContactList.php @@ -0,0 +1,44 @@ +increments('id'); + + $table->integer('corporationID'); + + $table->integer('contactID'); + $table->string('contactName'); + $table->integer('standing'); + $table->integer('contactTypeID'); + + // Indexes + $table->index('corporationID'); + $table->index('contactID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('corporation_contactlist_alliance'); + } + +} diff --git a/app/database/migrations/2014_04_01_155200_CreateEveCorporationCorporateContactList.php b/app/database/migrations/2014_04_01_155200_CreateEveCorporationCorporateContactList.php new file mode 100644 index 00000000..34a6eca0 --- /dev/null +++ b/app/database/migrations/2014_04_01_155200_CreateEveCorporationCorporateContactList.php @@ -0,0 +1,44 @@ +increments('id'); + + $table->integer('corporationID'); + + $table->integer('contactID'); + $table->string('contactName'); + $table->integer('standing'); + $table->integer('contactTypeID'); + + // Indexes + $table->index('corporationID'); + $table->index('contactID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('corporation_contactlist_corporate'); + } + +} diff --git a/app/database/migrations/2014_04_01_170702_CreateEveCorporationContracts.php b/app/database/migrations/2014_04_01_170702_CreateEveCorporationContracts.php new file mode 100644 index 00000000..959e4ef9 --- /dev/null +++ b/app/database/migrations/2014_04_01_170702_CreateEveCorporationContracts.php @@ -0,0 +1,61 @@ +increments('id'); + + $table->integer('corporationID'); + + $table->integer('contractID'); + $table->integer('issuerID'); + $table->integer('issuerCorpID'); + $table->integer('acceptorID'); + $table->integer('startStationID'); + $table->integer('endStationID'); + $table->string('type'); + $table->string('status'); + $table->string('title')->nullable(); + $table->integer('forCorp'); + $table->string('availability'); + $table->dateTime('dateIssued'); + $table->dateTime('dateExpired')->nullable(); + $table->dateTime('dateAccepted')->nullable(); + $table->integer('numDays'); + $table->dateTime('dateCompleted')->nullable(); + $table->decimal('price', 22,2); + $table->decimal('reward', 22,2); + $table->decimal('collateral', 22,2); + $table->decimal('buyout', 22,2); + $table->integer('volume'); + + // Indexes + $table->index('corporationID'); + $table->index('contractID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('corporation_contracts'); + } + +} diff --git a/app/database/migrations/2014_04_01_170730_CreateEveCorporationContractsItems.php b/app/database/migrations/2014_04_01_170730_CreateEveCorporationContractsItems.php new file mode 100644 index 00000000..0f9471bc --- /dev/null +++ b/app/database/migrations/2014_04_01_170730_CreateEveCorporationContractsItems.php @@ -0,0 +1,49 @@ +increments('id'); + + // Id for the many to one relationship from class + // EveEveCharacterInfo + $table->integer('corporationID'); + $table->integer('contractID'); + + $table->integer('recordID'); + $table->integer('typeID'); + $table->integer('quantity'); + $table->integer('rawQuantity')->nullable(); + $table->integer('singleton'); + $table->string('included'); + + // Indexes + $table->index('corporationID'); + $table->index('contractID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('corporation_contracts_items'); + } + +} diff --git a/app/database/migrations/2014_04_02_110839_CreateEveCorporationSheet.php b/app/database/migrations/2014_04_02_110839_CreateEveCorporationSheet.php new file mode 100644 index 00000000..d841d292 --- /dev/null +++ b/app/database/migrations/2014_04_02_110839_CreateEveCorporationSheet.php @@ -0,0 +1,65 @@ +increments('id'); + + $table->integer('corporationID'); + + $table->string('corporationName'); + $table->string('ticker'); + $table->integer('ceoID'); + $table->string('ceoName'); + $table->integer('stationID'); + $table->string('stationName'); + $table->text('description'); + $table->string('url'); + $table->integer('allianceID'); + $table->integer('factionID'); + $table->string('allianceName'); + $table->decimal('taxRate', 22,2); + $table->integer('memberCount'); + $table->integer('memberLimit'); + $table->integer('shares'); + + // Really dont see why we need to make another table just for these attribs. + // Soooo, just gonna slap 'em in here. + $table->integer('graphicID'); + $table->integer('shape1'); + $table->integer('shape2'); + $table->integer('shape3'); + $table->integer('color1'); + $table->integer('color2'); + $table->integer('color3'); + + // Indexes + $table->index('corporationID'); + $table->index('corporationName'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('corporation_corporationsheet'); + } + +} diff --git a/app/database/migrations/2014_04_02_111815_CreateEveCorporationSheetDivisions.php b/app/database/migrations/2014_04_02_111815_CreateEveCorporationSheetDivisions.php new file mode 100644 index 00000000..d202b2da --- /dev/null +++ b/app/database/migrations/2014_04_02_111815_CreateEveCorporationSheetDivisions.php @@ -0,0 +1,42 @@ +increments('id'); + + $table->integer('corporationID'); + + $table->integer('accountKey'); + $table->string('description'); + + // Indexes + $table->index('corporationID'); + $table->index('accountKey'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('corporation_corporationsheet_divisions'); + } + +} diff --git a/app/database/migrations/2014_04_02_111830_CreateEveCorporationSheetWalletDivisions.php b/app/database/migrations/2014_04_02_111830_CreateEveCorporationSheetWalletDivisions.php new file mode 100644 index 00000000..2a8659ad --- /dev/null +++ b/app/database/migrations/2014_04_02_111830_CreateEveCorporationSheetWalletDivisions.php @@ -0,0 +1,42 @@ +increments('id'); + + $table->integer('corporationID'); + + $table->integer('accountKey'); + $table->string('description'); + + // Indexes + $table->index('corporationID'); + $table->index('accountKey'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('corporation_corporationsheet_walletdivisions'); + } + +} diff --git a/app/database/migrations/2014_04_02_114928_CreateEveCorporationIndustryJobs.php b/app/database/migrations/2014_04_02_114928_CreateEveCorporationIndustryJobs.php new file mode 100644 index 00000000..ab3332e1 --- /dev/null +++ b/app/database/migrations/2014_04_02_114928_CreateEveCorporationIndustryJobs.php @@ -0,0 +1,73 @@ +increments('id'); + + // Id for the many to one relationship from class + // EveEveCharacterInfo + $table->integer('corporationID'); + $table->integer('jobID'); + $table->integer('assemblyLineID'); + $table->bigInteger('containerID'); + $table->bigInteger('installedItemID'); + $table->bigInteger('installedItemLocationID'); + $table->integer('installedItemQuantity'); + $table->integer('installedItemProductivityLevel'); + $table->integer('installedItemMaterialLevel'); + $table->integer('installedItemLicensedProductionRunsRemaining'); + $table->bigInteger('outputLocationID'); + $table->integer('installerID'); + $table->integer('runs'); + $table->integer('licensedProductionRuns'); + $table->integer('installedInSolarSystemID'); + $table->integer('containerLocationID'); + $table->float('materialMultiplier'); + $table->float('charMaterialMultiplier'); + $table->float('timeMultiplier'); + $table->float('charTimeMultiplier'); + $table->integer('installedItemTypeID'); + $table->integer('outputTypeID'); + $table->integer('containerTypeID'); + $table->boolean('installedItemCopy'); + $table->boolean('completed'); + $table->boolean('completedSuccessfully'); + $table->integer('installedItemFlag'); + $table->integer('outputFlag'); + $table->integer('activityID'); + $table->integer('completedStatus'); + $table->dateTime('installTime'); + $table->dateTime('beginProductionTime'); + $table->dateTime('endProductionTime'); + $table->dateTime('pauseProductionTime'); + + // Indexes + $table->index('corporationID'); + $table->index('jobID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('corporation_industryjobs'); + } +} diff --git a/app/database/migrations/2014_04_02_121216_CreateEveCorporationAssetListLocations.php b/app/database/migrations/2014_04_02_121216_CreateEveCorporationAssetListLocations.php new file mode 100644 index 00000000..c40a78eb --- /dev/null +++ b/app/database/migrations/2014_04_02_121216_CreateEveCorporationAssetListLocations.php @@ -0,0 +1,44 @@ +increments('id'); + + $table->integer('corporationID'); + + $table->bigInteger('itemID'); + $table->string('itemName'); + $table->double('x'); + $table->double('y'); + $table->double('z'); + + $table->index('corporationID'); + $table->index('itemID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('corporation_assetlist_locations'); + } + +} diff --git a/app/database/migrations/2014_04_02_162945_CreateEveCorporationMarketOrders.php b/app/database/migrations/2014_04_02_162945_CreateEveCorporationMarketOrders.php new file mode 100644 index 00000000..3ea49af9 --- /dev/null +++ b/app/database/migrations/2014_04_02_162945_CreateEveCorporationMarketOrders.php @@ -0,0 +1,55 @@ +increments('id'); + + $table->integer('corporationID'); + $table->bigInteger('orderID'); + $table->integer('charID'); + $table->integer('stationID'); + $table->integer('volEntered'); + $table->integer('volRemaining'); + $table->integer('minVolume'); + $table->integer('orderState'); + $table->integer('typeID'); + $table->integer('range'); + $table->integer('accountKey'); + $table->integer('duration'); + $table->decimal('escrow', 22,2); + $table->decimal('price', 22,2); + $table->integer('bid'); + $table->dateTime('issued'); + + // Indexes + $table->index('corporationID'); + $table->index('orderID'); + $table->index('accountKey'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('corporation_marketorders'); + } + +} diff --git a/app/database/migrations/2014_04_02_165032_CreateEveCorporationMedals.php b/app/database/migrations/2014_04_02_165032_CreateEveCorporationMedals.php new file mode 100644 index 00000000..d577df59 --- /dev/null +++ b/app/database/migrations/2014_04_02_165032_CreateEveCorporationMedals.php @@ -0,0 +1,43 @@ +increments('id'); + + $table->integer('corporationID'); + $table->integer('medalID'); + $table->string('title'); + $table->text('description'); + $table->integer('creatorID'); + $table->dateTime('created'); + + // Indexes + $table->index('corporationID'); + $table->index('medalID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('corporation_medals'); + } +} diff --git a/app/database/migrations/2014_04_02_171402_CreateEveCorporationMemberMedals.php b/app/database/migrations/2014_04_02_171402_CreateEveCorporationMemberMedals.php new file mode 100644 index 00000000..f722367f --- /dev/null +++ b/app/database/migrations/2014_04_02_171402_CreateEveCorporationMemberMedals.php @@ -0,0 +1,44 @@ +increments('id'); + + $table->integer('corporationID'); + $table->integer('medalID'); + $table->integer('characterID'); + $table->string('reason'); + $table->string('status'); + $table->integer('issuerID'); + $table->dateTime('issued'); + + // Indexes + $table->index('corporationID'); + $table->index('medalID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('corporation_member_medals'); + } +} diff --git a/app/database/migrations/2014_04_03_051704_CreateEveCorporationMemberSecurityRoles.php b/app/database/migrations/2014_04_03_051704_CreateEveCorporationMemberSecurityRoles.php new file mode 100644 index 00000000..02543b99 --- /dev/null +++ b/app/database/migrations/2014_04_03_051704_CreateEveCorporationMemberSecurityRoles.php @@ -0,0 +1,45 @@ +increments('id'); + + $table->integer('characterID'); + $table->integer('corporationID'); + $table->string('name'); + + $table->bigInteger('roleID'); + $table->string('roleName'); + + // Indexes + $table->index('characterID'); + $table->index('corporationID'); + $table->index('roleID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_msec_roles'); + } + +} diff --git a/app/database/migrations/2014_04_03_051747_CreateEveCorporationMemberSecurityGrantableRoles.php b/app/database/migrations/2014_04_03_051747_CreateEveCorporationMemberSecurityGrantableRoles.php new file mode 100644 index 00000000..70e78b81 --- /dev/null +++ b/app/database/migrations/2014_04_03_051747_CreateEveCorporationMemberSecurityGrantableRoles.php @@ -0,0 +1,45 @@ +increments('id'); + + $table->integer('characterID'); + $table->integer('corporationID'); + $table->string('name'); + + $table->bigInteger('roleID'); + $table->string('roleName'); + + // Indexes + $table->index('characterID'); + $table->index('corporationID'); + $table->index('roleID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_msec_grantable_roles'); + } + +} diff --git a/app/database/migrations/2014_04_03_051814_CreateEveCorporationMemberSecurityRolesAtHQ.php b/app/database/migrations/2014_04_03_051814_CreateEveCorporationMemberSecurityRolesAtHQ.php new file mode 100644 index 00000000..1ca3e084 --- /dev/null +++ b/app/database/migrations/2014_04_03_051814_CreateEveCorporationMemberSecurityRolesAtHQ.php @@ -0,0 +1,45 @@ +increments('id'); + + $table->integer('characterID'); + $table->integer('corporationID'); + $table->string('name'); + + $table->bigInteger('roleID'); + $table->string('roleName'); + + // Indexes + $table->index('characterID'); + $table->index('corporationID'); + $table->index('roleID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_msec_roles_at_hq'); + } + +} diff --git a/app/database/migrations/2014_04_03_051844_CreateEveCorporationMemberSecurityGrantableRolesAtHQ.php b/app/database/migrations/2014_04_03_051844_CreateEveCorporationMemberSecurityGrantableRolesAtHQ.php new file mode 100644 index 00000000..9295891a --- /dev/null +++ b/app/database/migrations/2014_04_03_051844_CreateEveCorporationMemberSecurityGrantableRolesAtHQ.php @@ -0,0 +1,45 @@ +increments('id'); + + $table->integer('characterID'); + $table->integer('corporationID'); + $table->string('name'); + + $table->bigInteger('roleID'); + $table->string('roleName'); + + // Indexes + $table->index('characterID'); + $table->index('corporationID'); + $table->index('roleID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_msec_grantable_roles_at_hq'); + } + +} diff --git a/app/database/migrations/2014_04_03_051919_CreateEveCorporationMemberSecurityRolesAtBase.php b/app/database/migrations/2014_04_03_051919_CreateEveCorporationMemberSecurityRolesAtBase.php new file mode 100644 index 00000000..04ebce97 --- /dev/null +++ b/app/database/migrations/2014_04_03_051919_CreateEveCorporationMemberSecurityRolesAtBase.php @@ -0,0 +1,45 @@ +increments('id'); + + $table->integer('characterID'); + $table->integer('corporationID'); + $table->string('name'); + + $table->bigInteger('roleID'); + $table->string('roleName'); + + // Indexes + $table->index('characterID'); + $table->index('corporationID'); + $table->index('roleID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_msec_roles_at_base'); + } + +} diff --git a/app/database/migrations/2014_04_03_051947_CreateEveCorporationMemberSecurityGrantableRolesAtBase.php b/app/database/migrations/2014_04_03_051947_CreateEveCorporationMemberSecurityGrantableRolesAtBase.php new file mode 100644 index 00000000..e4d359b9 --- /dev/null +++ b/app/database/migrations/2014_04_03_051947_CreateEveCorporationMemberSecurityGrantableRolesAtBase.php @@ -0,0 +1,45 @@ +increments('id'); + + $table->integer('characterID'); + $table->integer('corporationID'); + $table->string('name'); + + $table->bigInteger('roleID'); + $table->string('roleName'); + + // Indexes + $table->index('characterID'); + $table->index('corporationID'); + $table->index('roleID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_msec_grantable_roles_at_base'); + } + +} diff --git a/app/database/migrations/2014_04_03_052029_CreateEveCorporationMemberSecurityRolesAtOther.php b/app/database/migrations/2014_04_03_052029_CreateEveCorporationMemberSecurityRolesAtOther.php new file mode 100644 index 00000000..8d2b0ef4 --- /dev/null +++ b/app/database/migrations/2014_04_03_052029_CreateEveCorporationMemberSecurityRolesAtOther.php @@ -0,0 +1,45 @@ +increments('id'); + + $table->integer('characterID'); + $table->integer('corporationID'); + $table->string('name'); + + $table->bigInteger('roleID'); + $table->string('roleName'); + + // Indexes + $table->index('characterID'); + $table->index('corporationID'); + $table->index('roleID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_msec_roles_at_other'); + } + +} diff --git a/app/database/migrations/2014_04_03_052049_CreateEveCorporationMemberSecurityGrantableRolesAtOther.php b/app/database/migrations/2014_04_03_052049_CreateEveCorporationMemberSecurityGrantableRolesAtOther.php new file mode 100644 index 00000000..15396f60 --- /dev/null +++ b/app/database/migrations/2014_04_03_052049_CreateEveCorporationMemberSecurityGrantableRolesAtOther.php @@ -0,0 +1,45 @@ +increments('id'); + + $table->integer('characterID'); + $table->integer('corporationID'); + $table->string('name'); + + $table->bigInteger('roleID'); + $table->string('roleName'); + + // Indexes + $table->index('characterID'); + $table->index('corporationID'); + $table->index('roleID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_msec_grantable_roles_at_other'); + } + +} diff --git a/app/database/migrations/2014_04_03_052111_CreateEveCorporationMemberSecurityTitles.php b/app/database/migrations/2014_04_03_052111_CreateEveCorporationMemberSecurityTitles.php new file mode 100644 index 00000000..eb9da224 --- /dev/null +++ b/app/database/migrations/2014_04_03_052111_CreateEveCorporationMemberSecurityTitles.php @@ -0,0 +1,45 @@ +increments('id'); + + $table->integer('characterID'); + $table->integer('corporationID'); + $table->string('name'); + + $table->bigInteger('titleID'); + $table->string('titleName'); + + // Indexes + $table->index('characterID'); + $table->index('corporationID'); + $table->index('titleID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_msec_titles'); + } + +} diff --git a/app/database/migrations/2014_04_03_071610_CreateEveCorporationMemberSecurityLog.php b/app/database/migrations/2014_04_03_071610_CreateEveCorporationMemberSecurityLog.php new file mode 100644 index 00000000..8b871f5e --- /dev/null +++ b/app/database/migrations/2014_04_03_071610_CreateEveCorporationMemberSecurityLog.php @@ -0,0 +1,50 @@ +increments('id'); + + $table->integer('corporationID'); + $table->integer('characterID'); + + $table->string('characterName'); + $table->dateTime('changeTime'); + $table->integer('issuerID'); + $table->string('issuerName'); + $table->string('roleLocationType'); + + $table->string('hash')->unique(); + + // Indexes + $table->index('characterID'); + $table->index('corporationID'); + $table->index('hash'); + + $table->timestamps(); + }); + } + + // changeTime,characterID,issuerID,roleLocationType + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_msec_log'); + } + +} diff --git a/app/database/migrations/2014_04_03_071638_CreateEveCorporationMemberSecurityLogDetails.php b/app/database/migrations/2014_04_03_071638_CreateEveCorporationMemberSecurityLogDetails.php new file mode 100644 index 00000000..641cdf0f --- /dev/null +++ b/app/database/migrations/2014_04_03_071638_CreateEveCorporationMemberSecurityLogDetails.php @@ -0,0 +1,40 @@ +increments('id'); + + $table->string('hash'); + $table->text('oldRoles'); + $table->text('newRoles'); + + // Indexes + $table->index('hash'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_msec_log_details'); + } + +} diff --git a/app/database/migrations/2014_04_03_083203_CreateEveCorporationMemberTracking.php b/app/database/migrations/2014_04_03_083203_CreateEveCorporationMemberTracking.php new file mode 100644 index 00000000..b7a9823c --- /dev/null +++ b/app/database/migrations/2014_04_03_083203_CreateEveCorporationMemberTracking.php @@ -0,0 +1,53 @@ +increments('id'); + + $table->integer('corporationID'); + $table->integer('characterID'); + $table->string('name'); + $table->dateTime('startDateTime'); + $table->bigInteger('baseID'); + $table->string('base'); + $table->string('title'); + $table->dateTime('logonDateTime'); + $table->dateTime('logoffDateTime'); + $table->integer('locationID'); + $table->string('location'); + $table->integer('shipTypeID'); + $table->string('shipType'); + $table->string('roles'); + $table->string('grantableRoles'); + + // Indexes + $table->index('characterID'); + $table->index('corporationID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_member_tracking'); + } + +} diff --git a/app/database/migrations/2014_04_03_084907_CreateEveCorporationShareholderCharacters.php b/app/database/migrations/2014_04_03_084907_CreateEveCorporationShareholderCharacters.php new file mode 100644 index 00000000..b9220ca3 --- /dev/null +++ b/app/database/migrations/2014_04_03_084907_CreateEveCorporationShareholderCharacters.php @@ -0,0 +1,44 @@ +increments('id'); + + $table->integer('corporationID'); + $table->integer('shareholderID'); + $table->string('shareholderName'); + $table->integer('shareholderCorporationID'); + $table->string('shareholderCorporationName'); + $table->integer('shares'); + + // Indexes + $table->index('shareholderID'); + $table->index('corporationID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_shareholder_characters'); + } + +} diff --git a/app/database/migrations/2014_04_03_085050_CreateEveCorporationShareholderCorporations.php b/app/database/migrations/2014_04_03_085050_CreateEveCorporationShareholderCorporations.php new file mode 100644 index 00000000..bf4a44eb --- /dev/null +++ b/app/database/migrations/2014_04_03_085050_CreateEveCorporationShareholderCorporations.php @@ -0,0 +1,42 @@ +increments('id'); + + $table->integer('corporationID'); + $table->integer('shareholderID'); + $table->string('shareholderName'); + $table->integer('shares'); + + // Indexes + $table->index('shareholderID'); + $table->index('corporationID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_shareholder_corporations'); + } + +} diff --git a/app/database/migrations/2014_04_03_095308_CreateEveCorporationStandingsAgents.php b/app/database/migrations/2014_04_03_095308_CreateEveCorporationStandingsAgents.php new file mode 100644 index 00000000..4facabc5 --- /dev/null +++ b/app/database/migrations/2014_04_03_095308_CreateEveCorporationStandingsAgents.php @@ -0,0 +1,42 @@ +increments('id'); + + $table->integer('corporationID'); + + $table->integer('fromID'); + $table->string('fromName'); + $table->float('standing'); + + // Indexes + $table->index('corporationID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_standings_agents'); + } + +} diff --git a/app/database/migrations/2014_04_03_095335_CreateEveCorporationStandingsNPCCorporations.php b/app/database/migrations/2014_04_03_095335_CreateEveCorporationStandingsNPCCorporations.php new file mode 100644 index 00000000..27684426 --- /dev/null +++ b/app/database/migrations/2014_04_03_095335_CreateEveCorporationStandingsNPCCorporations.php @@ -0,0 +1,42 @@ +increments('id'); + + $table->integer('corporationID'); + + $table->integer('fromID'); + $table->string('fromName'); + $table->float('standing'); + + // Indexes + $table->index('corporationID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_standings_npccorporations'); + } + +} diff --git a/app/database/migrations/2014_04_03_095406_CreateEveCorporationStandingsFactions.php b/app/database/migrations/2014_04_03_095406_CreateEveCorporationStandingsFactions.php new file mode 100644 index 00000000..2c802b8a --- /dev/null +++ b/app/database/migrations/2014_04_03_095406_CreateEveCorporationStandingsFactions.php @@ -0,0 +1,42 @@ +increments('id'); + + $table->integer('corporationID'); + + $table->integer('fromID'); + $table->string('fromName'); + $table->float('standing'); + + // Indexes + $table->index('corporationID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_standings_factions'); + } + +} diff --git a/app/database/migrations/2014_04_03_110700_CreateEveCorporationStarbaseList.php b/app/database/migrations/2014_04_03_110700_CreateEveCorporationStarbaseList.php new file mode 100644 index 00000000..efdb754f --- /dev/null +++ b/app/database/migrations/2014_04_03_110700_CreateEveCorporationStarbaseList.php @@ -0,0 +1,48 @@ +increments('id'); + + $table->integer('corporationID'); + + $table->bigInteger('itemID')->unique(); + $table->integer('typeID'); + $table->bigInteger('locationID'); + $table->bigInteger('moonID'); + $table->integer('state'); + $table->dateTime('stateTimestamp'); + $table->dateTime('onlineTimestamp'); + $table->bigInteger('standingOwnerID'); + + // Indexes + $table->index('corporationID'); + $table->index('itemID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_starbaselist'); + } + +} diff --git a/app/database/migrations/2014_04_03_114920_CreateEveCorporationStarbaseDetail.php b/app/database/migrations/2014_04_03_114920_CreateEveCorporationStarbaseDetail.php new file mode 100644 index 00000000..2e3a1055 --- /dev/null +++ b/app/database/migrations/2014_04_03_114920_CreateEveCorporationStarbaseDetail.php @@ -0,0 +1,56 @@ +increments('id'); + + $table->integer('corporationID'); + + $table->bigInteger('itemID')->unique(); + $table->integer('state'); + $table->dateTime('stateTimestamp'); + $table->dateTime('onlineTimestamp'); + $table->integer('usageFlags'); + $table->integer('deployFlags'); + $table->integer('allowCorporationMembers'); + $table->integer('allowAllianceMembers'); + $table->integer('useStandingsFrom'); + $table->integer('onStandingDrop'); + $table->integer('onStatusDropEnabled'); + $table->integer('onStatusDropStanding'); + $table->integer('onAggression'); + $table->integer('onCorporationWar'); + $table->integer('fuelBlocks')->default(0); + $table->integer('strontium')->default(0); + + // Indexes + $table->index('corporationID'); + $table->index('itemID'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_starbasedetail'); + } + +} diff --git a/app/database/migrations/2014_04_03_155021_CreateEveCorporationWalletJournal.php b/app/database/migrations/2014_04_03_155021_CreateEveCorporationWalletJournal.php new file mode 100644 index 00000000..2b6e00e4 --- /dev/null +++ b/app/database/migrations/2014_04_03_155021_CreateEveCorporationWalletJournal.php @@ -0,0 +1,60 @@ +increments('id'); + + $table->integer('corporationID'); + + // Hash for transaction uniqueness as it appears that + // refID's may cycle... + $table->string('hash')->unique(); + + $table->integer('accountKey'); + $table->bigInteger('refID'); + $table->dateTime('date'); + $table->integer('refTypeID'); + $table->string('ownerName1'); + $table->integer('ownerID1'); + $table->string('ownerName2'); + $table->integer('ownerID2'); + $table->string('argName1'); + $table->integer('argID1'); + $table->decimal('amount', 22,2); + $table->decimal('balance', 22,2); + $table->string('reason'); + $table->integer('owner1TypeID'); + $table->integer('owner2TypeID'); + + // Indexes + $table->index('corporationID'); + $table->index('refID'); + $table->index('accountKey'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_walletjournal'); + } + +} diff --git a/app/database/migrations/2014_04_03_160954_CreateEveCorporationWalletTransactions.php b/app/database/migrations/2014_04_03_160954_CreateEveCorporationWalletTransactions.php new file mode 100644 index 00000000..a9f95a5b --- /dev/null +++ b/app/database/migrations/2014_04_03_160954_CreateEveCorporationWalletTransactions.php @@ -0,0 +1,60 @@ +increments('id'); + + $table->integer('corporationID'); + + // Hash for transaction uniqueness as it appears that + // refID's may cycle... + $table->string('hash')->unique(); + + $table->integer('accountKey'); + $table->bigInteger('transactionID'); + $table->dateTime('transactionDateTime'); + $table->integer('quantity'); + $table->string('typeName'); + $table->integer('typeID'); + $table->decimal('price', 22,2); + $table->integer('clientID'); + $table->string('clientName'); + $table->integer('stationID'); + $table->string('stationName'); + $table->enum('transactionType', array('buy','sell')); + $table->enum('transactionFor', array('personal','corporation')); + $table->bigInteger('journalTransactionID'); + $table->integer('clientTypeID'); + + // Indexes + $table->index('corporationID'); + $table->index('transactionID'); + $table->index('accountKey'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_wallettransactions'); + } + +} diff --git a/app/database/migrations/2014_04_04_080921_CreateEveCorporationAssetListLocationsAddMapData.php b/app/database/migrations/2014_04_04_080921_CreateEveCorporationAssetListLocationsAddMapData.php new file mode 100644 index 00000000..efe198e3 --- /dev/null +++ b/app/database/migrations/2014_04_04_080921_CreateEveCorporationAssetListLocationsAddMapData.php @@ -0,0 +1,36 @@ +integer('mapID')->nullable()->default(null); + $table->string('mapName')->nullable()->default(null); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('corporation_assetlist_locations', function($table) + { + $table->dropColumn('mapID'); + $table->dropColumn('mapName'); + }); + } + +} diff --git a/app/database/migrations/2014_04_04_113830_create_password_reminders_table.php b/app/database/migrations/2014_04_04_113830_create_password_reminders_table.php new file mode 100644 index 00000000..68a06749 --- /dev/null +++ b/app/database/migrations/2014_04_04_113830_create_password_reminders_table.php @@ -0,0 +1,33 @@ +string('email')->index(); + $table->string('token')->index(); + $table->timestamp('created_at'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('password_reminders'); + } + +} \ No newline at end of file diff --git a/app/database/seeds/.gitkeep b/app/database/seeds/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/app/database/seeds/DatabaseSeeder.php b/app/database/seeds/DatabaseSeeder.php new file mode 100644 index 00000000..c6840893 --- /dev/null +++ b/app/database/seeds/DatabaseSeeder.php @@ -0,0 +1,18 @@ +call('UserTableSeeder'); + $this->call('EveApiCalllistTableSeeder'); + $this->call('EveNotificationTypesSeeder'); + } +} \ No newline at end of file diff --git a/app/database/seeds/EveApiCalllistTableSeeder.php b/app/database/seeds/EveApiCalllistTableSeeder.php new file mode 100644 index 00000000..f51622ea --- /dev/null +++ b/app/database/seeds/EveApiCalllistTableSeeder.php @@ -0,0 +1,67 @@ +delete(); + + // Eve Api Callist from https://api.eveonline.com/api/calllist.xml.aspx + // Taken Sat, 22 Mar 2014 06:47:37 +0000 + EveApiCalllist::create(array('type' => 'Character', 'name' => 'Locations', 'accessMask' => 134217728, 'description' => 'Allows the fetching of coordinate and name data for items owned by the character.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'Contracts', 'accessMask' => 67108864, 'description' => 'List of all Contracts the character is involved in.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'AccountStatus', 'accessMask' => 33554432, 'description' => 'EVE player account status.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'CharacterInfo', 'accessMask' => 16777216, 'description' => 'Sensitive Character Information, exposes account balance and last known location on top of the other Character Information call.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'CharacterInfo', 'accessMask' => 8388608, 'description' => 'Character information, exposes skill points and current ship information on top of \'Show Info\' information.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'WalletTransactions', 'accessMask' => 4194304, 'description' => 'Market transaction journal of character.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'WalletJournal', 'accessMask' => 2097152, 'description' => 'Wallet journal of character.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'UpcomingCalendarEvents', 'accessMask' => 1048576, 'description' => 'Upcoming events on characters calendar.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'Standings', 'accessMask' => 524288, 'description' => 'NPC Standings towards the character.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'SkillQueue', 'accessMask' => 262144, 'description' => 'Entire skill queue of character.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'SkillInTraining', 'accessMask' => 131072, 'description' => 'Skill currently in training on the character. Subset of entire Skill Queue.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'Research', 'accessMask' => 65536, 'description' => 'List of all Research agents working for the character and the progress of the research.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'NotificationTexts', 'accessMask' => 32768, 'description' => 'Actual body of notifications sent to the character. Requires Notification access to function.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'Notifications', 'accessMask' => 16384, 'description' => 'List of recent notifications sent to the character.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'Medals', 'accessMask' => 8192, 'description' => 'Medals awarded to the character.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'MarketOrders', 'accessMask' => 4096, 'description' => 'List of all Market Orders the character has made.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'MailMessages', 'accessMask' => 2048, 'description' => 'List of all messages in the characters EVE Mail Inbox.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'MailingLists', 'accessMask' => 1024, 'description' => 'List of all Mailing Lists the character subscribes to.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'MailBodies', 'accessMask' => 512, 'description' => 'EVE Mail bodies. Requires MailMessages as well to function.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'KillLog', 'accessMask' => 256, 'description' => 'Characters kill log.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'IndustryJobs', 'accessMask' => 128, 'description' => 'Character jobs, completed and active.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'FacWarStats', 'accessMask' => 64, 'description' => 'Characters Factional Warfare Statistics.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'ContactNotifications', 'accessMask' => 32, 'description' => 'Most recent contact notifications for the character.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'ContactList', 'accessMask' => 16, 'description' => 'List of character contacts and relationship levels.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'CharacterSheet', 'accessMask' => 8, 'description' => 'Character Sheet information. Contains basic \'Show Info\' information along with clones, account balance, implants, attributes, skills, certificates and corporation roles.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'CalendarEventAttendees', 'accessMask' => 4, 'description' => 'Event attendee responses. Requires UpcomingCalendarEvents to function.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'AssetList', 'accessMask' => 2, 'description' => 'Entire asset list of character.')); + EveApiCalllist::create(array('type' => 'Character', 'name' => 'AccountBalance', 'accessMask' => 1, 'description' => 'Current balance of characters wallet.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'MemberTrackingExtended', 'accessMask' => 33554432, 'description' => 'Extensive Member information. Time of last logoff, last known location and ship.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'Locations', 'accessMask' => 16777216, 'description' => 'Allows the fetching of coordinate and name data for items owned by the corporation.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'Contracts', 'accessMask' => 8388608, 'description' => 'List of recent Contracts the corporation is involved in.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'Titles', 'accessMask' => 4194304, 'description' => 'Titles of corporation and the roles they grant.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'WalletTransactions', 'accessMask' => 2097152, 'description' => 'Market transactions of all corporate accounts.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'WalletJournal', 'accessMask' => 1048576, 'description' => 'Wallet journal for all corporate accounts.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'StarbaseList', 'accessMask' => 524288, 'description' => 'List of all corporate starbases.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'Standings', 'accessMask' => 262144, 'description' => 'NPC Standings towards corporation.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'StarbaseDetail', 'accessMask' => 131072, 'description' => 'List of all settings of corporate starbases.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'Shareholders', 'accessMask' => 65536, 'description' => 'Shareholders of the corporation.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'OutpostServiceDetail', 'accessMask' => 32768, 'description' => 'List of all service settings of corporate outposts.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'OutpostList', 'accessMask' => 16384, 'description' => 'List of all outposts controlled by the corporation.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'Medals', 'accessMask' => 8192, 'description' => 'List of all medals created by the corporation.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'MarketOrders', 'accessMask' => 4096, 'description' => 'List of all corporate market orders.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'MemberTrackingLimited', 'accessMask' => 2048, 'description' => 'Limited Member information.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'MemberSecurityLog', 'accessMask' => 1024, 'description' => 'Member role and title change log.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'MemberSecurity', 'accessMask' => 512, 'description' => 'Member roles and titles.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'KillLog', 'accessMask' => 256, 'description' => 'Corporation kill log.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'IndustryJobs', 'accessMask' => 128, 'description' => 'Corporation jobs, completed and active.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'FacWarStats', 'accessMask' => 64, 'description' => 'Corporations Factional Warfare Statistics.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'ContainerLog', 'accessMask' => 32, 'description' => 'Corporate secure container acess log.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'ContactList', 'accessMask' => 16, 'description' => 'Corporate contact list and relationships.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'CorporationSheet', 'accessMask' => 8, 'description' => 'Exposes basic \'Show Info\' information as well as Member Limit and basic division and wallet info.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'MemberMedals', 'accessMask' => 4, 'description' => 'List of medals awarded to corporation members.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'AssetList', 'accessMask' => 2, 'description' => 'List of all corporation assets.')); + EveApiCalllist::create(array('type' => 'Corporation', 'name' => 'AccountBalance', 'accessMask' => 1, 'description' => 'Current balance of all corporation accounts.')); + } + +} diff --git a/app/database/seeds/EveNotificationTypesSeeder.php b/app/database/seeds/EveNotificationTypesSeeder.php new file mode 100644 index 00000000..e8906e9f --- /dev/null +++ b/app/database/seeds/EveNotificationTypesSeeder.php @@ -0,0 +1,141 @@ +delete(); + + EveEveNotificationTypes::create(array("typeID" => "1", "description" => "Legacy")); + EveEveNotificationTypes::create(array("typeID" => "2", "description" => "Character deleted")); + EveEveNotificationTypes::create(array("typeID" => "3", "description" => "Give medal to character")); + EveEveNotificationTypes::create(array("typeID" => "4", "description" => "Alliance maintenance bill")); + EveEveNotificationTypes::create(array("typeID" => "5", "description" => "Alliance war declared")); + EveEveNotificationTypes::create(array("typeID" => "6", "description" => "Alliance war surrender")); + EveEveNotificationTypes::create(array("typeID" => "7", "description" => "Alliance war retracted")); + EveEveNotificationTypes::create(array("typeID" => "8", "description" => "Alliance war invalidated by Concord")); + EveEveNotificationTypes::create(array("typeID" => "9", "description" => "Bill issued to a character")); + EveEveNotificationTypes::create(array("typeID" => "10", "description" => "Bill issued to corporation or alliance")); + EveEveNotificationTypes::create(array("typeID" => "11", "description" => "Bill not paid because there's not enough ISK available")); + EveEveNotificationTypes::create(array("typeID" => "12", "description" => "Bill")); + EveEveNotificationTypes::create(array("typeID" => "13", "description" => "Bill")); + EveEveNotificationTypes::create(array("typeID" => "14", "description" => "Bounty claimed")); + EveEveNotificationTypes::create(array("typeID" => "15", "description" => "Clone activated")); + EveEveNotificationTypes::create(array("typeID" => "16", "description" => "New corp member application")); + EveEveNotificationTypes::create(array("typeID" => "17", "description" => "Corp application rejected")); + EveEveNotificationTypes::create(array("typeID" => "18", "description" => "Corp application accepted")); + EveEveNotificationTypes::create(array("typeID" => "19", "description" => "Corp tax rate changed")); + EveEveNotificationTypes::create(array("typeID" => "20", "description" => "Corp news report")); + EveEveNotificationTypes::create(array("typeID" => "21", "description" => "Player leaves corp")); + EveEveNotificationTypes::create(array("typeID" => "22", "description" => "Corp news")); + EveEveNotificationTypes::create(array("typeID" => "23", "description" => "Corp dividend/liquidation")); + EveEveNotificationTypes::create(array("typeID" => "24", "description" => "Corp dividend payout")); + EveEveNotificationTypes::create(array("typeID" => "25", "description" => "Corp vote created")); + EveEveNotificationTypes::create(array("typeID" => "26", "description" => "Corp CEO votes revoked during voting")); + EveEveNotificationTypes::create(array("typeID" => "27", "description" => "Corp declares war")); + EveEveNotificationTypes::create(array("typeID" => "28", "description" => "Corp war has started")); + EveEveNotificationTypes::create(array("typeID" => "29", "description" => "Corp surrenders war")); + EveEveNotificationTypes::create(array("typeID" => "30", "description" => "Corp retracts war")); + EveEveNotificationTypes::create(array("typeID" => "31", "description" => "Corp war invalidated by Concord")); + EveEveNotificationTypes::create(array("typeID" => "32", "description" => "Container password retrieval")); + EveEveNotificationTypes::create(array("typeID" => "33", "description" => "Contraband or low standings cause an attack or items being confiscated")); + EveEveNotificationTypes::create(array("typeID" => "34", "description" => "First ship insurance")); + EveEveNotificationTypes::create(array("typeID" => "35", "description" => "Ship destroyed")); + EveEveNotificationTypes::create(array("typeID" => "36", "description" => "Insurance contract invalidated/runs out")); + EveEveNotificationTypes::create(array("typeID" => "37", "description" => "Sovereignty claim fails (alliance)")); + EveEveNotificationTypes::create(array("typeID" => "38", "description" => "Sovereignty claim fails (corporation)")); + EveEveNotificationTypes::create(array("typeID" => "39", "description" => "Sovereignty bill late (alliance)")); + EveEveNotificationTypes::create(array("typeID" => "40", "description" => "Sovereignty bill late (corporation)")); + EveEveNotificationTypes::create(array("typeID" => "41", "description" => "Sovereignty claim lost (alliance)")); + EveEveNotificationTypes::create(array("typeID" => "42", "description" => "Sovereignty claim lost (corporation)")); + EveEveNotificationTypes::create(array("typeID" => "43", "description" => "Sovereignty claim acquired (alliance)")); + EveEveNotificationTypes::create(array("typeID" => "44", "description" => "Sovereignty claim acquired (corporation)")); + EveEveNotificationTypes::create(array("typeID" => "45", "description" => "Alliance anchoring alert")); + EveEveNotificationTypes::create(array("typeID" => "46", "description" => "Alliance structure turns vulnerable")); + EveEveNotificationTypes::create(array("typeID" => "47", "description" => "Alliance structure turns invulnerable")); + EveEveNotificationTypes::create(array("typeID" => "48", "description" => "Sovereignty disruptor anchored")); + EveEveNotificationTypes::create(array("typeID" => "49", "description" => "Structure won/lost")); + EveEveNotificationTypes::create(array("typeID" => "50", "description" => "Corp office lease expiration notice")); + EveEveNotificationTypes::create(array("typeID" => "51", "description" => "Clone contract revoked by station manager")); + EveEveNotificationTypes::create(array("typeID" => "52", "description" => "Corp member clones moved between stations")); + EveEveNotificationTypes::create(array("typeID" => "53", "description" => "Clone contract revoked by station manager")); + EveEveNotificationTypes::create(array("typeID" => "54", "description" => "Insurance contract expired")); + EveEveNotificationTypes::create(array("typeID" => "55", "description" => "Insurance contract issued")); + EveEveNotificationTypes::create(array("typeID" => "56", "description" => "Jump clone destroyed")); + EveEveNotificationTypes::create(array("typeID" => "57", "description" => "Jump clone destroyed")); + EveEveNotificationTypes::create(array("typeID" => "58", "description" => "Corporation joining factional warfare")); + EveEveNotificationTypes::create(array("typeID" => "59", "description" => "Corporation leaving factional warfare")); + EveEveNotificationTypes::create(array("typeID" => "60", "description" => "Corporation kicked from factional warfare on startup because of too low standing to the faction")); + EveEveNotificationTypes::create(array("typeID" => "61", "description" => "Character kicked from factional warfare on startup because of too low standing to the faction")); + EveEveNotificationTypes::create(array("typeID" => "62", "description" => "Corporation in factional warfare warned on startup because of too low standing to the faction")); + EveEveNotificationTypes::create(array("typeID" => "63", "description" => "Character in factional warfare warned on startup because of too low standing to the faction")); + EveEveNotificationTypes::create(array("typeID" => "64", "description" => "Character loses factional warfare rank")); + EveEveNotificationTypes::create(array("typeID" => "65", "description" => "Character gains factional warfare rank")); + EveEveNotificationTypes::create(array("typeID" => "66", "description" => "Agent has moved")); + EveEveNotificationTypes::create(array("typeID" => "67", "description" => "Mass transaction reversal message")); + EveEveNotificationTypes::create(array("typeID" => "68", "description" => "Reimbursement message")); + EveEveNotificationTypes::create(array("typeID" => "69", "description" => "Agent locates a character")); + EveEveNotificationTypes::create(array("typeID" => "70", "description" => "Research mission becomes available from an agent")); + EveEveNotificationTypes::create(array("typeID" => "71", "description" => "Agent mission offer expires")); + EveEveNotificationTypes::create(array("typeID" => "72", "description" => "Agent mission times out")); + EveEveNotificationTypes::create(array("typeID" => "73", "description" => "Agent offers a storyline mission")); + EveEveNotificationTypes::create(array("typeID" => "74", "description" => "Tutorial message sent on character creation")); + EveEveNotificationTypes::create(array("typeID" => "75", "description" => "Tower alert")); + EveEveNotificationTypes::create(array("typeID" => "76", "description" => "Tower resource alert")); + EveEveNotificationTypes::create(array("typeID" => "77", "description" => "Station service aggression message")); + EveEveNotificationTypes::create(array("typeID" => "78", "description" => "Station state change message")); + EveEveNotificationTypes::create(array("typeID" => "79", "description" => "Station conquered message")); + EveEveNotificationTypes::create(array("typeID" => "80", "description" => "Station aggression message")); + EveEveNotificationTypes::create(array("typeID" => "81", "description" => "Corporation requests joining factional warfare")); + EveEveNotificationTypes::create(array("typeID" => "82", "description" => "Corporation requests leaving factional warfare")); + EveEveNotificationTypes::create(array("typeID" => "83", "description" => "Corporation withdrawing a request to join factional warfare")); + EveEveNotificationTypes::create(array("typeID" => "84", "description" => "Corporation withdrawing a request to leave factional warfare")); + EveEveNotificationTypes::create(array("typeID" => "85", "description" => "Corporation liquidation")); + EveEveNotificationTypes::create(array("typeID" => "86", "description" => "Territorial Claim Unit under attack")); + EveEveNotificationTypes::create(array("typeID" => "87", "description" => "Sovereignty Blockade Unit under attack")); + EveEveNotificationTypes::create(array("typeID" => "88", "description" => "Infrastructure Hub under attack")); + EveEveNotificationTypes::create(array("typeID" => "89", "description" => "Contact add notification")); + EveEveNotificationTypes::create(array("typeID" => "90", "description" => "Contact edit notification")); + EveEveNotificationTypes::create(array("typeID" => "91", "description" => "Incursion Completed")); + EveEveNotificationTypes::create(array("typeID" => "92", "description" => "Corp Kicked")); + EveEveNotificationTypes::create(array("typeID" => "93", "description" => "Customs office has been attacked")); + EveEveNotificationTypes::create(array("typeID" => "94", "description" => "Customs office has entered reinforced")); + EveEveNotificationTypes::create(array("typeID" => "95", "description" => "Customs office has been transferred")); + EveEveNotificationTypes::create(array("typeID" => "96", "description" => "FW Alliance Warning")); + EveEveNotificationTypes::create(array("typeID" => "97", "description" => "FW Alliance Kick")); + EveEveNotificationTypes::create(array("typeID" => "98", "description" => "AllWarCorpJoined Msg")); + EveEveNotificationTypes::create(array("typeID" => "99", "description" => "Ally Joined Defender")); + EveEveNotificationTypes::create(array("typeID" => "100", "description" => "Ally Has Joined a War Aggressor")); + EveEveNotificationTypes::create(array("typeID" => "101", "description" => "Ally Joined War Ally")); + EveEveNotificationTypes::create(array("typeID" => "102", "description" => "New war system: entity is offering assistance in a war.")); + EveEveNotificationTypes::create(array("typeID" => "103", "description" => "War Surrender Offer")); + EveEveNotificationTypes::create(array("typeID" => "104", "description" => "War Surrender Declined")); + EveEveNotificationTypes::create(array("typeID" => "105", "description" => "FacWar LP Payout Kill")); + EveEveNotificationTypes::create(array("typeID" => "106", "description" => "FacWar LP Payout Event")); + EveEveNotificationTypes::create(array("typeID" => "107", "description" => "FacWar LP Disqualified Eventd")); + EveEveNotificationTypes::create(array("typeID" => "108", "description" => "FacWar LP Disqualified Kill")); + EveEveNotificationTypes::create(array("typeID" => "109", "description" => "Alliance Contract Cancelled")); + EveEveNotificationTypes::create(array("typeID" => "110", "description" => "War Ally Declined Offer")); + EveEveNotificationTypes::create(array("typeID" => "111", "description" => "Your Bounty Claimed")); + EveEveNotificationTypes::create(array("typeID" => "112", "description" => "Bounty Placed (Char)")); + EveEveNotificationTypes::create(array("typeID" => "113", "description" => "Bounty Placed (Corp)")); + EveEveNotificationTypes::create(array("typeID" => "114", "description" => "Bounty Placed (Alliance)")); + EveEveNotificationTypes::create(array("typeID" => "115", "description" => "Kill Right Available")); + EveEveNotificationTypes::create(array("typeID" => "116", "description" => "Kill Right Available Open")); + EveEveNotificationTypes::create(array("typeID" => "117", "description" => "Kill Right Earned")); + EveEveNotificationTypes::create(array("typeID" => "118", "description" => "Kill Right Used")); + EveEveNotificationTypes::create(array("typeID" => "119", "description" => "Kill Right Unavailable")); + EveEveNotificationTypes::create(array("typeID" => "120", "description" => "Kill Right Unavailable Open")); + EveEveNotificationTypes::create(array("typeID" => "121", "description" => "Declare War")); + EveEveNotificationTypes::create(array("typeID" => "122", "description" => "Offered Surrender")); + EveEveNotificationTypes::create(array("typeID" => "123", "description" => "Accepted Surrender")); + EveEveNotificationTypes::create(array("typeID" => "124", "description" => "Made War Mutual")); + EveEveNotificationTypes::create(array("typeID" => "125", "description" => "Retracts War")); + EveEveNotificationTypes::create(array("typeID" => "126", "description" => "Offered To Ally")); + EveEveNotificationTypes::create(array("typeID" => "127", "description" => "Accepted Ally")); + EveEveNotificationTypes::create(array("typeID" => "128", "description" => "Character Application Accept Message")); + EveEveNotificationTypes::create(array("typeID" => "129", "description" => "Character Application Reject Message")); + EveEveNotificationTypes::create(array("typeID" => "130", "description" => "Character Application Withdraw Message")); + } + +} diff --git a/app/database/seeds/UserTableSeeder.php b/app/database/seeds/UserTableSeeder.php new file mode 100644 index 00000000..2c91e224 --- /dev/null +++ b/app/database/seeds/UserTableSeeder.php @@ -0,0 +1,16 @@ +delete(); + + User::create(array( + 'email' => 'foo@bar.com', + 'username' => 'admin', + 'password' => Hash::make('seat!admin') + )); + } + +} \ No newline at end of file diff --git a/app/eveapi/Api.php b/app/eveapi/Api.php new file mode 100644 index 00000000..65402b36 --- /dev/null +++ b/app/eveapi/Api.php @@ -0,0 +1,20 @@ +apiScope->calllist(); + + return $calllist; + } +} diff --git a/app/eveapi/BaseAPI.php b/app/eveapi/BaseAPI.php new file mode 100644 index 00000000..0c0cfb18 --- /dev/null +++ b/app/eveapi/BaseAPI.php @@ -0,0 +1,431 @@ +cache = new \Pheal\Cache\FileStorage( storage_path(). '/cache/phealcache/' ); + PhealConfig::getInstance()->access = new \Pheal\Access\StaticCheck(); + PhealConfig::getInstance()->log = new \Pheal\Log\FileStorage( storage_path() . '/logs/' ); + PhealConfig::getInstance()->http_user_agent = 'SeAT ' . \Config::get('seat.version') . 'API Fetcher'; + PhealConfig::getInstance()->api_customkeys = true; + PhealConfig::getInstance()->http_method = 'curl'; + } + + /* + |-------------------------------------------------------------------------- + | validateKeyPair() + |-------------------------------------------------------------------------- + | + | Check that a give keyID & vCode is valid + | + */ + + public static function validateKeyPair($keyID, $vCode) + { + if (!is_numeric($keyID)) + throw new \Exception('A API keyID must be a integer, we got: ' . $keyID); + + if (strlen($vCode) <> 64) + throw new \Exception('A vCode should be 64 chars long, we got: ' . $vCode); + } + + /* + |-------------------------------------------------------------------------- + | makeCallHash() + |-------------------------------------------------------------------------- + | + | Generate a MD5 hash based on the 3 received arguements for caching related + | information in the database. + | + */ + + public static function makeCallHash($api, $scope, $owner) + { + return md5(implode(',', array($api, $scope, $owner) )); + } + + /* + |-------------------------------------------------------------------------- + | disableKey() + |-------------------------------------------------------------------------- + | + | Sets the `isOk` field in the `seat_keys` table to 0, effectively marking the + | key as inactive. + | + */ + + public static function disableKey($keyID, $error = null) + { + $key = \SeatKey::where('keyID', '=', $keyID)->first(); + + if (!$key) + throw new Exception('Unable to find the entry in `seat_keys` to disable key: ' . $keyID); + + $key->isOk = 0; + $key->lastError = $error; + $key->save(); + } + + /* + |-------------------------------------------------------------------------- + | banCall() + |-------------------------------------------------------------------------- + | + | Records a API call as banned together with the access mask. + | + */ + + public static function banCall($api, $scope, $owner = 0, $accessMask = 0, $reason = null) + { + + // Check if we should retreive the current access mask + if ($accessMask == 0) + $accessMask = \EveAccountAPIKeyInfo::where('keyID', '=', $owner)->pluck('accessMask'); + + // Generate a hash with which to ID this call + $hash = BaseApi::makeCallHash($api, $scope, $owner . $accessMask); + + // We will give each call 2 tries. After the 2nd attempt, we actually action the ban + $banned = \EveBannedCall::where('hash', '=', $hash)->first(); + + // Check if a entry exists for this key + if (!\Cache::has('call_blacklist_' . $hash)) { + + // Add the entry and return. + \Cache::forever('call_blacklist_' . $hash, 'blacklisted'); + return; + + } + + // We _should_ get here when the entire truth block above this fails, meaning a blacklisted entry was entered before + $banned = \EveBannedCall::where('hash', '=', $hash)->first(); + if (!$banned) + $banned = new \EveBannedCall; + + $banned->ownerID = $owner; + $banned->api = $api; + $banned->scope = $scope; + $banned->accessMask = $accessMask; + $banned->hash = $hash; + $banned->reason = $reason; + $banned->save(); + + // Log this ban + } + + /* + |-------------------------------------------------------------------------- + | isBannedCall() + |-------------------------------------------------------------------------- + | + | Checks if a API call is banned + | + */ + + public static function isBannedCall($api, $scope, $owner = 0, $accessMask = 0) + { + + // Check if we should retreive the current access mask + if ($accessMask == 0) + $accessMask = \EveAccountAPIKeyInfo::where('keyID', '=', $owner)->pluck('accessMask'); + + $hash = BaseApi::makeCallHash($api, $scope, $owner . $accessMask); + $banned = \EveBannedCall::where('hash', '=', $hash)->first(); + + if ($banned) + return true; + else + return false; + } + + /* + |-------------------------------------------------------------------------- + | checkDbCache() + |-------------------------------------------------------------------------- + | + | Check if the data in the database is considered up to data. + | Returns true if it is, false if it is not or there is no date recorded. + | + */ + + public static function checkDbCache($api, $scope, $cachedUntil, $owner = 0) + { + // Generate the hash based on the func args + $hash = BaseApi::makeCallHash($api, $scope, $owner); + $current_cache_time = $current_cache_time = \EveCachedUntil::where('hash', '=', $hash)->first(); + + // Check if we have a cache timer set. + if ($current_cache_time) { + + // If the timer is still the same as when we set it, return true + // Else, return false indicating its no longer up to date. + if ($current_cache_time->cached_until == $cachedUntil ) + return true; + else + return false; + + } else { + + // No cache timer means its not up to date and needs updatin + return false; + } + } + + /* + |-------------------------------------------------------------------------- + | setDbCache() + |-------------------------------------------------------------------------- + | + | Set the cached_until time for a api call. + | + */ + + public static function setDbCache($api, $scope, $cachedUntil, $owner = 0) + { + // Generate the hash based on the func args + $hash = BaseApi::makeCallHash($api, $scope, $owner); + $cache_time_exists = $current_cache_time = \EveCachedUntil::where('hash', '=', $hash)->first(); + + if ($current_cache_time) { + + $current_cache_time->cached_until = $cachedUntil; + $current_cache_time->save(); + } else { + + \EveCachedUntil::create(array( + 'ownerID' => $owner, + 'api' => $api, + 'scope' => $scope, + 'hash' => $hash, + 'cached_until' => $cachedUntil + )); + } + } + + /* + |-------------------------------------------------------------------------- + | lockCall() + |-------------------------------------------------------------------------- + | + | Set the cached_until time for a api call. + | + */ + + public static function lockCall($api, $scope, $owner = 0) + { + // Generate the hash based on the func args + $hash = BaseApi::makeCallHash($api, $scope, $owner); + + \Cache::put('api_lock_' . $hash, '_locked_', Carbon::now()->addMinutes(60)); + + // print 'Locked ' . $api . ' with hash ' . $hash; + + return $hash; + } + + /* + |-------------------------------------------------------------------------- + | isLockedCall() + |-------------------------------------------------------------------------- + | + | Check if a API call is locked + | + */ + + public static function isLockedCall($api, $scope, $owner = 0) + { + // Generate the hash based on the func args + $hash = BaseApi::makeCallHash($api, $scope, $owner); + + if (\Cache::has('api_lock_' . $hash)) { + // print 'Api ' . $api . ' is still locked'; + return true; + } + else { + return false; + } + } + + /* + |-------------------------------------------------------------------------- + | unlockCall() + |-------------------------------------------------------------------------- + | + | Unlocks a given api call via hash + | + */ + + public static function unlockCall($hash) + { + // print 'Unlocked ' . $hash; + \Cache::forget('api_lock_' . $hash); + } + + /* + |-------------------------------------------------------------------------- + | determineAccess() + |-------------------------------------------------------------------------- + | + | Return an array of valid API calls that are allowed for a recorded keyID + | + */ + + public static function determineAccess($keyID) + { + + // Locate the key in the db + $key = \SeatKey::where('keyID', '=', $keyID)->where('isOk', '=', 1)->first(); + + if (!$key) + return array(); + + // Attempt to get the type & accessMask from the database. + Account\APIKeyInfo::update($keyID, $key->vCode); + $key_mask_info = \EveAccountAPIKeyInfo::where('keyID', '=', $keyID)->first(); + + // TODO: Where to put this call???? + Account\AccountStatus::update($keyID, $key->vCode); + + // If we still can't determine mask information, leave everything + if (!$key_mask_info) + return array(); + + // Prepare a return by setting the 'type' key to the key type we have + $type = ($key_mask_info->type == 'Account') ? 'Character' : $key_mask_info->type; + $return_access = array('type' => $type); + + // Loop over all the masks we have, and return those we have access to for this key + foreach (\EveApiCalllist::where('type', '=', $type)->get() as $mask) { + + if ($key_mask_info->accessMask & $mask->accessMask) + $return_access['access'][] = array('type' => $mask->type, 'name' => $mask->name); + } + + // Return it all as a nice array + return $return_access; + } + + /* + |-------------------------------------------------------------------------- + | findKeyCharacters() + |-------------------------------------------------------------------------- + | + | Return an array of valid API calls that are allowed for a recorded keyID + | + */ + + public static function findKeyCharacters($keyID) + { + + // Locate the key in the db + $characters = \EveAccountAPIKeyInfoCharacters::where('keyID', '=', $keyID)->first(); + + if (!$characters) + return; + + $return = array(); + foreach (\EveAccountAPIKeyInfoCharacters::where('keyID', '=', $keyID)->get() as $character) + $return[] = $character->characterID; + + // Return it all as a nice array + return $return; + } + + /* + |-------------------------------------------------------------------------- + | findCharacterCorporation() + |-------------------------------------------------------------------------- + | + | Return the corporationID of a character + | + */ + + public static function findCharacterCorporation($characterID) + { + + // Locate the key in the db + $character = \EveAccountAPIKeyInfoCharacters::where('characterID', '=', $characterID)->first(); + + if (!$character) + return; + + // Return the characters corporationID + return $character->corporationID; + } + + /* + |-------------------------------------------------------------------------- + | findClosestMoon() + |-------------------------------------------------------------------------- + | + | Find the moonID and name closest to the given coordinates + | + */ + + public static function findClosestMoon($itemID, $x, $y, $z) + { + + // Get the system location of the itemID + $systemID = \EveCorporationAssetList::where('itemID', '=', $itemID)->first(); + $nearest_distance = INF; // Placeholder amount + + // Prepare some empty responses + $calculatedSystemID = null; + $calculatedSystemName = null; + + // Find the closest moonID to $x, $x & $z. groupID 8 looks like moons only in the SDE + foreach (\EveMapDenormalize::where('groupID', '=', 8)->where('solarSystemID', '=', $systemID->locationID)->get() as $system) { + + // So it looks there are 2 ways of determining the nearest celestial. The sqrt one is + // aparently a lot more accurate, versus the manhattan one that can be seen in the ECM + // source is slightly less accurate. TBH, I have no idea which one to use. + + // See: http://math.stackexchange.com/a/42642 + $distance = sqrt(pow(($x - $system->x), 2) + pow(($y - $system->y), 2) + pow(($z - $system->z), 2)); + + // Or we can use this alternative from ECM: https://github.com/evecm/ecm/blob/master/ecm/plugins/assets/tasks/assets.py#L418 + // that uses http://en.wikipedia.org/wiki/Taxicab_geometry + // $distance = abs($x - $system->x) + abs($y - $system->y) + abs($z - $system->z); + + // We are only interested in the moonID that is closest to our asset. + // so will update to this moon if it is closer than the previous one + if ($distance < $nearest_distance) { + + // Update the current closes distance for the next pass + $nearest_distance = $distance; + + // Set the variables that will eventually be returned + $calculatedSystemID = $system->itemID; + $calculatedSystemName = $system->itemName; + } + } + + return array('id' => $calculatedSystemID, 'name' => $calculatedSystemName); + } +} diff --git a/app/eveapi/account/AccountAPIKeyInfo.php b/app/eveapi/account/AccountAPIKeyInfo.php new file mode 100644 index 00000000..bfcaa375 --- /dev/null +++ b/app/eveapi/account/AccountAPIKeyInfo.php @@ -0,0 +1,100 @@ +accountScope + ->APIKeyInfo(); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get key information, just disable they key as its probably + // not valid + BaseApi::disableKey($keyID, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $key_info->cached_until, $keyID)) { + + $key_data = \EveAccountAPIKeyInfo::where('keyID', '=', $keyID)->first(); + + if (!$key_data) + $key_data = new \EveAccountAPIKeyInfo; + + $key_data->keyID = $keyID; + $key_data->accessMask = $key_info->key->accessMask; + $key_data->type = $key_info->key->type; + $key_data->expires = (strlen($key_info->key->expires) > 0 ? $key_info->key->expires : null); // hack much? + $key_data->save(); + + // Check if we have any knowledge of any characters for this key. We will remove values from this + // array as we move along to determine which characters we should delete that are possibly no + // longer on this key + $known_characters = array(); + foreach (\EveAccountAPIKeyInfoCharacters::where('keyID', '=', $keyID)->get() as $character) { + $known_characters[] = $character->characterID; + } + $known_characters = array_flip($known_characters); + + // Update the key characters + foreach ($key_info->key->characters as $character) { + + // Check if we need to update || insert + $character_data = \EveAccountAPIKeyInfoCharacters::where('keyID', '=', $keyID) + ->where('characterID', '=', $character->characterID)->first(); + + if (!$character_data) + $character_data = new \EveAccountAPIKeyInfoCharacters; + + // else, add/update + $character_data->characterID = $character->characterID; + $character_data->characterName = $character->characterName; + $character_data->corporationID = $character->corporationID; + $character_data->corporationName = $character->corporationName; + $key_data->characters()->save($character_data); + + // Remove this characterID from the known_characters as its still on + // the key + if (array_key_exists($character->characterID, $known_characters)) + unset($known_characters[$character->characterID]); + } + + // Delete the characters that are no longer part of this key + foreach (array_flip($known_characters) as $oldcharacter) + \EveAccountAPIKeyInfoCharacters::where('keyID', '=', $keyID)->where('characterID', '=', $oldcharacter)->delete(); + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $key_info->cached_until, $keyID); + } + + return $key_info; + } +} diff --git a/app/eveapi/account/AccountAccountStatus.php b/app/eveapi/account/AccountAccountStatus.php new file mode 100644 index 00000000..b7fc16e3 --- /dev/null +++ b/app/eveapi/account/AccountAccountStatus.php @@ -0,0 +1,72 @@ +accountScope + ->AccountStatus(); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $status_info->cached_until, $keyID)) { + + $check_status = \EveAccountAccountStatus::where('keyID', '=', $keyID)->first(); + + if (!$check_status) + $status_data = new \EveAccountAccountStatus; + else + $status_data = $check_status; + + $status_data->keyID = $keyID; + $status_data->paidUntil = $status_info->paidUntil; + $status_data->createDate = $status_info->createDate; + $status_data->logonCount = $status_info->logonCount; + $status_data->logonMinutes = $status_info->logonMinutes; + $status_data->save(); + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $status_info->cached_until, $keyID); + } + return $status_info; + } +} diff --git a/app/eveapi/character/CharacterAccountBalance.php b/app/eveapi/character/CharacterAccountBalance.php new file mode 100644 index 00000000..5044452c --- /dev/null +++ b/app/eveapi/character/CharacterAccountBalance.php @@ -0,0 +1,99 @@ +charScope + ->AccountBalance(array('characterID' => $characterID)); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $account_balance->cached_until, $characterID)) { + + // While we _know_ that there should only be one account for characters + // aka account 1000, lets loop anyways. You never know what CCP might do + // next :) + foreach ($account_balance->accounts as $account) { + + $check_account = \EveCharacterAccountBalance::where('characterID', '=', $characterID) + ->where('accountID', '=', $account->accountID) + ->first(); + + if (!$check_account) + $account_data = new \EveCharacterAccountBalance; + else + $account_data = $check_account; + + $account_data->characterID = $characterID; + $account_data->accountID = $account->accountID; + $account_data->accountKey = $account->accountKey; + $account_data->balance = $account->balance; + $account_data->save(); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $account_balance->cached_until, $characterID); + } + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $account_balance; + } +} diff --git a/app/eveapi/character/CharacterAssetList.php b/app/eveapi/character/CharacterAssetList.php new file mode 100644 index 00000000..7f6a869c --- /dev/null +++ b/app/eveapi/character/CharacterAssetList.php @@ -0,0 +1,120 @@ +charScope + ->AssetList(array('characterID' => $characterID)); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $asset_list->cached_until, $characterID)) { + + // TODO: Look as how we update this. As per https://neweden-dev.com/Character/Asset_List, the itemID + // may change. So, we cant really just update existing ids. For now, we just trash all and recreate the + // assets :< + // Maybe do this in one big transaction? lel + + \EveCharacterAssetList::where('characterID', '=', $characterID)->delete(); + \EveCharacterAssetListContents::where('characterID', '=', $characterID)->delete(); + + // Populate the assets for this character as well as the contents. + foreach ($asset_list->assets as $asset) { + + $asset_data = new \EveCharacterAssetList; + + $asset_data->characterID = $characterID; + $asset_data->itemID = $asset->itemID; + $asset_data->locationID = $asset->locationID; + $asset_data->typeID = $asset->typeID; + $asset_data->quantity = $asset->quantity; + $asset_data->flag = $asset->flag; + $asset_data->singleton = $asset->singleton; + $asset_data->save(); + + // Process the contents if there are any + if (isset($asset->contents)) { + + foreach ($asset->contents as $content) { + + $content_data = new \EveCharacterAssetListContents; + + $content_data->characterID = $characterID; + $content_data->itemID = $asset_data->itemID; + $content_data->typeID = $content->itemID; + $content_data->quantity = $content->quantity; + $content_data->flag = $content->flag; + $content_data->singleton = $content->singleton; + $content_data->rawQuantity = (isset($content->rawQuantity) ? $content->rawQuantity : 0); + + $asset_data->contents()->save($content_data); + } + } + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $asset_list->cached_until, $characterID); + } + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $asset_list; + } +} diff --git a/app/eveapi/character/CharacterCharacterSheet.php b/app/eveapi/character/CharacterCharacterSheet.php new file mode 100644 index 00000000..19111b46 --- /dev/null +++ b/app/eveapi/character/CharacterCharacterSheet.php @@ -0,0 +1,124 @@ +charScope + ->CharacterSheet(array('characterID' => $characterID)); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $character_sheet->cached_until, $characterID)) { + + $character_data = \EveCharacterCharacterSheet::where('characterID', '=', $characterID)->first(); + + if (!$character_data) + $new_data = new \EveCharacterCharacterSheet; + else + $new_data = $character_data; + + $new_data->characterID = $character_sheet->characterID; + $new_data->name = $character_sheet->name; + $new_data->DoB = $character_sheet->DoB; + $new_data->race = $character_sheet->race; + $new_data->bloodLine = $character_sheet->bloodLine; + $new_data->ancestry = $character_sheet->ancestry; + $new_data->gender = $character_sheet->gender; + $new_data->corporationName = $character_sheet->corporationName; + $new_data->corporationID = $character_sheet->corporationID; + $new_data->cloneName = $character_sheet->cloneName; + $new_data->cloneSkillPoints = $character_sheet->cloneSkillPoints; + $new_data->balance = $character_sheet->balance; + $new_data->intelligence = $character_sheet->attributes->intelligence; + $new_data->memory = $character_sheet->attributes->memory; + $new_data->charisma = $character_sheet->attributes->charisma; + $new_data->perception = $character_sheet->attributes->perception; + $new_data->willpower = $character_sheet->attributes->willpower; + $new_data->save(); + + // Update the characters skills + foreach ($character_sheet->skills as $skill) { + + $skill_data = \EveCharacterCharacterSheetSkills::where('characterID', '=', $characterID) + ->where('typeID', '=', $skill->typeID) + ->first(); + + if (!$skill_data) + $skill_info = new \EveCharacterCharacterSheetSkills; + else + $skill_info = $skill_data; + + $skill_info->characterID = $characterID; + $skill_info->typeID = $skill->typeID; + $skill_info->skillpoints = $skill->skillpoints; + $skill_info->level = $skill->level; + $skill_info->published = $skill->published; + $new_data->skills()->save($skill_info); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $character_sheet->cached_until, $characterID); + } + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $character_sheet; + } +} diff --git a/app/eveapi/character/CharacterContactList.php b/app/eveapi/character/CharacterContactList.php new file mode 100644 index 00000000..28f7c738 --- /dev/null +++ b/app/eveapi/character/CharacterContactList.php @@ -0,0 +1,134 @@ +charScope + ->ContactList(array('characterID' => $characterID)); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $contact_list->cached_until, $characterID)) { + + // The ContactList API will potentially return the characters: + // a) personal contacts, + // b) corporation contacts, + // c) alliance contracts. + + // TODO: Think about maybe doing this in a transaction? + + // First, the personal contacts + // Remove the current contacts + \EveCharacterContactList::where('characterID', '=', $characterID)->delete(); + + // Loop over the list we got from the api and update the db + foreach ($contact_list->contactList as $contact) { + + $new_contact = new \EveCharacterContactList; + $new_contact->characterID = $characterID; + $new_contact->contactID = $contact->contactID; + $new_contact->contactName = $contact->contactName; + $new_contact->inWatchlist = (isset($contact->inWatchlist) ? $contact->inWatchlist : null); + $new_contact->standing = $contact->standing; + $new_contact->contactTypeID = $contact->contactTypeID; + $new_contact->save(); + } + + // Second, the corporate contacts + // Remove the current contacts + \EveCharacterContactListCorporate::where('characterID', '=', $characterID)->delete(); + + // Loop over the list we got from the api and update the db + foreach ($contact_list->corporateContactList as $contact) { + + $new_contact = new \EveCharacterContactListCorporate; + $new_contact->characterID = $characterID; + $new_contact->contactID = $contact->contactID; + $new_contact->contactName = $contact->contactName; + $new_contact->standing = $contact->standing; + $new_contact->contactTypeID = $contact->contactTypeID; + $new_contact->save(); + } + + // Third, the alliance contacts + // Remove the current contacts + \EveCharacterContactListAlliance::where('characterID', '=', $characterID)->delete(); + + // Loop over the list we got from the api and update the db + foreach ($contact_list->allianceContactList as $contact) { + + $new_contact = new \EveCharacterContactListAlliance; + $new_contact->characterID = $characterID; + $new_contact->contactID = $contact->contactID; + $new_contact->contactName = $contact->contactName; + $new_contact->standing = $contact->standing; + $new_contact->contactTypeID = $contact->contactTypeID; + $new_contact->save(); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $contact_list->cached_until, $characterID); + } + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $contact_list; + } +} diff --git a/app/eveapi/character/CharacterContactNotifications.php b/app/eveapi/character/CharacterContactNotifications.php new file mode 100644 index 00000000..db4bb39d --- /dev/null +++ b/app/eveapi/character/CharacterContactNotifications.php @@ -0,0 +1,99 @@ +charScope + ->ContactNotifications(array('characterID' => $characterID)); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $contact_notifications->cached_until, $characterID)) { + + // Process all of the received notifications + foreach ($contact_notifications->contactNotifications as $notification) { + + $notification_data = \EveCharacterContactNotifications::where('characterID', '=', $characterID) + ->where('notificationID', '=', $notification->notificationID) + ->first(); + + if (!$notification_data) + $new_data = new \EveCharacterContactNotifications; + else + $new_data = $notification_data; + + $new_data->characterID = $characterID; + $new_data->notificationID = $notification->notificationID; + $new_data->senderID = $notification->senderID; + $new_data->senderName = $notification->senderName; + $new_data->sentDate = $notification->sentDate; + $new_data->messageData = $notification->messageData; + $new_data->save(); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $contact_notifications->cached_until, $characterID); + } + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $contact_notifications; + } +} diff --git a/app/eveapi/character/CharacterContracts.php b/app/eveapi/character/CharacterContracts.php new file mode 100644 index 00000000..3ffeb6fe --- /dev/null +++ b/app/eveapi/character/CharacterContracts.php @@ -0,0 +1,161 @@ +charScope + ->Contracts(array('characterID' => $characterID)); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $contracts->cached_until, $characterID)) { + + // Loop over the contracts and update + foreach ($contracts->contractList as $contract) { + + $contract_data = \EveCharacterContracts::where('characterID', '=', $characterID) + ->where('contractID', '=', $contract->contractID) + ->first(); + + // If we an existing contract that we are just going to update, then dont bother + // running /char/ContractItems. I *think* this will be the same all the time + // and can only change by creating a new contract + if (!$contract_data) { + + $new_data = new \EveCharacterContracts; + $get_items = true; // [1] + } else { + + $new_data = $contract_data; + $get_items = false; + } + + $new_data->characterID = $characterID; + $new_data->contractID = $contract->contractID; + $new_data->issuerID = $contract->issuerID; + $new_data->issuerCorpID = $contract->issuerCorpID; + $new_data->acceptorID = $contract->acceptorID; + $new_data->startStationID = $contract->startStationID; + $new_data->endStationID = $contract->endStationID; + $new_data->type = $contract->type; + $new_data->status = $contract->status; + $new_data->title = $contract->title; + $new_data->forCorp = $contract->forCorp; + $new_data->availability = $contract->availability; + $new_data->dateIssued = $contract->dateIssued; + $new_data->dateExpired = (strlen($contract->dateExpired) > 0 ? $contract->dateExpired : null); + $new_data->dateAccepted = (strlen($contract->dateAccepted) > 0 ? $contract->dateAccepted : null); + $new_data->numDays = $contract->numDays; + $new_data->dateCompleted = (strlen($contract->dateCompleted) > 0 ? $contract->dateCompleted : null); + $new_data->price = $contract->price; + $new_data->reward = $contract->reward; + $new_data->collateral = $contract->collateral; + $new_data->buyout = $contract->buyout; + $new_data->volume = $contract->volume; + $new_data->save(); + + // [1] New contracts will have their 'items' updated too. Do it + if ($get_items) { + + try { + + $contracts_items = $pheal + ->charScope + ->ContractItems(array('characterID' => $characterID, 'contractID' => $contract->contractID)); + + // We wont use the ban logic here as the accessmask does not differ + // from the call that got us as far as this. + } catch (\Pheal\Exceptions\APIException $e) { + + // What to do with a invalid id? + continue; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Loop over the items and save it + $items = new \EveCharacterContractsItems; + + foreach ($contracts_items->itemList as $item) { + + $items->characterID = $characterID; + $items->contractID = $contract->contractID; + $items->recordID = $item->recordID; + $items->typeID = $item->typeID; + $items->quantity = $item->quantity; + $items->rawQuantity = (isset($item->rawQuantity) ? $item->rawQuantity : null); + $items->singleton = $item->singleton; + $items->included = $item->included; + $new_data->items()->save($items); + } + } + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $contracts->cached_until, $characterID); + } + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $contracts; + } +} diff --git a/app/eveapi/character/CharacterIndustryJobs.php b/app/eveapi/character/CharacterIndustryJobs.php new file mode 100644 index 00000000..fce64cf9 --- /dev/null +++ b/app/eveapi/character/CharacterIndustryJobs.php @@ -0,0 +1,127 @@ +charScope + ->IndustryJobs(array('characterID' => $characterID)); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $industry_jobs->cached_until, $characterID)) { + + // Populate the jobs for this character + foreach ($industry_jobs->jobs as $job) { + + $job_data = \EveCharacterIndustryJobs::where('characterID', '=', $characterID) + ->where('jobID', '=', $job->jobID) + ->first(); + + if (!$job_data) + $new_job = new \EveCharacterIndustryJobs; + else + $new_job = $job_data; + + $new_job->characterID = $characterID; + $new_job->jobID = $job->jobID; + $new_job->assemblyLineID = $job->assemblyLineID; + $new_job->containerID = $job->containerID; + $new_job->installedItemID = $job->installedItemID; + $new_job->installedItemLocationID = $job->installedItemLocationID; + $new_job->installedItemQuantity = $job->installedItemQuantity; + $new_job->installedItemProductivityLevel = $job->installedItemProductivityLevel; + $new_job->installedItemMaterialLevel = $job->installedItemMaterialLevel; + $new_job->installedItemLicensedProductionRunsRemaining = $job->installedItemLicensedProductionRunsRemaining; + $new_job->outputLocationID = $job->outputLocationID; + $new_job->installerID = $job->installerID; + $new_job->runs = $job->runs; + $new_job->licensedProductionRuns = $job->licensedProductionRuns; + $new_job->installedInSolarSystemID = $job->installedInSolarSystemID; + $new_job->containerLocationID = $job->containerLocationID; + $new_job->materialMultiplier = $job->materialMultiplier; + $new_job->charMaterialMultiplier = $job->charMaterialMultiplier; + $new_job->timeMultiplier = $job->timeMultiplier; + $new_job->charTimeMultiplier = $job->charTimeMultiplier; + $new_job->installedItemTypeID = $job->installedItemTypeID; + $new_job->outputTypeID = $job->outputTypeID; + $new_job->containerTypeID = $job->containerTypeID; + $new_job->installedItemCopy = $job->installedItemCopy; + $new_job->completed = $job->completed; + $new_job->completedSuccessfully = $job->completedSuccessfully; + $new_job->installedItemFlag = $job->installedItemFlag; + $new_job->outputFlag = $job->outputFlag; + $new_job->activityID = $job->activityID; + $new_job->completedStatus = $job->completedStatus; + $new_job->installTime = $job->installTime; + $new_job->beginProductionTime = $job->beginProductionTime; + $new_job->endProductionTime = $job->endProductionTime; + $new_job->pauseProductionTime = $job->pauseProductionTime; + $new_job->save(); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $industry_jobs->cached_until, $characterID); + } + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $industry_jobs; + } +} diff --git a/app/eveapi/character/CharacterMailMessages.php b/app/eveapi/character/CharacterMailMessages.php new file mode 100644 index 00000000..6b256b2d --- /dev/null +++ b/app/eveapi/character/CharacterMailMessages.php @@ -0,0 +1,149 @@ +charScope + ->MailMessages(array('characterID' => $characterID)); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $mail_messages->cached_until, $characterID)) { + + // Loop over the list we got from the api and update the db, + // remebering the messageID's for downloading the bodies too + $bodies = array(); + foreach ($mail_messages->messages as $message) { + + $mail_body_data = \EveCharacterMailMessages::where('characterID', '=', $characterID) + ->where('messageID', '=', $message->messageID) + ->first(); + + if (!$mail_body_data) { + + $mail_body = new \EveCharacterMailMessages; + $bodies[] = $message->messageID; // Record the messagID to download later + } else { + + // Check if we have the body for this existing message, else + // we will add it to the list to download + if (!\EveCharacterMailBodies::where('messageID', '=', $message->messageID)) + $bodies[] = $message->messageID; + + continue; + } + + $mail_body->characterID = $characterID; + $mail_body->messageID = $message->messageID; + $mail_body->senderID = $message->senderID; + $mail_body->senderName = $message->senderName; + $mail_body->sentDate = $message->sentDate; + $mail_body->title = $message->title; + $mail_body->toCorpOrAllianceID = (strlen($message->toCorpOrAllianceID) > 0 ? $message->toCorpOrAllianceID : null); + $mail_body->toCharacterIDs = (strlen($message->toCharacterIDs) > 0 ? $message->toCharacterIDs : null); + $mail_body->toListID = (strlen($message->toListID) > 0 ? $message->toListID : null); + $mail_body->save(); + } + + // Split the bodies we need to download into chunks of 10 each. Pheal-NG will + // log the whole request as a file name for chaching... + // which is tooooooo looooooooooooong + $bodies = array_chunk($bodies, 10); + + // Iterate over the chunks. + foreach ($bodies as $chunk) { + + try { + + $mail_bodies = $pheal + ->charScope + ->MailBodies(array('characterID' => $characterID, 'ids' => implode(',', $chunk))); + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Loop over the received bodies + foreach ($mail_bodies->messages as $body) { + + // Actually, this check is pretty redundant, so maybe remove it + $body_data = \EveCharacterMailBodies::where('messageID', '=', $body->messageID)->first(); + + if (!$body_data) + $new_body = new \EveCharacterMailBodies; + else + continue; + + $new_body->messageID = $body->messageID; + $new_body->body = $body->__toString(); + $new_body->save(); + } + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $mail_messages->cached_until, $characterID); + } + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $mail_messages; + } +} diff --git a/app/eveapi/character/CharacterMailingLists.php b/app/eveapi/character/CharacterMailingLists.php new file mode 100644 index 00000000..399f1ca7 --- /dev/null +++ b/app/eveapi/character/CharacterMailingLists.php @@ -0,0 +1,98 @@ +charScope + ->MailingLists(array('characterID' => $characterID)); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $mailing_lists->cached_until, $characterID)) { + + foreach ($mailing_lists->mailingLists as $list) { + + $list_data = \EveCharacterMailingLists::where('characterID', '=', $characterID) + ->where('listID', '=', $list->listID) + ->first(); + + // Start a new \EveCharacterMailingLists instance, else, just continue. + // Doesn't look like ML's can be renamed, and we want to keep old ones + // to be able to lookup old ML id's. + if (!$list_data) + $new_list = new \EveCharacterMailingLists; + else + continue; + + $new_list->characterID = $characterID; + $new_list->listID = $list->listID; + $new_list->displayName = $list->displayName; + $new_list->save(); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $mailing_lists->cached_until, $characterID); + } + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $mailing_lists; + } +} diff --git a/app/eveapi/character/CharacterMarketOrders.php b/app/eveapi/character/CharacterMarketOrders.php new file mode 100644 index 00000000..6f8725da --- /dev/null +++ b/app/eveapi/character/CharacterMarketOrders.php @@ -0,0 +1,107 @@ +charScope + ->MarketOrders(array('characterID' => $characterID)); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $market_orders->cached_until, $characterID)) { + + foreach ($market_orders->orders as $order) { + + $order_data = \EveCharacterMarketOrders::where('characterID', '=', $characterID) + ->where('orderID', '=', $order->orderID) + ->first(); + + if (!$order_data) + $order_info = new \EveCharacterMarketOrders; + else + $order_info = $order_data; + + $order_info->characterID = $characterID; + $order_info->orderID = $order->orderID; + $order_info->charID = $order->charID; + $order_info->stationID = $order->stationID; + $order_info->volEntered = $order->volEntered; + $order_info->volRemaining = $order->volRemaining; + $order_info->minVolume = $order->minVolume; + $order_info->orderState = $order->orderState; + $order_info->typeID = $order->typeID; + $order_info->range = $order->range; + $order_info->duration = $order->duration; + $order_info->escrow = $order->escrow; + $order_info->price = $order->price; + $order_info->bid = $order->bid; + $order_info->issued = $order->issued; + $order_info->save(); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $market_orders->cached_until, $characterID); + } + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $market_orders; + } +} diff --git a/app/eveapi/character/CharacterNotifications.php b/app/eveapi/character/CharacterNotifications.php new file mode 100644 index 00000000..40f1d670 --- /dev/null +++ b/app/eveapi/character/CharacterNotifications.php @@ -0,0 +1,147 @@ +charScope + ->Notifications(array('characterID' => $characterID)); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $notifications->cached_until, $characterID)) { + + // Loop over the list we got from the api and update the db, + // remebering the messageID's for downloading the bodies too + $texts = array(); + foreach ($notifications->notifications as $notification) { + + $notification_data = \EveCharacterNotifications::where('characterID', '=', $characterID) + ->where('notificationID', '=', $notification->notificationID) + ->first(); + + if (!$notification_data) { + + $new_notification = new \EveCharacterNotifications; + $texts[] = $notification->notificationID; // Record the notificationID to download later + } else { + + // Check if we have the body for this existing message, else + // we will add it to the list to download + if (!\EveCharacterNotificationTexts::where('notificationID', '=', $notification->notificationID)) + $texts[] = $notification->notificationID; + + continue; + } + + $new_notification->characterID = $characterID; + $new_notification->notificationID = $notification->notificationID; + $new_notification->typeID = $notification->typeID; + $new_notification->senderID = $notification->senderID; + $new_notification->senderName = $notification->senderName; + $new_notification->sentDate = $notification->sentDate; + $new_notification->read = $notification->read; + $new_notification->save(); + } + + // Split the text we need to download into chunks of 10 each. Pheal-NG will + // log the whole request as a file name for chaching... + // which is tooooooo looooooooooooong + $texts = array_chunk($texts, 10); + + // Iterate over the chunks. + foreach ($texts as $chunk) { + + try { + + $notification_texts = $pheal + ->charScope + ->NotificationTexts(array('characterID' => $characterID, 'ids' => implode(',', $chunk))); + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Loop over the received texts + foreach ($notification_texts->notifications as $text) { + + // Actually, this check is pretty redundant, so maybe remove it + $text_data = \EveCharacterNotificationTexts::where('notificationID', '=', $text->notificationID)->first(); + + if (!$text_data) + $new_text = new \EveCharacterNotificationTexts; + else + continue; + + $new_text->notificationID = $text->notificationID; + $new_text->text = $text->__toString(); + $new_text->save(); + } + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $notifications->cached_until, $characterID); + } + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $notifications; + } +} diff --git a/app/eveapi/character/CharacterResearch.php b/app/eveapi/character/CharacterResearch.php new file mode 100644 index 00000000..c2d7b60a --- /dev/null +++ b/app/eveapi/character/CharacterResearch.php @@ -0,0 +1,99 @@ +charScope + ->Research(array('characterID' => $characterID)); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $research->cached_until, $characterID)) { + + // Populate the jobs for this character + foreach ($research->research as $r) { + + $research_data = \EveCharacterResearch::where('characterID', '=', $characterID) + ->where('agentID', '=', $r->agentID) + ->first(); + + if (!$research_data) + $new_r = new \EveCharacterResearch; + else + $new_r = $research_data; + + $new_r->characterID = $characterID; + $new_r->agentID = $r->agentID; + $new_r->skillTypeID = $r->skillTypeID; + $new_r->researchStartDate = $r->researchStartDate; + $new_r->pointsPerDay = $r->pointsPerDay; + $new_r->remainderPoints = $r->remainderPoints; + $new_r->save(); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $research->cached_until, $characterID); + } + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $research; + } +} diff --git a/app/eveapi/character/CharacterSkillInTraining.php b/app/eveapi/character/CharacterSkillInTraining.php new file mode 100644 index 00000000..ce74b053 --- /dev/null +++ b/app/eveapi/character/CharacterSkillInTraining.php @@ -0,0 +1,103 @@ +charScope + ->SkillInTraining(array('characterID' => $characterID)); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $skill_in_training->cached_until, $characterID)) { + + $character_data = \EveCharacterSkillInTraining::where('characterID', '=', $characterID)->first(); + + if (!$character_data) + $character_data = new \EveCharacterSkillInTraining; + + if ($skill_in_training->skillInTraining == 1) { + + $character_data->characterID = $characterID; + $character_data->currentTQTime = $skill_in_training->currentTQTime->_value; + $character_data->trainingEndTime = $skill_in_training->trainingEndTime; + $character_data->trainingStartTime = $skill_in_training->trainingStartTime; + $character_data->trainingTypeID = $skill_in_training->trainingTypeID; + $character_data->trainingStartSP = $skill_in_training->trainingStartSP; + $character_data->trainingDestinationSP = $skill_in_training->trainingDestinationSP; + $character_data->trainingToLevel = $skill_in_training->trainingToLevel; + $character_data->skillInTraining = $skill_in_training->skillInTraining; + $character_data->save(); + + } else { + + $character_data->characterID = $characterID; + $character_data->skillInTraining = 0; + $character_data->save(); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $skill_in_training->cached_until, $characterID); + } + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $skill_in_training; + } +} diff --git a/app/eveapi/character/CharacterSkillQueue.php b/app/eveapi/character/CharacterSkillQueue.php new file mode 100644 index 00000000..aa3b6138 --- /dev/null +++ b/app/eveapi/character/CharacterSkillQueue.php @@ -0,0 +1,99 @@ +charScope + ->SkillQueue(array('characterID' => $characterID)); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $skill_queue->cached_until, $characterID)) { + + // Remove the current Queue + \EveCharacterSkillQueue::where('characterID', '=', $characterID)->delete(); + + // Add the current queue information + foreach ($skill_queue->skillqueue as $queue) { + + // Start a new queue entry for this character + $character_data = new \EveCharacterSkillQueue; + + // And populate the fields for him. + $character_data->characterID = $characterID; + $character_data->queuePosition = $queue->queuePosition; + $character_data->typeID = $queue->typeID; + $character_data->level = $queue->level; + $character_data->startSP = $queue->startSP; + $character_data->endSP = $queue->endSP; + $character_data->startTime = (strlen($queue->startTime) > 0 ? $queue->startTime : null); + $character_data->endTime = (strlen($queue->endTime) > 0 ? $queue->endTime : null); + $character_data->save(); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $skill_queue->cached_until, $characterID); + } + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $skill_queue; + } +} diff --git a/app/eveapi/character/CharacterStandings.php b/app/eveapi/character/CharacterStandings.php new file mode 100644 index 00000000..11be461d --- /dev/null +++ b/app/eveapi/character/CharacterStandings.php @@ -0,0 +1,129 @@ +charScope + ->Standings(array('characterID' => $characterID)); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $standings->cached_until, $characterID)) { + + // Populate the agents standings for this character + foreach ($standings->characterNPCStandings->agents as $standing) { + + $standing_data = \EveCharacterStandingsAgents::where('characterID', '=', $characterID) + ->where('fromID', '=', $standing->fromID) + ->first(); + + if (!$standing_data) + $standing_data = new \EveCharacterStandingsAgents; + + $standing_data->characterID = $characterID; + $standing_data->fromID = $standing->fromID; + $standing_data->fromName = $standing->fromName; + $standing_data->standing = $standing->standing; + $standing_data->save(); + } + + // Populate the faction standings for this character + foreach ($standings->characterNPCStandings->factions as $standing) { + + $standing_data = \EveCharacterStandingsFactions::where('characterID', '=', $characterID) + ->where('fromID', '=', $standing->fromID) + ->first(); + + if (!$standing_data) + $standing_data = new \EveCharacterStandingsFactions; + + $standing_data->characterID = $characterID; + $standing_data->fromID = $standing->fromID; + $standing_data->fromName = $standing->fromName; + $standing_data->standing = $standing->standing; + $standing_data->save(); + } + + // Populate the NPCCorporation standings for this character + foreach ($standings->characterNPCStandings->NPCCorporations as $standing) { + + $standing_data = \EveCharacterStandingsNPCCorporations::where('characterID', '=', $characterID) + ->where('fromID', '=', $standing->fromID) + ->first(); + + if (!$standing_data) + $standing_data = new \EveCharacterStandingsNPCCorporations; + + $standing_data->characterID = $characterID; + $standing_data->fromID = $standing->fromID; + $standing_data->fromName = $standing->fromName; + $standing_data->standing = $standing->standing; + $standing_data->save(); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $standings->cached_until, $characterID); + } + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $standings; + } +} diff --git a/app/eveapi/character/CharacterUpcomingCalendarEvents.php b/app/eveapi/character/CharacterUpcomingCalendarEvents.php new file mode 100644 index 00000000..eb88acb8 --- /dev/null +++ b/app/eveapi/character/CharacterUpcomingCalendarEvents.php @@ -0,0 +1,102 @@ +charScope + ->UpcomingCalendarEvents(array('characterID' => $characterID)); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $events->cached_until, $characterID)) { + + // Populate the jobs for this character + foreach ($events->upcomingEvents as $event) { + + $event_data = \EveCharacterUpcomingCalendarEvents::where('characterID', '=', $characterID) + ->where('eventID', '=', $event->eventID) + ->first(); + + if (!$event_data) + $event_data = new \EveCharacterUpcomingCalendarEvents; + + $event_data->characterID = $characterID; + $event_data->eventID = $event->eventID; + $event_data->ownerID = $event->ownerID; + $event_data->ownerName = $event->ownerName; + $event_data->eventDate = $event->eventDate; + $event_data->eventTitle = $event->eventTitle; + $event_data->duration = $event->duration; + $event_data->importance = $event->importance; + $event_data->response = $event->response; + $event_data->eventText = $event->eventText; + $event_data->ownerTypeID = $event->ownerTypeID; + $event_data->save(); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $events->cached_until, $characterID); + } + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $events; + } +} diff --git a/app/eveapi/character/CharacterWalletJournal.php b/app/eveapi/character/CharacterWalletJournal.php new file mode 100644 index 00000000..c1fef59b --- /dev/null +++ b/app/eveapi/character/CharacterWalletJournal.php @@ -0,0 +1,140 @@ +charScope + ->WalletJournal(array('characterID' => $characterID, 'rowCount' => $row_count)); + + // flip the first_request as those that get processed from here need to be from the `fromID` + $first_request = false; + + } else { + + $wallet_journal = $pheal + ->charScope + ->WalletJournal(array('characterID' => $characterID, 'rowCount' => $row_count, 'fromID' => $from_id)); + } + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Process the transactions + foreach ($wallet_journal->transactions as $transaction) { + + // Ensure that $from_id is at its lowest + $from_id = min($transaction->refID, $from_id); + + // Generate a transaction hash. It would seem that refID's could possibly be cycled. + $transaction_hash = md5(implode(',', array($characterID, $transaction->date, $transaction->ownerID1, $transaction->refID))); + + $transaction_data = \EveCharacterWalletJournal::where('characterID', '=', $characterID) + ->where('hash', '=', $transaction_hash) + ->first(); + + if (!$transaction_data) + $transaction_data = new \EveCharacterWalletJournal; + else + continue; + + $transaction_data->characterID = $characterID; + $transaction_data->hash = $transaction_hash; + $transaction_data->refID = $transaction->refID; + $transaction_data->date = $transaction->date; + $transaction_data->refTypeID = $transaction->refTypeID; + $transaction_data->ownerName1 = $transaction->ownerName1; + $transaction_data->ownerID1 = $transaction->ownerID1; + $transaction_data->ownerName2 = $transaction->ownerName2; + $transaction_data->ownerID2 = $transaction->ownerID2; + $transaction_data->argName1 = $transaction->argName1; + $transaction_data->argID1 = $transaction->argID1; + $transaction_data->amount = $transaction->amount; + $transaction_data->balance = $transaction->balance; + $transaction_data->reason = $transaction->reason; + $transaction_data->taxReceiverID = (strlen($transaction->taxReceiverID) > 0 ? $transaction->taxReceiverID : 0); + $transaction_data->taxAmount = (strlen($transaction->taxAmount) > 0 ? $transaction->taxAmount : 0); + $transaction_data->owner1TypeID = $transaction->owner1TypeID; + $transaction_data->owner2TypeID = $transaction->owner2TypeID; + $transaction_data->save(); + } + + // Check how many entries we got back. If it us less that $row_count, we know we have + // walked back the entire journal + if (count($wallet_journal->transactions) < $row_count) + break; // Break the while loop + } + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $wallet_journal; + } +} diff --git a/app/eveapi/character/CharacterWalletTransactions.php b/app/eveapi/character/CharacterWalletTransactions.php new file mode 100644 index 00000000..4bd4b07d --- /dev/null +++ b/app/eveapi/character/CharacterWalletTransactions.php @@ -0,0 +1,136 @@ +charScope + ->WalletTransactions(array('characterID' => $characterID, 'rowCount' => $row_count)); + } else { + + $wallet_transactions = $pheal + ->charScope + ->WalletTransactions(array('characterID' => $characterID, 'rowCount' => $row_count, 'fromID' => $from_id)); + } + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + + // Process the transactions + foreach ($wallet_transactions->transactions as $transaction) { + + // Ensure that $from_id is at its lowest + $from_id = min($transaction->transactionID, $from_id); + + // Generate a transaction hash. It would seem that transactionID's could possibly be + // cycled. + $transaction_hash = md5(implode(',', array($characterID, $transaction->transactionDateTime, $transaction->clientID, $transaction->transactionID))); + + $transaction_data = \EveCharacterWalletTransactions::where('characterID', '=', $characterID) + ->where('hash', '=', $transaction_hash) + ->first(); + + if (!$transaction_data) + $transaction_data = new \EveCharacterWalletTransactions; + else + continue; + + $transaction_data->characterID = $characterID; + $transaction_data->hash = $transaction_hash; + $transaction_data->transactionID = $transaction->transactionID; + $transaction_data->transactionDateTime = $transaction->transactionDateTime; + $transaction_data->quantity = $transaction->quantity; + $transaction_data->typeName = $transaction->typeName; + $transaction_data->typeID = $transaction->typeID; + $transaction_data->price = $transaction->price; + $transaction_data->clientID = $transaction->clientID; + $transaction_data->clientName = $transaction->clientName; + $transaction_data->stationID = $transaction->stationID; + $transaction_data->stationName = $transaction->stationName; + $transaction_data->transactionType = $transaction->transactionType; + $transaction_data->transactionFor = $transaction->transactionFor; + $transaction_data->journalTransactionID = $transaction->journalTransactionID; + $transaction_data->clientTypeID = $transaction->clientTypeID; + $transaction_data->save(); + } + + // Check how many entries we got back. If it us less than $row_count, we know we have + // walked back the entire journal + if (count($wallet_transactions->transactions) < $row_count) + break; // Break the while loop + } + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $wallet_transactions; + } +} diff --git a/app/eveapi/corporation/CorporationAccountBalance.php b/app/eveapi/corporation/CorporationAccountBalance.php new file mode 100644 index 00000000..86a53fcd --- /dev/null +++ b/app/eveapi/corporation/CorporationAccountBalance.php @@ -0,0 +1,96 @@ +corpScope + ->AccountBalance(array('characterID' => $characters[0])); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $account_balance->cached_until, $corporationID)) { + + // Update the accounts + foreach ($account_balance->accounts as $account) { + + $account_data = \EveCorporationAccountBalance::where('corporationID', '=', $corporationID) + ->where('accountID', '=', $account->accountID) + ->first(); + + if (!$account_data) + $account_data = new \EveCorporationAccountBalance; + + $account_data->corporationID = $corporationID; + $account_data->accountID = $account->accountID; + $account_data->accountKey = $account->accountKey; + $account_data->balance = $account->balance; + $account_data->save(); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $account_balance->cached_until, $corporationID); + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $account_balance; + } +} diff --git a/app/eveapi/corporation/CorporationAssetList.php b/app/eveapi/corporation/CorporationAssetList.php new file mode 100644 index 00000000..4d370f06 --- /dev/null +++ b/app/eveapi/corporation/CorporationAssetList.php @@ -0,0 +1,176 @@ +corpScope + ->AssetList(array('characterID' => $characters[0])); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $asset_list->cached_until, $corporationID)) { + + // TODO: Look as how we update this. As per https://neweden-dev.com/Character/Asset_List, the itemID + // may change. So, we cant really just update existing ids. For now, we just trash all and recreate the + // assets :< + // Maybe do this in one big transaction? lel + + \EveCorporationAssetList::where('corporationID', '=', $corporationID)->delete(); + \EveCorporationAssetListContents::where('corporationID', '=', $corporationID)->delete(); + + // Note about /corp/Locations + // + // We will build a list of itemID's to update the location information about + // while we loop over the assets. This will be stored in location_retreive and + // processed here [1] + $location_retreive = array(); + + // Populate the assets for this corporation as well as the contents. + foreach ($asset_list->assets as $asset) { + + // Add the asset to the location retreival array + $location_retreive[] = $asset->itemID; + + // Process the rest of the database population + $asset_data = new \EveCorporationAssetList; + + $asset_data->corporationID = $corporationID; + $asset_data->itemID = $asset->itemID; + $asset_data->locationID = $asset->locationID; + $asset_data->typeID = $asset->typeID; + $asset_data->quantity = $asset->quantity; + $asset_data->flag = $asset->flag; + $asset_data->singleton = $asset->singleton; + $asset_data->save(); + + // Process the contents if there are any + if (isset($asset->contents)) { + + foreach ($asset->contents as $content) { + + $content_data = new \EveCorporationAssetListContents; + + $content_data->corporationID = $corporationID; + $content_data->itemID = $asset_data->itemID; + $content_data->typeID = $content->typeID; + $content_data->quantity = $content->quantity; + $content_data->flag = $content->flag; + $content_data->singleton = $content->singleton; + $content_data->rawQuantity = (isset($content->rawQuantity) ? $content->rawQuantity : 0); + + $asset_data->contents()->save($content_data); + } + } + } + + // Now empty and process the locations as per [1] + \EveCorporationAssetListLocations::where('corporationID', '=', $corporationID)->delete(); + $location_retreive = array_chunk($location_retreive, 1); + + // Iterate over the chunks. + foreach ($location_retreive as $chunk) { + + try { + + $locations = $pheal + ->corpScope + ->Locations(array('characterID' => $characters[0], 'ids' => implode(',', $chunk))); + + } catch (\Pheal\Exceptions\PhealException $e) { + + // Temp hack to check the asset list thingie + // TBH, I am not 100% sure yet why the freaking call would fail for a id we **just** + // got from the previous API call... + if ($e->getCode() == 135 || $e->getCode() == 221) // 135 "not the owner" | 221 "illegal page request" + continue; + else + throw $e; + } + + // Loop over the locations, check their closest celestial + // and add the data to the database + foreach ($locations->locations as $location) { + + $closest_moon = BaseApi::findClosestMoon($location->itemID, $location->x, $location->y, $location->z); + + $location_data = new \EveCorporationAssetListLocations; + + $location_data->corporationID = $corporationID; + $location_data->itemID = $location->itemID; + $location_data->itemName = $location->itemName; + $location_data->x = $location->x; + $location_data->y = $location->y; + $location_data->z = $location->z; + $location_data->mapID = $closest_moon['id']; + $location_data->mapName = $closest_moon['name']; + $location_data->save(); + } + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $asset_list->cached_until, $corporationID); + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $asset_list; + } +} diff --git a/app/eveapi/corporation/CorporationContactList.php b/app/eveapi/corporation/CorporationContactList.php new file mode 100644 index 00000000..4bb7f969 --- /dev/null +++ b/app/eveapi/corporation/CorporationContactList.php @@ -0,0 +1,117 @@ +corpScope + ->ContactList(array('characterID' => $characters[0])); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $contact_list->cached_until, $corporationID)) { + + // The ContactList API will potentially return the corporations: + // a) corporation contacts, + // b) alliance contracts. + + // TODO: Think about maybe doing this in a transaction? + + // First, the corporate contacts + // Remove the current contacts + \EveCorporationContactListCorporate::where('corporationID', '=', $corporationID)->delete(); + + // Loop over the list we got from the api and update the db + foreach ($contact_list->corporateContactList as $contact) { + + $new_contact = new \EveCorporationContactListCorporate; + $new_contact->corporationID = $corporationID; + $new_contact->contactID = $contact->contactID; + $new_contact->contactName = $contact->contactName; + $new_contact->standing = $contact->standing; + $new_contact->contactTypeID = $contact->contactTypeID; + $new_contact->save(); + } + + // Second, the alliance contacts + // Remove the current contacts + \EveCorporationContactListAlliance::where('corporationID', '=', $corporationID)->delete(); + + // Loop over the list we got from the api and update the db + foreach ($contact_list->allianceContactList as $contact) { + + $new_contact = new \EveCorporationContactListAlliance; + $new_contact->corporationID = $corporationID; + $new_contact->contactID = $contact->contactID; + $new_contact->contactName = $contact->contactName; + $new_contact->standing = $contact->standing; + $new_contact->contactTypeID = $contact->contactTypeID; + $new_contact->save(); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $contact_list->cached_until, $corporationID); + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $contact_list; + } +} diff --git a/app/eveapi/corporation/CorporationContracts.php b/app/eveapi/corporation/CorporationContracts.php new file mode 100644 index 00000000..7c4a8e12 --- /dev/null +++ b/app/eveapi/corporation/CorporationContracts.php @@ -0,0 +1,162 @@ +corpScope + ->Contracts(array('characterID' => $characters[0])); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $contracts->cached_until, $corporationID)) { + + // Loop over the contracts and update + foreach ($contracts->contractList as $contract) { + + $contract_data = \EveCorporationContracts::where('corporationID', '=', $corporationID) + ->where('contractID', '=', $contract->contractID) + ->first(); + + // If we an existing contract that we are just going to update, then dont bother + // running /char/ContractItems. I *think* this will be the same all the time + // and can only change by creating a new contract + if (!$contract_data) { + + $new_data = new \EveCorporationContracts; + $get_items = true; // [1] + } else { + + $new_data = $contract_data; + $get_items = false; + } + + $new_data->corporationID = $corporationID; + $new_data->contractID = $contract->contractID; + $new_data->issuerID = $contract->issuerID; + $new_data->issuerCorpID = $contract->issuerCorpID; + $new_data->acceptorID = $contract->acceptorID; + $new_data->startStationID = $contract->startStationID; + $new_data->endStationID = $contract->endStationID; + $new_data->type = $contract->type; + $new_data->status = $contract->status; + $new_data->title = $contract->title; + $new_data->forCorp = $contract->forCorp; + $new_data->availability = $contract->availability; + $new_data->dateIssued = $contract->dateIssued; + $new_data->dateExpired = (strlen($contract->dateExpired) > 0 ? $contract->dateExpired : null); + $new_data->dateAccepted = (strlen($contract->dateAccepted) > 0 ? $contract->dateAccepted : null); + $new_data->numDays = $contract->numDays; + $new_data->dateCompleted = (strlen($contract->dateCompleted) > 0 ? $contract->dateCompleted : null); + $new_data->price = $contract->price; + $new_data->reward = $contract->reward; + $new_data->collateral = $contract->collateral; + $new_data->buyout = $contract->buyout; + $new_data->volume = $contract->volume; + $new_data->save(); + + // [1] New contracts will have their 'items' updated too. Do it + if ($get_items) { + + try { + + $contracts_items = $pheal + ->corpScope + ->ContractItems(array('characterID' => $characters[0], 'contractID' => $contract->contractID)); + + // We wont use the ban logic here as the accessmask does not differ + // from the call that got us as far as this. + } catch (\Pheal\Exceptions\APIException $e) { + + // What to do with a invalid id? + continue; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Loop over the items and save it + $items = new \EveCorporationContractsItems; + + foreach ($contracts_items->itemList as $item) { + + $items->corporationID = $corporationID; + $items->contractID = $contract->contractID; + $items->recordID = $item->recordID; + $items->typeID = $item->typeID; + $items->quantity = $item->quantity; + $items->rawQuantity = (isset($item->rawQuantity) ? $item->rawQuantity : null); + $items->singleton = $item->singleton; + $items->included = $item->included; + $new_data->items()->save($items); + } + } + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $contracts->cached_until, $corporationID); + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $contracts; + } +} diff --git a/app/eveapi/corporation/CorporationCorporationSheet.php b/app/eveapi/corporation/CorporationCorporationSheet.php new file mode 100644 index 00000000..8314b8b1 --- /dev/null +++ b/app/eveapi/corporation/CorporationCorporationSheet.php @@ -0,0 +1,142 @@ +corpScope + ->CorporationSheet(array('characterID' => $characters[0])); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $corporation_sheet->cached_until, $corporationID)) { + + $corporation_data = \EveCorporationCorporationSheet::where('corporationID', '=', $corporationID)->first(); + + if (!$corporation_data) + $corporation_data = new \EveCorporationCorporationSheet; + + $corporation_data->corporationID = $corporation_sheet->corporationID; + $corporation_data->corporationName = $corporation_sheet->corporationName; + $corporation_data->ticker = $corporation_sheet->ticker; + $corporation_data->ceoID = $corporation_sheet->ceoID; + $corporation_data->ceoName = $corporation_sheet->ceoName; + $corporation_data->stationID = $corporation_sheet->stationID; + $corporation_data->stationName = $corporation_sheet->stationName; + $corporation_data->description = $corporation_sheet->description; + $corporation_data->url = $corporation_sheet->url; + $corporation_data->allianceID = $corporation_sheet->allianceID; + $corporation_data->factionID = $corporation_sheet->factionID; + $corporation_data->allianceName = $corporation_sheet->allianceName; + $corporation_data->taxRate = $corporation_sheet->taxRate; + $corporation_data->memberCount = $corporation_sheet->memberCount; + $corporation_data->memberLimit = $corporation_sheet->memberLimit; + $corporation_data->shares = $corporation_sheet->shares; + $corporation_data->graphicID = $corporation_sheet->logo->graphicID; + $corporation_data->shape1 = $corporation_sheet->logo->shape1; + $corporation_data->shape2 = $corporation_sheet->logo->shape2; + $corporation_data->shape3 = $corporation_sheet->logo->shape3; + $corporation_data->color1 = $corporation_sheet->logo->color1; + $corporation_data->color2 = $corporation_sheet->logo->color2; + $corporation_data->color3 = $corporation_sheet->logo->color3; + $corporation_data->corporationID = $corporation_sheet->corporationID; + $corporation_data->save(); + + // Update the Divisions + foreach ($corporation_sheet->divisions as $division) { + + $division_data = \EveCorporationCorporationSheetDivisions::where('corporationID', '=', $corporationID) + ->where('accountKey', '=', $division->accountKey) + ->first(); + + if (!$division_data) + $division_data = new \EveCorporationCorporationSheetDivisions; + + $division_data->corporationID = $corporationID; + $division_data->accountKey = $division->accountKey; + $division_data->description = $division->description; + $corporation_data->divisions()->save($division_data); + } + + // Update the Wallet Divisions + foreach ($corporation_sheet->walletDivisions as $division) { + + $division_data = \EveCorporationCorporationSheetWalletDivisions::where('corporationID', '=', $corporationID) + ->where('accountKey', '=', $division->accountKey) + ->first(); + + if (!$division_data) + $division_data = new \EveCorporationCorporationSheetWalletDivisions; + + $division_data->corporationID = $corporationID; + $division_data->accountKey = $division->accountKey; + $division_data->description = $division->description; + $corporation_data->walletdivisions()->save($division_data); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $corporation_sheet->cached_until, $corporationID); + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $corporation_sheet; + } +} diff --git a/app/eveapi/corporation/CorporationIndustryJobs.php b/app/eveapi/corporation/CorporationIndustryJobs.php new file mode 100644 index 00000000..69cde1e1 --- /dev/null +++ b/app/eveapi/corporation/CorporationIndustryJobs.php @@ -0,0 +1,126 @@ +corpScope + ->IndustryJobs(array('characterID' => $characters[0])); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $industry_jobs->cached_until, $corporationID)) { + + // Populate the jobs for this character + foreach ($industry_jobs->jobs as $job) { + + $job_data = \EveCorporationIndustryJobs::where('corporationID', '=', $corporationID) + ->where('jobID', '=', $job->jobID) + ->first(); + + if (!$job_data) + $job_data = new \EveCorporationIndustryJobs; + + $job_data->corporationID = $corporationID; + $job_data->jobID = $job->jobID; + $job_data->assemblyLineID = $job->assemblyLineID; + $job_data->containerID = $job->containerID; + $job_data->installedItemID = $job->installedItemID; + $job_data->installedItemLocationID = $job->installedItemLocationID; + $job_data->installedItemQuantity = $job->installedItemQuantity; + $job_data->installedItemProductivityLevel = $job->installedItemProductivityLevel; + $job_data->installedItemMaterialLevel = $job->installedItemMaterialLevel; + $job_data->installedItemLicensedProductionRunsRemaining = $job->installedItemLicensedProductionRunsRemaining; + $job_data->outputLocationID = $job->outputLocationID; + $job_data->installerID = $job->installerID; + $job_data->runs = $job->runs; + $job_data->licensedProductionRuns = $job->licensedProductionRuns; + $job_data->installedInSolarSystemID = $job->installedInSolarSystemID; + $job_data->containerLocationID = $job->containerLocationID; + $job_data->materialMultiplier = $job->materialMultiplier; + $job_data->charMaterialMultiplier = $job->charMaterialMultiplier; + $job_data->timeMultiplier = $job->timeMultiplier; + $job_data->charTimeMultiplier = $job->charTimeMultiplier; + $job_data->installedItemTypeID = $job->installedItemTypeID; + $job_data->outputTypeID = $job->outputTypeID; + $job_data->containerTypeID = $job->containerTypeID; + $job_data->installedItemCopy = $job->installedItemCopy; + $job_data->completed = $job->completed; + $job_data->completedSuccessfully = $job->completedSuccessfully; + $job_data->installedItemFlag = $job->installedItemFlag; + $job_data->outputFlag = $job->outputFlag; + $job_data->activityID = $job->activityID; + $job_data->completedStatus = $job->completedStatus; + $job_data->installTime = $job->installTime; + $job_data->beginProductionTime = $job->beginProductionTime; + $job_data->endProductionTime = $job->endProductionTime; + $job_data->pauseProductionTime = $job->pauseProductionTime; + $job_data->save(); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $industry_jobs->cached_until, $corporationID); + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $industry_jobs; + } +} diff --git a/app/eveapi/corporation/CorporationMarketOrders.php b/app/eveapi/corporation/CorporationMarketOrders.php new file mode 100644 index 00000000..08b8ee96 --- /dev/null +++ b/app/eveapi/corporation/CorporationMarketOrders.php @@ -0,0 +1,109 @@ +corpScope + ->MarketOrders(array('characterID' => $characters[0])); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $market_orders->cached_until, $corporationID)) { + + foreach ($market_orders->orders as $order) { + + $order_data = \EveCorporationMarketOrders::where('corporationID', '=', $corporationID) + ->where('orderID', '=', $order->orderID) + ->first(); + + if (!$order_data) + $order_info = new \EveCorporationMarketOrders; + else + $order_info = $order_data; + + $order_info->corporationID = $corporationID; + $order_info->orderID = $order->orderID; + $order_info->charID = $order->charID; + $order_info->stationID = $order->stationID; + $order_info->volEntered = $order->volEntered; + $order_info->volRemaining = $order->volRemaining; + $order_info->minVolume = $order->minVolume; + $order_info->orderState = $order->orderState; + $order_info->typeID = $order->typeID; + $order_info->range = $order->range; + $order_info->accountKey = $order->accountKey; + $order_info->duration = $order->duration; + $order_info->escrow = $order->escrow; + $order_info->price = $order->price; + $order_info->bid = $order->bid; + $order_info->issued = $order->issued; + $order_info->save(); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $market_orders->cached_until, $corporationID); + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $market_orders; + } +} diff --git a/app/eveapi/corporation/CorporationMedals.php b/app/eveapi/corporation/CorporationMedals.php new file mode 100644 index 00000000..1cca8b0d --- /dev/null +++ b/app/eveapi/corporation/CorporationMedals.php @@ -0,0 +1,97 @@ +corpScope + ->Medals(array('characterID' => $characters[0])); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $medals->cached_until, $corporationID)) { + + foreach ($medals->medals as $medal) { + + $medal_data = \EveCorporationMedals::where('corporationID', '=', $corporationID) + ->where('medalID', '=', $medal->medalID) + ->first(); + + if (!$medal_data) + $medal_data = new \EveCorporationMedals; + + $medal_data->corporationID = $corporationID; + $medal_data->medalID = $medal->medalID; + $medal_data->title = $medal->title; + $medal_data->description = $medal->description; + $medal_data->creatorID = $medal->creatorID; + $medal_data->created = $medal->created; + $medal_data->save(); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $medals->cached_until, $corporationID); + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $medals; + } +} diff --git a/app/eveapi/corporation/CorporationMemberMedals.php b/app/eveapi/corporation/CorporationMemberMedals.php new file mode 100644 index 00000000..80b86f3e --- /dev/null +++ b/app/eveapi/corporation/CorporationMemberMedals.php @@ -0,0 +1,99 @@ +corpScope + ->MemberMedals(array('characterID' => $characters[0])); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $medals->cached_until, $corporationID)) { + + foreach ($medals->issuedMedals as $medal) { + + $medal_data = \EveCorporationMemberMedals::where('corporationID', '=', $corporationID) + ->where('medalID', '=', $medal->medalID) + ->where('characterID', '=', $medal->characterID) + ->first(); + + if (!$medal_data) + $medal_data = new \EveCorporationMemberMedals; + + $medal_data->corporationID = $corporationID; + $medal_data->medalID = $medal->medalID; + $medal_data->characterID = $medal->characterID; + $medal_data->reason = $medal->reason; + $medal_data->status = $medal->status; + $medal_data->issuerID = $medal->issuerID; + $medal_data->issued = $medal->issued; + $medal_data->save(); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $medals->cached_until, $corporationID); + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $medals; + } +} diff --git a/app/eveapi/corporation/CorporationMemberSecurity.php b/app/eveapi/corporation/CorporationMemberSecurity.php new file mode 100644 index 00000000..d8328e92 --- /dev/null +++ b/app/eveapi/corporation/CorporationMemberSecurity.php @@ -0,0 +1,259 @@ +corpScope + ->MemberSecurity(array('characterID' => $characters[0])); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $member_security->cached_until, $corporationID)) { + + foreach ($member_security->members as $security) { + + // Update order: + // a) roles + // b) grantableRoles + // c) rolesAtHQ + // d) grantableRolesAtHQ + // e) rolesAtBase + // f) grantableRolesAtBase + // g) rolesAtOther + // h) grantableRolesAtOther + // i) titles + // + // The roles get deleted, and re-inserted based on the API response. Pretty shit way of + // doing it I guess :< + + // a) Roles Update + \EveCorporationMemberSecurityRoles::where('characterID', '=', $security->characterID) + ->where('corporationID', '=', $corporationID) + ->delete(); + + foreach ($security->roles as $role) { + + $roles_data = new \EveCorporationMemberSecurityRoles; + + $roles_data->characterID = $security->characterID; + $roles_data->corporationID = $corporationID; + $roles_data->name = $security->name; + $roles_data->roleID = $role->roleID; + $roles_data->roleName = $role->roleName; + + $roles_data->save(); + } + + + // b) grantableRoles Update + \EveCorporationMemberSecurityGrantableRoles::where('characterID', '=', $security->characterID) + ->where('corporationID', '=', $corporationID) + ->delete(); + + foreach ($security->grantableRoles as $role) { + + $roles_data = new \EveCorporationMemberSecurityGrantableRoles; + + $roles_data->characterID = $security->characterID; + $roles_data->corporationID = $corporationID; + $roles_data->name = $security->name; + $roles_data->roleID = $role->roleID; + $roles_data->roleName = $role->roleName; + + $roles_data->save(); + } + + // c) rolesAtHQ Update + \EveCorporationMemberSecurityRolesAtHQ::where('characterID', '=', $security->characterID) + ->where('corporationID', '=', $corporationID) + ->delete(); + + foreach ($security->rolesAtHQ as $role) { + + $roles_data = new \EveCorporationMemberSecurityRolesAtHQ; + + $roles_data->characterID = $security->characterID; + $roles_data->corporationID = $corporationID; + $roles_data->name = $security->name; + $roles_data->roleID = $role->roleID; + $roles_data->roleName = $role->roleName; + + $roles_data->save(); + } + + // d) grantableRolesAtHQ Update + \EveCorporationMemberSecurityGrantableRolesAtHQ::where('characterID', '=', $security->characterID) + ->where('corporationID', '=', $corporationID) + ->delete(); + + foreach ($security->grantableRolesAtHQ as $role) { + + $roles_data = new \EveCorporationMemberSecurityGrantableRolesAtHQ; + + $roles_data->characterID = $security->characterID; + $roles_data->corporationID = $corporationID; + $roles_data->name = $security->name; + $roles_data->roleID = $role->roleID; + $roles_data->roleName = $role->roleName; + + $roles_data->save(); + } + + // e) rolesAtBase Update + \EveCorporationMemberSecurityRolesAtBase::where('characterID', '=', $security->characterID) + ->where('corporationID', '=', $corporationID) + ->delete(); + + foreach ($security->rolesAtBase as $role) { + + $roles_data = new \EveCorporationMemberSecurityRolesAtBase; + + $roles_data->characterID = $security->characterID; + $roles_data->corporationID = $corporationID; + $roles_data->name = $security->name; + $roles_data->roleID = $role->roleID; + $roles_data->roleName = $role->roleName; + + $roles_data->save(); + } + + // f) grantableRolesAtBase Update + \EveCorporationMemberSecurityGrantableRolesAtBase::where('characterID', '=', $security->characterID) + ->where('corporationID', '=', $corporationID) + ->delete(); + + foreach ($security->grantableRolesAtBase as $role) { + + $roles_data = new \EveCorporationMemberSecurityGrantableRolesAtBase; + + $roles_data->characterID = $security->characterID; + $roles_data->corporationID = $corporationID; + $roles_data->name = $security->name; + $roles_data->roleID = $role->roleID; + $roles_data->roleName = $role->roleName; + + $roles_data->save(); + } + + // g) rolesAtOther Update + \EveCorporationMemberSecurityRolesAtOther::where('characterID', '=', $security->characterID) + ->where('corporationID', '=', $corporationID) + ->delete(); + + foreach ($security->rolesAtOther as $role) { + + $roles_data = new \EveCorporationMemberSecurityRolesAtOther; + + $roles_data->characterID = $security->characterID; + $roles_data->corporationID = $corporationID; + $roles_data->name = $security->name; + $roles_data->roleID = $role->roleID; + $roles_data->roleName = $role->roleName; + + $roles_data->save(); + } + + // h) grantableRolesAtOther Update + \EveCorporationMemberSecurityGrantableRolesAtOther::where('characterID', '=', $security->characterID) + ->where('corporationID', '=', $corporationID) + ->delete(); + + foreach ($security->grantableRolesAtOther as $role) { + + $roles_data = new \EveCorporationMemberSecurityGrantableRolesAtOther; + + $roles_data->characterID = $security->characterID; + $roles_data->corporationID = $corporationID; + $roles_data->name = $security->name; + $roles_data->roleID = $role->roleID; + $roles_data->roleName = $role->roleName; + + $roles_data->save(); + } + + // i) titles Update + \EveCorporationMemberSecurityTitles::where('characterID', '=', $security->characterID) + ->where('corporationID', '=', $corporationID) + ->delete(); + + foreach ($security->titles as $role) { + + $roles_data = new \EveCorporationMemberSecurityTitles; + + $roles_data->characterID = $security->characterID; + $roles_data->corporationID = $corporationID; + $roles_data->name = $security->name; + $roles_data->titleID = $role->titleID; + $roles_data->titleName = $role->titleName; + + $roles_data->save(); + } + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $member_security->cached_until, $corporationID); + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $member_security; + } +} diff --git a/app/eveapi/corporation/CorporationMemberSecurityLog.php b/app/eveapi/corporation/CorporationMemberSecurityLog.php new file mode 100644 index 00000000..52f3172f --- /dev/null +++ b/app/eveapi/corporation/CorporationMemberSecurityLog.php @@ -0,0 +1,122 @@ +corpScope + ->MemberSecurityLog(array('characterID' => $characters[0])); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $member_security_log->cached_until, $corporationID)) { + + foreach ($member_security_log->roleHistory as $log) { + + // Generate a log hash to lookup + $loghash = md5(implode(',', array($log->changeTime, $log->characterID, $log->roleLocationType))); + + $log_data = \EveCorporationMemberSecurityLog::where('hash', '=', $loghash) + ->first(); + + if (!$log_data) + $log_data = new \EveCorporationMemberSecurityLog; + else + // We already have this log entry recorded, so just move along + continue; + + // Record the log entry + $log_data->corporationID = $corporationID; + $log_data->characterID = $log->characterID; + $log_data->characterName = $log->characterName; + $log_data->changeTime = $log->changeTime; + $log_data->issuerID = $log->issuerID; + $log_data->issuerName = $log->issuerName; + $log_data->roleLocationType = $log->roleLocationType; + $log_data->hash = $loghash; + $log_data->save(); + + // Generate the oldRoles & newRoles entries. Well just make some + // lazy ass json entries. + $oldRoles = array(); + foreach ($log->oldRoles as $entry) + $oldRoles[$entry->roleID] = $entry->roleName; + + $newRoles = array(); + foreach ($log->newRoles as $entry) + $newRoles[$entry->roleID] = $entry->roleName; + + // Save the log details + $entry_data = new \EveCorporationMemberSecurityLogDetails; + $entry_data->hash = $loghash; + $entry_data->oldRoles = json_encode($oldRoles); + $entry_data->newRoles = json_encode($newRoles); + $log_data->details()->save($entry_data); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $member_security_log->cached_until, $corporationID); + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $member_security_log; + } +} diff --git a/app/eveapi/corporation/CorporationMemberTracking.php b/app/eveapi/corporation/CorporationMemberTracking.php new file mode 100644 index 00000000..6e596a51 --- /dev/null +++ b/app/eveapi/corporation/CorporationMemberTracking.php @@ -0,0 +1,109 @@ +corpScope + ->MemberTracking(array('characterID' => $characters[0], 'extended' => 1)); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $member_tracking->cached_until, $corporationID)) { + + foreach ($member_tracking->members as $member) { + + //TODO: Start an array to delete old members + + $member_data = \EveCorporationMemberTracking::where('characterID', '=', $member->characterID) + ->where('corporationID', '=', $corporationID) + ->first(); + + if (!$member_data) + $member_data = new \EveCorporationMemberTracking; + + $member_data->characterID = $member->characterID; + $member_data->corporationID = $corporationID; + $member_data->name = $member->name; + $member_data->startDateTime = $member->startDateTime; + $member_data->baseID = $member->baseID; + $member_data->base = $member->base; + $member_data->title = $member->title; + $member_data->logonDateTime = $member->logonDateTime; + $member_data->logoffDateTime = $member->logoffDateTime; + $member_data->locationID = $member->locationID; + $member_data->location = $member->location; + $member_data->shipTypeID = $member->shipTypeID; + $member_data->shipType = $member->shipType; + $member_data->roles = $member->roles; + $member_data->grantableRoles = $member->grantableRoles; + + $member_data->save(); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $member_tracking->cached_until, $corporationID); + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $member_tracking; + } +} diff --git a/app/eveapi/corporation/CorporationShareholders.php b/app/eveapi/corporation/CorporationShareholders.php new file mode 100644 index 00000000..a38690d3 --- /dev/null +++ b/app/eveapi/corporation/CorporationShareholders.php @@ -0,0 +1,114 @@ +corpScope + ->Shareholders(array('characterID' => $characters[0])); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $shareholders->cached_until, $corporationID)) { + + // Characters & Corporations can be share holders. Record both + foreach ($shareholders->characters as $holder) { + + $holder_data = \EveCorporationShareholderCharacters::where('shareholderID', '=', $holder->shareholderID) + ->where('corporationID', '=', $corporationID) + ->first(); + + if (!$holder_data) + $holder_data = new \EveCorporationShareholderCharacters; + + $holder_data->corporationID = $corporationID; + $holder_data->shareholderID = $holder->shareholderID; + $holder_data->shareholderName = $holder->shareholderName; + $holder_data->shareholderCorporationID = $holder->shareholderCorporationID; + $holder_data->shareholderCorporationName = $holder->shareholderCorporationName; + $holder_data->shares = $holder->shares; + $holder_data->save(); + } + + foreach ($shareholders->corporations as $holder) { + + $holder_data = \EveCorporationShareholderCorporations::where('shareholderID', '=', $holder->shareholderID) + ->where('corporationID', '=', $corporationID) + ->first(); + + if (!$holder_data) + $holder_data = new \EveCorporationShareholderCorporations; + + $holder_data->corporationID = $corporationID; + $holder_data->shareholderID = $holder->shareholderID; + $holder_data->shareholderName = $holder->shareholderName; + $holder_data->shares = $holder->shares; + $holder_data->save(); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $shareholders->cached_until, $corporationID); + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $shareholders; + } +} diff --git a/app/eveapi/corporation/CorporationStandings.php b/app/eveapi/corporation/CorporationStandings.php new file mode 100644 index 00000000..d91467fa --- /dev/null +++ b/app/eveapi/corporation/CorporationStandings.php @@ -0,0 +1,130 @@ +corpScope + ->Standings(array('characterID' => $characters[0])); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $standings->cached_until, $corporationID)) { + + // Populate the agents standings + foreach ($standings->corporationNPCStandings->agents as $standing) { + + $standing_data = \EveCorporationStandingsAgents::where('corporationID', '=', $corporationID) + ->where('fromID', '=', $standing->fromID) + ->first(); + + if (!$standing_data) + $standing_data = new \EveCorporationStandingsAgents; + + $standing_data->corporationID = $corporationID; + $standing_data->fromID = $standing->fromID; + $standing_data->fromName = $standing->fromName; + $standing_data->standing = $standing->standing; + $standing_data->save(); + } + + // Populate the faction standings + foreach ($standings->corporationNPCStandings->factions as $standing) { + + $standing_data = \EveCorporationStandingsFactions::where('corporationID', '=', $corporationID) + ->where('fromID', '=', $standing->fromID) + ->first(); + + if (!$standing_data) + $standing_data = new \EveCorporationStandingsFactions; + + $standing_data->corporationID = $corporationID; + $standing_data->fromID = $standing->fromID; + $standing_data->fromName = $standing->fromName; + $standing_data->standing = $standing->standing; + $standing_data->save(); + } + + // Populate the NPCCorporation standings + foreach ($standings->corporationNPCStandings->NPCCorporations as $standing) { + + $standing_data = \EveCorporationStandingsNPCCorporations::where('corporationID', '=', $corporationID) + ->where('fromID', '=', $standing->fromID) + ->first(); + + if (!$standing_data) + $standing_data = new \EveCorporationStandingsNPCCorporations; + + $standing_data->corporationID = $corporationID; + $standing_data->fromID = $standing->fromID; + $standing_data->fromName = $standing->fromName; + $standing_data->standing = $standing->standing; + $standing_data->save(); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $standings->cached_until, $corporationID); + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $standings; + } +} diff --git a/app/eveapi/corporation/CorporationStarbaseDetail.php b/app/eveapi/corporation/CorporationStarbaseDetail.php new file mode 100644 index 00000000..7467a19e --- /dev/null +++ b/app/eveapi/corporation/CorporationStarbaseDetail.php @@ -0,0 +1,111 @@ +get() as $starbase) { + + // Do the actual API call. pheal-ng actually handles some internal + // caching too. + try { + + $starbase_detail = $pheal + ->corpScope + ->StarbaseDetail(array('characterID' => $characters[0], 'itemID' => $starbase->itemID)); + + } catch (\Pheal\Exceptions\APIException $e) { + + // In the odd chance that we get a old/invalid ID, catch only that error + // else go boom + if ($e->getCode() <> 114) + throw $e; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Update the details + $starbase_data = \EveCorporationStarbaseDetail::where('corporationID', '=', $corporationID) + ->where('itemID', '=', $starbase->itemID) + ->first(); + + if (!$starbase_data) + $starbase_data = new \EveCorporationStarbaseDetail; + + $starbase_data->corporationID = $corporationID; + $starbase_data->itemID = $starbase->itemID; // Fromt he outer loop + $starbase_data->state = $starbase_detail->state; + $starbase_data->stateTimestamp = $starbase_detail->stateTimestamp; + $starbase_data->onlineTimestamp = $starbase_detail->onlineTimestamp; + $starbase_data->usageFlags = $starbase_detail->generalSettings->usageFlags; + $starbase_data->deployFlags = $starbase_detail->generalSettings->deployFlags; + $starbase_data->allowCorporationMembers = $starbase_detail->generalSettings->allowCorporationMembers; + $starbase_data->allowAllianceMembers = $starbase_detail->generalSettings->allowAllianceMembers; + $starbase_data->useStandingsFrom = $starbase_detail->combatSettings->useStandingsFrom->ownerID; + $starbase_data->onStandingDrop = $starbase_detail->combatSettings->onStandingDrop->standing; + $starbase_data->onStatusDropEnabled = $starbase_detail->combatSettings->onStatusDrop->enabled; + $starbase_data->onStatusDropStanding = $starbase_detail->combatSettings->onStatusDrop->standing; + $starbase_data->onAggression = $starbase_detail->combatSettings->onAggression->enabled; + $starbase_data->onCorporationWar = $starbase_detail->combatSettings->onCorporationWar->enabled; + + // Add the fuel + foreach ($starbase_detail->fuel as $fuel) { + + if ($fuel->typeID == 16275) + $starbase_data->strontium = $fuel->quantity; + else + $starbase_data->fuelBlocks = $fuel->quantity; + } + + $starbase_data->save(); + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return null; + } +} diff --git a/app/eveapi/corporation/CorporationStarbaseList.php b/app/eveapi/corporation/CorporationStarbaseList.php new file mode 100644 index 00000000..9c2d0ee1 --- /dev/null +++ b/app/eveapi/corporation/CorporationStarbaseList.php @@ -0,0 +1,130 @@ +corpScope + ->StarbaseList(array('characterID' => $characters[0])); + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $starbase_list->cached_until, $corporationID)) { + + + // So for this call I dont think we should just trash all of the posses and their + // details. Instead, cause I'm bad, well get all of the current posses for the corp + // and delete the values that we know of. The resulting array will be the ones we delete + // as they are probably removed/killed posses + $old_starbases = array(); + foreach (\EveCorporationStarbaseList::where('corporationID', '=', $corporationID)->get() as $item) + $old_starbases[] = $item->itemID; + + // Arrayflip hax to get the starbaseID's as keys + $old_starbases = array_flip($old_starbases); // <-- help a noob please :< + + // Next, loop over the starbases from the API and populate/update the db + foreach ($starbase_list->starbases as $starbase) { + + $starbase_data = \EveCorporationStarbaseList::where('corporationID', '=', $corporationID) + ->where('itemID', '=', $starbase->itemID) + ->first(); + + if (!$starbase_data) + $starbase_data = new \EveCorporationStarbaseList; + + $starbase_data->corporationID = $corporationID; + $starbase_data->itemID = $starbase->itemID; + $starbase_data->typeID = $starbase->typeID; + $starbase_data->locationID = $starbase->locationID; + $starbase_data->moonID = $starbase->moonID; + $starbase_data->state = $starbase->state; + $starbase_data->stateTimestamp = $starbase->stateTimestamp; + $starbase_data->onlineTimestamp = $starbase->onlineTimestamp; + $starbase_data->standingOwnerID = $starbase->standingOwnerID; + $starbase_data->save(); + + // Update the old_starbases list by removing the ones that still + // exist + if (array_key_exists($starbase->itemID, $old_starbases)) + unset($old_starbases[$starbase->itemID]); + } + + // Delete old starbases if there are any + if (count($old_starbases) > 0) { + + // Delete the old starbase... + foreach (array_flip($old_starbases) as $starbase_id) + \EveCorporationStarbaseList::where('itemID', '=', $starbase_id)->delete(); + + // ... and its details + foreach (array_flip($old_starbases) as $starbase_id) + \EveCorporationStarbaseDetail::where('itemID', '=', $starbase_id)->delete(); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $starbase_list->cached_until, $corporationID); + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $starbase_list; + } +} diff --git a/app/eveapi/corporation/CorporationWalletJournal.php b/app/eveapi/corporation/CorporationWalletJournal.php new file mode 100644 index 00000000..d36667bd --- /dev/null +++ b/app/eveapi/corporation/CorporationWalletJournal.php @@ -0,0 +1,144 @@ +get() as $walletdivision) { + + // Start a infinite loop for the Journal Walking. We will break out of this once + // we have reached the end of the records that we can get + + // TODO: This needs a lot more brain thingies applied in order to figure out how + // we are going to go about the database cached_untill timer. For now, we will just + // ignore the DB level one and rely entirely on pheal-ng to cache the XML's + + $first_request = true; + $from_id = 9223372036854775807; // Max integer for 64bit PHP + while (true) { + + // Do the actual API call. pheal-ng actually handles some internal + // caching too. + try { + + if ($first_request) { + + $wallet_journal = $pheal + ->corpScope + ->WalletJournal(array('characterID' => $characters[0], 'rowCount' => $row_count, 'accountKey' => $walletdivision->accountKey)); + + // flip the first_request as those that get processed from here need to be from the `fromID` + $first_request = false; + + } else { + + $wallet_journal = $pheal + ->corpScope + ->WalletJournal(array('characterID' => $characters[0], 'rowCount' => $row_count, 'accountKey'=> $walletdivision->accountKey, 'fromID' => $from_id)); + } + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Process the transactions + foreach ($wallet_journal->entries as $transaction) { + + // Ensure that $from_id is at its lowest + $from_id = min($transaction->refID, $from_id); + + // Generate a transaction hash. It would seem that refID's could possibly be cycled. + $transaction_hash = md5(implode(',', array($corporationID, $walletdivision->accountKey, $transaction->date, $transaction->ownerID1, $transaction->refID))); + + $transaction_data = \EveCorporationWalletJournal::where('corporationID', '=', $corporationID) + ->where('hash', '=', $transaction_hash) + ->first(); + + if (!$transaction_data) + $transaction_data = new \EveCorporationWalletJournal; + else + continue; + + $transaction_data->corporationID = $corporationID; + $transaction_data->hash = $transaction_hash; + $transaction_data->accountKey = $walletdivision->accountKey; // From the outer foreach + $transaction_data->refID = $transaction->refID; + $transaction_data->date = $transaction->date; + $transaction_data->refTypeID = $transaction->refTypeID; + $transaction_data->ownerName1 = $transaction->ownerName1; + $transaction_data->ownerID1 = $transaction->ownerID1; + $transaction_data->ownerName2 = $transaction->ownerName2; + $transaction_data->ownerID2 = $transaction->ownerID2; + $transaction_data->argName1 = $transaction->argName1; + $transaction_data->argID1 = $transaction->argID1; + $transaction_data->amount = $transaction->amount; + $transaction_data->balance = $transaction->balance; + $transaction_data->reason = $transaction->reason; + $transaction_data->owner1TypeID = $transaction->owner1TypeID; + $transaction_data->owner2TypeID = $transaction->owner2TypeID; + $transaction_data->save(); + } + + // Check how many entries we got back. If it us less that $row_count, we know we have + // walked back the entire journal + if (count($wallet_journal->entries) < $row_count) + break; // Break the while loop + } + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $wallet_journal; + } +} diff --git a/app/eveapi/corporation/CorporationWalletTransactions.php b/app/eveapi/corporation/CorporationWalletTransactions.php new file mode 100644 index 00000000..e5f934e0 --- /dev/null +++ b/app/eveapi/corporation/CorporationWalletTransactions.php @@ -0,0 +1,144 @@ +get() as $walletdivision) { + + // Start a infinite loop for the Journal Walking. We will break out of this once + // we have reached the end of the records that we can get + + // TODO: This needs a lot more brain thingies applied in order to figure out how + // we are going to go about the database cached_untill timer. For now, we will just + // ignore the DB level one and rely entirely on pheal-ng to cache the XML's + + $first_request = true; + $from_id = 9223372036854775807; // Max integer for 64bit PHP + while (true) { + + // Do the actual API call. pheal-ng actually handles some internal + // caching too. + try { + + if ($first_request) { + + $wallet_transactions = $pheal + ->corpScope + ->WalletTransactions(array('characterID' => $characters[0], 'rowCount' => $row_count, 'accountKey' => $walletdivision->accountKey)); + + // flip the first_request as those that get processed from here need to be from the `fromID` + $first_request = false; + + } else { + + $wallet_transactions = $pheal + ->corpScope + ->WalletTransactions(array('characterID' => $characters[0], 'rowCount' => $row_count, 'accountKey'=> $walletdivision->accountKey, 'fromID' => $from_id)); + } + + } catch (\Pheal\Exceptions\APIException $e) { + + // If we cant get account status information, prevent us from calling + // this API again + BaseApi::banCall($api, $scope, $keyID, 0, $e->getCode() . ': ' . $e->getMessage()); + return; + + } catch (\Pheal\Exceptions\PhealException $e) { + + throw $e; + } + + // Process the transactions + foreach ($wallet_transactions->transactions as $transaction) { + + // Ensure that $from_id is at its lowest + $from_id = min($transaction->transactionID, $from_id); + + // Generate a transaction hash. It would seem that refID's could possibly be cycled. + $transaction_hash = md5(implode(',', array($corporationID, $walletdivision->accountKey, $transaction->transactionDateTime, $transaction->clientID, $transaction->transactionID))); + + $transaction_data = \EveCorporationWalletTransactions::where('corporationID', '=', $corporationID) + ->where('hash', '=', $transaction_hash) + ->first(); + + if (!$transaction_data) + $transaction_data = new \EveCorporationWalletTransactions; + else + continue; + + $transaction_data->corporationID = $corporationID; + $transaction_data->hash = $transaction_hash; + $transaction_data->accountKey = $walletdivision->accountKey; + $transaction_data->transactionID = $transaction->transactionID; + $transaction_data->transactionDateTime = $transaction->transactionDateTime; + $transaction_data->quantity = $transaction->quantity; + $transaction_data->typeName = $transaction->typeName; + $transaction_data->typeID = $transaction->typeID; + $transaction_data->price = $transaction->price; + $transaction_data->clientID = $transaction->clientID; + $transaction_data->clientName = $transaction->clientName; + $transaction_data->stationID = $transaction->stationID; + $transaction_data->stationName = $transaction->stationName; + $transaction_data->transactionType = $transaction->transactionType; + $transaction_data->transactionFor = $transaction->transactionFor; + $transaction_data->journalTransactionID = $transaction->journalTransactionID; + $transaction_data->clientTypeID = $transaction->clientTypeID; + $transaction_data->save(); + } + + // Check how many entries we got back. If it us less that $row_count, we know we have + // walked back the entire journal + if (count($wallet_transactions->transactions) < $row_count) + break; // Break the while loop + } + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $wallet_transactions; + } +} diff --git a/app/eveapi/eve/EveAllianceList.php b/app/eveapi/eve/EveAllianceList.php new file mode 100644 index 00000000..f55660af --- /dev/null +++ b/app/eveapi/eve/EveAllianceList.php @@ -0,0 +1,75 @@ +eveScope + ->AllianceList(); + + } catch (Exception $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $alliance_list->cached_until)) { + + // Really crappy method to do this I guess. But oh well. + \EveEveAllianceListMemberCorporations::truncate(); + + foreach ($alliance_list->alliances as $alliance) { + + $alliance_check = \EveEveAllianceList::where('allianceID', '=', $alliance->allianceID)->first(); + + if (!$alliance_check) + $alliance_data = new \EveEveAllianceList; + else + $alliance_data = $alliance_check; + + $alliance_data->name = $alliance->name; + $alliance_data->shortName = $alliance->shortName; + $alliance_data->allianceID = $alliance->allianceID; + $alliance_data->executorCorpID = $alliance->executorCorpID; + $alliance_data->memberCount = $alliance->memberCount; + $alliance_data->startDate = $alliance->startDate; + $alliance_data->save(); + + $alliance_data->save(); + + // And repopulate the current members + foreach ($alliance->memberCorporations as $corporation) { + + $member_corp = new \EveEveAllianceListMemberCorporations; + $member_corp->corporationID = $corporation->corporationID; + $member_corp->startDate = $corporation->startDate; + $alliance_data->members()->save($member_corp); + } + } + + // Set the cached entry time + BaseApi::setDbCache($scope, $api, $alliance_list->cached_until); + } + + return $alliance_list; + } +} diff --git a/app/eveapi/eve/EveCharacterInfo.php b/app/eveapi/eve/EveCharacterInfo.php new file mode 100644 index 00000000..6cdef9cf --- /dev/null +++ b/app/eveapi/eve/EveCharacterInfo.php @@ -0,0 +1,100 @@ +eveScope + ->CharacterInfo(array('characterID' => $characterID)); + + } catch (Exception $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $character_info->cached_until, $characterID)) { + + // Update the \EveEveCharacterInfo + $character_check = \EveEveCharacterInfo::where('characterID', '=', $character_info->characterID)->first(); + + if (!$character_check) + $character = new \EveEveCharacterInfo; + else + $character = $character_check; + + $character->characterID = $character_info->characterID; + $character->characterName = $character_info->characterName; + $character->race = $character_info->race; + $character->bloodline = $character_info->bloodline; + + $character->accountBalance = $character_info->accountBalance; + $character->skillPoints = $character_info->skillPoints; + $character->nextTrainingEnds = $character_info->nextTrainingEnds; + $character->shipName = $character_info->shipName; + $character->shipTypeID = $character_info->shipTypeID; + $character->shipTypeName = $character_info->shipTypeName; + + $character->corporationID = $character_info->corporationID; + $character->corporation = $character_info->corporation; + $character->corporationDate = $character_info->corporationDate; + $character->allianceID = $character_info->allianceID; + $character->alliance = $character_info->alliance; + $character->allianceDate = $character_info->allianceDate; + + $character->lastKnownLocation = $character_info->lastKnownLocation; + + $character->securityStatus = $character_info->securityStatus; + $character->save(); + + // Update \EveEveCharacterInfoEmploymentHistory + foreach ($character_info->employmentHistory as $employment) { + + $employment_record_check = $character->employment()->where('recordID', '=', $employment->recordID)->first(); + + if (!$employment_record_check) + $employment_entry = new \EveEveCharacterInfoEmploymentHistory; + else + $employment_entry = $employment_record_check; + + $employment_entry->recordID = $employment->recordID; + $employment_entry->corporationID = $employment->corporationID; + $employment_entry->startDate = $employment->startDate; + + // Add/update the emplyment entry for this character + $character->employment()->save($employment_entry); + } + + // Set the cached entry time + BaseApi::setDbCache($scope, $api, $character_info->cached_until, $characterID); + } + + return $character_info; + } +} diff --git a/app/eveapi/eve/EveConquerableStationList.php b/app/eveapi/eve/EveConquerableStationList.php new file mode 100644 index 00000000..6d6c2d46 --- /dev/null +++ b/app/eveapi/eve/EveConquerableStationList.php @@ -0,0 +1,62 @@ +eveScope + ->ConquerableStationList(); + + } catch (Exception $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $station_list->cached_until)) { + + // Update the Database while we loop over the results + foreach ($station_list->outposts as $outpost) { + + // Check if we need to update || insert + $outpost_check = \EveEveConquerableStationList::where('stationID', '=', $outpost->stationID)->first(); + + if (!$outpost_check) + $outpost_data = new \EveEveConquerableStationList; + else + $outpost_data = $outpost_check; + + $outpost_data->stationID = $outpost->stationID; + $outpost_data->stationName = $outpost->stationName; + $outpost_data->stationTypeID = $outpost->stationTypeID; + $outpost_data->solarSystemID = $outpost->solarSystemID; + $outpost_data->corporationID = $outpost->corporationID; + $outpost_data->corporationName = $outpost->corporationName; + $outpost_data->save(); + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $station_list->cached_until); + } + } + return $station_list; + } +} diff --git a/app/eveapi/eve/EveErrorList.php b/app/eveapi/eve/EveErrorList.php new file mode 100644 index 00000000..bd7f46d4 --- /dev/null +++ b/app/eveapi/eve/EveErrorList.php @@ -0,0 +1,59 @@ +eveScope + ->ErrorList(); + + } catch (Exception $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $error_list->cached_until)) { + + // Update the Database while we loop over the solarSystem results + foreach ($error_list->errors as $error) { + + // Find the system to check if we need to update || insert + $error_check = \EveEveErrorList::where('errorCode', '=', $error->errorCode)->first(); + + if (!$error_check) + $error_data = new \EveEveErrorList; + else + $error_data = $error_check; + + // Update the system + $error_data->errorCode = $error->errorCode; + $error_data->errorText = $error->errorText; + $error_data->save(); + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $error_list->cached_until); + } + } + return $error_list; + } +} diff --git a/app/eveapi/eve/EveRefTypes.php b/app/eveapi/eve/EveRefTypes.php new file mode 100644 index 00000000..3de7dcd3 --- /dev/null +++ b/app/eveapi/eve/EveRefTypes.php @@ -0,0 +1,59 @@ +eveScope + ->RefTypes(); + + } catch (Exception $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $ref_types->cached_until)) { + + // Update the Database while we loop over the results + foreach ($ref_types->refTypes as $ref_type) { + + // Check if we need to update || insert + $type_check = \EveEveRefTypes::where('refTypeID', '=', $ref_type->refTypeID)->first(); + + if (!$type_check) + $type_data = new \EveEveRefTypes; + else + $type_data = $type_check; + + // Update the system + $type_data->refTypeID = $ref_type->refTypeID; + $type_data->refTypeName = $ref_type->refTypeName; + $type_data->save(); + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $ref_types->cached_until); + } + } + return $ref_types; + } +} diff --git a/app/eveapi/map/MapJumps.php b/app/eveapi/map/MapJumps.php new file mode 100644 index 00000000..6066fe4a --- /dev/null +++ b/app/eveapi/map/MapJumps.php @@ -0,0 +1,59 @@ +mapScope + ->Jumps(); + + } catch (Exception $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $jumps->cached_until)) { + + // Update the Database while we loop over the solarSystem results + foreach ($jumps->solarSystems as $solarSystem) { + + // Find the system to check if we need to update || insert + $system = \EveMapJumps::where('solarSystemID', '=', $solarSystem->solarSystemID)->first(); + + if (!$system) + $system_data = new \EveMapJumps; + else + $system_data = $system; + + // Update the system_data + $system_data->solarSystemID = $solarSystem->solarSystemID; + $system_data->shipJumps = $solarSystem->shipJumps; + $system_data->save(); + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $jumps->cached_until); + } + } + return $jumps; + } +} diff --git a/app/eveapi/map/MapKills.php b/app/eveapi/map/MapKills.php new file mode 100644 index 00000000..4ac67ce6 --- /dev/null +++ b/app/eveapi/map/MapKills.php @@ -0,0 +1,61 @@ +mapScope + ->Kills(); + + } catch (Exception $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $kills->cached_until)) { + + // Update the Database while we loop over the solarSystem results + foreach ($kills->solarSystems as $solarSystem) { + + // Find the system to check if we need to update || insert + $system = \EveMapKills::where('solarSystemID', '=', $solarSystem->solarSystemID)->first(); + + if (!$system) + $system_data = new \EveMapKills; + else + $system_data = $system; + + // Update the system + $system_data->solarSystemID = $solarSystem->solarSystemID; + $system_data->shipKills = $solarSystem->shipKills; + $system_data->factionKills = $solarSystem->factionKills; + $system_data->podKills = $solarSystem->podKills; + $system_data->save(); + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $kills->cached_until); + } + } + return $kills; + } +} diff --git a/app/eveapi/map/MapSovereignty.php b/app/eveapi/map/MapSovereignty.php new file mode 100644 index 00000000..d1fef307 --- /dev/null +++ b/app/eveapi/map/MapSovereignty.php @@ -0,0 +1,63 @@ +mapScope + ->Sovereignty(); + + } catch (Exception $e) { + + throw $e; + } + + // Check if the data in the database is still considered up to date. + // checkDbCache will return true if this is the case + if (!BaseApi::checkDbCache($scope, $api, $sovereignty->cached_until)) { + + // Update the Database while we loop over the solarSystem results + foreach ($sovereignty->solarSystems as $solarSystem) { + + // Find the system to check if we need to update || insert + $system = \EveMapSovereignty::where('solarSystemID', '=', $solarSystem->solarSystemID)->first(); + + if (!$system) + $system_data = new \EveMapSovereignty; + else + $system_data = $system; + + // Update the system + $system_data->solarSystemID = $solarSystem->solarSystemID; + $system_data->allianceID = $solarSystem->allianceID; + $system_data->factionID = $solarSystem->factionID; + $system_data->solarSystemName = $solarSystem->solarSystemName; + $system_data->corporationID = $solarSystem->corporationID; + $system_data->save(); + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $sovereignty->cached_until); + } + } + + return $sovereignty; + } +} diff --git a/app/eveapi/server/ServerServerStatus.php b/app/eveapi/server/ServerServerStatus.php new file mode 100644 index 00000000..6e82add8 --- /dev/null +++ b/app/eveapi/server/ServerServerStatus.php @@ -0,0 +1,69 @@ +serverScope + ->ServerStatus(); + + } catch (Exception $e) { + + throw $e; + } + + if (!BaseApi::checkDbCache($scope, $api, $server_status->cached_until)) { + + // Update the Database + $existing_status = \EveServerServerStatus::find(1); + + if (isset($existing_status)) { + + // Update the ServerStatus + $existing_status->currentTime = $server_status->request_time; + $existing_status->serverOpen = $server_status->serverOpen; + $existing_status->onlinePlayers = $server_status->onlinePlayers; + $existing_status->save(); + + } else { + + // Create a ServerStatus entry + \EveServerServerStatus::create(array( + 'currentTime' => $server_status->request_time, + 'serverOpen' => $server_status->serverOpen, + 'onlinePlayers' => $server_status->onlinePlayers + )); + } + + // Update the cached_until time in the database for this api call + BaseApi::setDbCache($scope, $api, $server_status->cached_until); + } + + // Unlock the call + BaseApi::unlockCall($lockhash); + + return $server_status; + } +} \ No newline at end of file diff --git a/app/filters.php b/app/filters.php new file mode 100644 index 00000000..55673025 --- /dev/null +++ b/app/filters.php @@ -0,0 +1,95 @@ +with('warning', 'Please Sign In first to continue'); +}); + + +Route::filter('auth.basic', function() +{ + return Auth::basic(); +}); + +/* +|-------------------------------------------------------------------------- +| Guest Filter +|-------------------------------------------------------------------------- +| +| The "guest" filter is the counterpart of the authentication filters as +| it simply checks that the current user is not logged in. A redirect +| response will be issued if they are, which you may freely change. +| +*/ + +Route::filter('guest', function() +{ + if (Auth::check()) return Redirect::to('/'); +}); + +/* +|-------------------------------------------------------------------------- +| CSRF Protection Filter +|-------------------------------------------------------------------------- +| +| The CSRF filter is responsible for protecting your application against +| cross-site request forgery attacks. If this special token in a user +| session does not match the one given in this request, we'll bail. +| +*/ + +Route::filter('csrf', function() +{ + + // Check ajax requests for token validity via the header. + // app.js has the code to grab form tokens and put it in + // a header, well validate it here if its a post AJAX + if (Request::ajax() && Request::getMethod() == 'POST') + { + if (Session::getToken() != Request::header('X-CSRF-Token')) + { + throw new Illuminate\Session\TokenMismatchException; + } + + } else { + if (Request::getMethod() == 'POST' && Session::token() != Input::get('_token')) + { + throw new Illuminate\Session\TokenMismatchException; + } + } +}); diff --git a/app/lang/en/pagination.php b/app/lang/en/pagination.php new file mode 100644 index 00000000..eb9be3ba --- /dev/null +++ b/app/lang/en/pagination.php @@ -0,0 +1,20 @@ + '« Previous', + + 'next' => 'Next »', + +); \ No newline at end of file diff --git a/app/lang/en/reminders.php b/app/lang/en/reminders.php new file mode 100644 index 00000000..e42148e9 --- /dev/null +++ b/app/lang/en/reminders.php @@ -0,0 +1,24 @@ + "Passwords must be at least six characters and match the confirmation.", + + "user" => "We can't find a user with that e-mail address.", + + "token" => "This password reset token is invalid.", + + "sent" => "Password reminder sent!", + +); diff --git a/app/lang/en/validation.php b/app/lang/en/validation.php new file mode 100644 index 00000000..94823021 --- /dev/null +++ b/app/lang/en/validation.php @@ -0,0 +1,98 @@ + "The :attribute must be accepted.", + "active_url" => "The :attribute is not a valid URL.", + "after" => "The :attribute must be a date after :date.", + "alpha" => "The :attribute may only contain letters.", + "alpha_dash" => "The :attribute may only contain letters, numbers, and dashes.", + "alpha_num" => "The :attribute may only contain letters and numbers.", + "array" => "The :attribute must be an array.", + "before" => "The :attribute must be a date before :date.", + "between" => array( + "numeric" => "The :attribute must be between :min and :max.", + "file" => "The :attribute must be between :min and :max kilobytes.", + "string" => "The :attribute must be between :min and :max characters.", + "array" => "The :attribute must have between :min and :max items.", + ), + "confirmed" => "The :attribute confirmation does not match.", + "date" => "The :attribute is not a valid date.", + "date_format" => "The :attribute does not match the format :format.", + "different" => "The :attribute and :other must be different.", + "digits" => "The :attribute must be :digits digits.", + "digits_between" => "The :attribute must be between :min and :max digits.", + "email" => "The :attribute format is invalid.", + "exists" => "The selected :attribute is invalid.", + "image" => "The :attribute must be an image.", + "in" => "The selected :attribute is invalid.", + "integer" => "The :attribute must be an integer.", + "ip" => "The :attribute must be a valid IP address.", + "max" => array( + "numeric" => "The :attribute may not be greater than :max.", + "file" => "The :attribute may not be greater than :max kilobytes.", + "string" => "The :attribute may not be greater than :max characters.", + "array" => "The :attribute may not have more than :max items.", + ), + "mimes" => "The :attribute must be a file of type: :values.", + "min" => array( + "numeric" => "The :attribute must be at least :min.", + "file" => "The :attribute must be at least :min kilobytes.", + "string" => "The :attribute must be at least :min characters.", + "array" => "The :attribute must have at least :min items.", + ), + "not_in" => "The selected :attribute is invalid.", + "numeric" => "The :attribute must be a number.", + "regex" => "The :attribute format is invalid.", + "required" => "The :attribute field is required.", + "required_if" => "The :attribute field is required when :other is :value.", + "required_with" => "The :attribute field is required when :values is present.", + "required_without" => "The :attribute field is required when :values is not present.", + "same" => "The :attribute and :other must match.", + "size" => array( + "numeric" => "The :attribute must be :size.", + "file" => "The :attribute must be :size kilobytes.", + "string" => "The :attribute must be :size characters.", + "array" => "The :attribute must contain :size items.", + ), + "unique" => "The :attribute has already been taken.", + "url" => "The :attribute format is invalid.", + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => array(), + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => array(), + +); diff --git a/app/models/Elegant.php b/app/models/Elegant.php new file mode 100644 index 00000000..09ecd0bd --- /dev/null +++ b/app/models/Elegant.php @@ -0,0 +1,30 @@ +rules); + + // check for failure + if ($v->fails()) + { + // set errors and return false + $this->errors = $v->errors; + return false; + } + + // validation pass + return true; + } + + public function errors() + { + return $this->errors; + } +} \ No newline at end of file diff --git a/app/models/EveAccountAPIKeyInfo.php b/app/models/EveAccountAPIKeyInfo.php new file mode 100644 index 00000000..22d6f745 --- /dev/null +++ b/app/models/EveAccountAPIKeyInfo.php @@ -0,0 +1,24 @@ +hasMany('EveAccountAPIKeyInfoCharacters', 'keyID', 'keyID'); + } + + public function accountStatus() { + + return $this->hasOne('EveAccountAccountStatus', 'keyID', 'keyID'); + } + + public function key() + { + return $this->belongsTo('SeatKey', 'keyID', 'keyID'); + } +} diff --git a/app/models/EveAccountAPIKeyInfoCharacters.php b/app/models/EveAccountAPIKeyInfoCharacters.php new file mode 100644 index 00000000..bc51a236 --- /dev/null +++ b/app/models/EveAccountAPIKeyInfoCharacters.php @@ -0,0 +1,14 @@ +hasOne('EveAccountAPIKeyInfo'); + } +} diff --git a/app/models/EveAccountAccountStatus.php b/app/models/EveAccountAccountStatus.php new file mode 100644 index 00000000..bbe98cc6 --- /dev/null +++ b/app/models/EveAccountAccountStatus.php @@ -0,0 +1,14 @@ +hasOne('EveAccountAPIKeyInfo', 'keyID', 'keyID'); + } +} diff --git a/app/models/EveApiCalllist.php b/app/models/EveApiCalllist.php new file mode 100644 index 00000000..8b964853 --- /dev/null +++ b/app/models/EveApiCalllist.php @@ -0,0 +1,9 @@ +hasMany('EveCharacterAssetListContents', 'itemID', 'itemID'); + } +} diff --git a/app/models/EveCharacterAssetListContents.php b/app/models/EveCharacterAssetListContents.php new file mode 100644 index 00000000..bf3ceec0 --- /dev/null +++ b/app/models/EveCharacterAssetListContents.php @@ -0,0 +1,14 @@ +hasOne('EveCharacterAssetList', 'itemID', 'itemID'); + } +} diff --git a/app/models/EveCharacterCharacterSheet.php b/app/models/EveCharacterCharacterSheet.php new file mode 100644 index 00000000..e1b6b2a1 --- /dev/null +++ b/app/models/EveCharacterCharacterSheet.php @@ -0,0 +1,14 @@ +hasMany('EveCharacterCharacterSheetSkills', 'characterID', 'characterID'); + } +} diff --git a/app/models/EveCharacterCharacterSheetSkills.php b/app/models/EveCharacterCharacterSheetSkills.php new file mode 100644 index 00000000..762fa834 --- /dev/null +++ b/app/models/EveCharacterCharacterSheetSkills.php @@ -0,0 +1,14 @@ +belongsTo('EveCharacterCharacterSheet', 'characterID', 'characterID'); + } +} diff --git a/app/models/EveCharacterContactList.php b/app/models/EveCharacterContactList.php new file mode 100644 index 00000000..eb8c9877 --- /dev/null +++ b/app/models/EveCharacterContactList.php @@ -0,0 +1,9 @@ +hasMany('EveCharacterContractsItems', 'contractID', 'contractID'); + } +} diff --git a/app/models/EveCharacterContractsItems.php b/app/models/EveCharacterContractsItems.php new file mode 100644 index 00000000..501a3c2b --- /dev/null +++ b/app/models/EveCharacterContractsItems.php @@ -0,0 +1,14 @@ +hasOne('EveCharacterContracts', 'contractID', 'contractID'); + } +} diff --git a/app/models/EveCharacterIndustryJobs.php b/app/models/EveCharacterIndustryJobs.php new file mode 100644 index 00000000..365e030d --- /dev/null +++ b/app/models/EveCharacterIndustryJobs.php @@ -0,0 +1,9 @@ +hasOne('EveCharacterCharacterSheetSkills', 'messageID', 'messageID'); + } +} diff --git a/app/models/EveCharacterMailMessages.php b/app/models/EveCharacterMailMessages.php new file mode 100644 index 00000000..e8102118 --- /dev/null +++ b/app/models/EveCharacterMailMessages.php @@ -0,0 +1,14 @@ +hasMany('EveCharacterMailBodies', 'messageID', 'messageID'); + } +} diff --git a/app/models/EveCharacterMailingLists.php b/app/models/EveCharacterMailingLists.php new file mode 100644 index 00000000..e46733f6 --- /dev/null +++ b/app/models/EveCharacterMailingLists.php @@ -0,0 +1,9 @@ +hasMany('EveCharacterNotifications', 'notificationID', 'notificationID'); + } +} diff --git a/app/models/EveCharacterNotifications.php b/app/models/EveCharacterNotifications.php new file mode 100644 index 00000000..6b762dc0 --- /dev/null +++ b/app/models/EveCharacterNotifications.php @@ -0,0 +1,14 @@ +hasOne('EveCharacterNotificationTexts', 'notificationID', 'notificationID'); + } +} diff --git a/app/models/EveCharacterResearch.php b/app/models/EveCharacterResearch.php new file mode 100644 index 00000000..32a668bd --- /dev/null +++ b/app/models/EveCharacterResearch.php @@ -0,0 +1,9 @@ +hasMany('EveCorporationAssetListContents', 'itemID', 'itemID'); + } +} diff --git a/app/models/EveCorporationAssetListContents.php b/app/models/EveCorporationAssetListContents.php new file mode 100644 index 00000000..42605dbe --- /dev/null +++ b/app/models/EveCorporationAssetListContents.php @@ -0,0 +1,14 @@ +hasOne('EveCorporationAssetList', 'itemID', 'itemID'); + } +} diff --git a/app/models/EveCorporationAssetListLocations.php b/app/models/EveCorporationAssetListLocations.php new file mode 100644 index 00000000..b8375673 --- /dev/null +++ b/app/models/EveCorporationAssetListLocations.php @@ -0,0 +1,9 @@ +hasMany('EveCorporationContractsItems', 'contractID', 'contractID'); + } +} diff --git a/app/models/EveCorporationContractsItems.php b/app/models/EveCorporationContractsItems.php new file mode 100644 index 00000000..8f80391c --- /dev/null +++ b/app/models/EveCorporationContractsItems.php @@ -0,0 +1,14 @@ +hasOne('EveCorporationContracts', 'contractID', 'contractID'); + } +} diff --git a/app/models/EveCorporationCorporationSheet.php b/app/models/EveCorporationCorporationSheet.php new file mode 100644 index 00000000..757e3e22 --- /dev/null +++ b/app/models/EveCorporationCorporationSheet.php @@ -0,0 +1,19 @@ +hasMany('EveCorporationCorporationSheetDivisions', 'corporationID', 'corporationID'); + } + + public function walletdivisions() + { + return $this->hasMany('EveCorporationCorporationSheetDivisions', 'corporationID', 'corporationID'); + } +} diff --git a/app/models/EveCorporationCorporationSheetDivisions.php b/app/models/EveCorporationCorporationSheetDivisions.php new file mode 100644 index 00000000..d4d7dfae --- /dev/null +++ b/app/models/EveCorporationCorporationSheetDivisions.php @@ -0,0 +1,14 @@ +hasOne('EveCorporationCorporationSheet', 'corporationID', 'corporationID'); + } +} diff --git a/app/models/EveCorporationCorporationSheetWalletDivisions.php b/app/models/EveCorporationCorporationSheetWalletDivisions.php new file mode 100644 index 00000000..e24692db --- /dev/null +++ b/app/models/EveCorporationCorporationSheetWalletDivisions.php @@ -0,0 +1,14 @@ +hasOne('EveCorporationCorporationSheet', 'corporationID', 'corporationID'); + } +} diff --git a/app/models/EveCorporationIndustryJobs.php b/app/models/EveCorporationIndustryJobs.php new file mode 100644 index 00000000..12a7ccca --- /dev/null +++ b/app/models/EveCorporationIndustryJobs.php @@ -0,0 +1,9 @@ +hasMany('EveCorporationMemberSecurityLogDetails', 'hash', 'hash'); + } +} diff --git a/app/models/EveCorporationMemberSecurityLogDetails.php b/app/models/EveCorporationMemberSecurityLogDetails.php new file mode 100644 index 00000000..d83ea83e --- /dev/null +++ b/app/models/EveCorporationMemberSecurityLogDetails.php @@ -0,0 +1,14 @@ +hasOne('EveCorporationMemberSecurityLog', 'hash', 'hash'); + } +} diff --git a/app/models/EveCorporationMemberSecurityRoles.php b/app/models/EveCorporationMemberSecurityRoles.php new file mode 100644 index 00000000..aef2c6d9 --- /dev/null +++ b/app/models/EveCorporationMemberSecurityRoles.php @@ -0,0 +1,9 @@ +hasMany('EveEveAllianceListMemberCorporations', 'allianceID', 'allianceID'); + } +} diff --git a/app/models/EveEveAllianceListMemberCorporations.php b/app/models/EveEveAllianceListMemberCorporations.php new file mode 100644 index 00000000..6bef8ddf --- /dev/null +++ b/app/models/EveEveAllianceListMemberCorporations.php @@ -0,0 +1,15 @@ +belongsTo('EveEveAllianceList'); + } +} diff --git a/app/models/EveEveCharacterInfo.php b/app/models/EveEveCharacterInfo.php new file mode 100644 index 00000000..d8d3031d --- /dev/null +++ b/app/models/EveEveCharacterInfo.php @@ -0,0 +1,15 @@ +hasMany('EveEveCharacterInfoEmploymentHistory', 'characterID', 'characterID'); + } +} diff --git a/app/models/EveEveCharacterInfoEmploymentHistory.php b/app/models/EveEveCharacterInfoEmploymentHistory.php new file mode 100644 index 00000000..33465703 --- /dev/null +++ b/app/models/EveEveCharacterInfoEmploymentHistory.php @@ -0,0 +1,15 @@ +belongsTo('EveEveCharacterInfo'); + } +} diff --git a/app/models/EveEveConquerableStationList.php b/app/models/EveEveConquerableStationList.php new file mode 100644 index 00000000..eb2768ae --- /dev/null +++ b/app/models/EveEveConquerableStationList.php @@ -0,0 +1,10 @@ +belongsTo('User'); + } + + public function apiKeyInfo() + { + return $this->hasOne('EveAccountAPIKeyInfo', 'keyID', 'keyID'); + } +} \ No newline at end of file diff --git a/app/models/SeatQueueInformation.php b/app/models/SeatQueueInformation.php new file mode 100644 index 00000000..82c363b2 --- /dev/null +++ b/app/models/SeatQueueInformation.php @@ -0,0 +1,10 @@ +getKey(); + } + + /** + * Get the password for the user. + * + * @return string + */ + public function getAuthPassword() + { + return $this->password; + } + + /** + * Get the e-mail address where password reminders are sent. + * + * @return string + */ + public function getReminderEmail() + { + return $this->email; + } + + public function keys() + { + return $this->hasMany('SeatKey'); + } + +} \ No newline at end of file diff --git a/app/queues/full/EveCharacter.php b/app/queues/full/EveCharacter.php new file mode 100644 index 00000000..abb95d3f --- /dev/null +++ b/app/queues/full/EveCharacter.php @@ -0,0 +1,124 @@ +getJobId())->first(); + + // Check that we have a valid jobid + if (!$job_record) { + + // Sometimes the jobs get picked up faster than the submitter could write a + // database entry about it. So, just wait 5 seconds before we come back and + // try again + $job->release(5); + return; + } + + // We place the actual API work in our own try catch so that we can report + // on any critical errors that may have occurred. + + // By default Laravel will requeue a failed job based on --tries, but we + // dont really want failed api jobs to continually poll the API Server + try { + + $job_record->status = 'Working'; + $job_record->save(); + + $job_record->output = 'Started AccountBalance Update'; + $job_record->save(); + EveApi\Character\AccountBalance::Update($keyID, $vCode); + + $job_record->output = 'Started AssetList Update'; + $job_record->save(); + EveApi\Character\AssetList::Update($keyID, $vCode); + + $job_record->output = 'Started CharacterSheet Update'; + $job_record->save(); + EveApi\Character\CharacterSheet::Update($keyID, $vCode); + + $job_record->output = 'Started ContactList Update'; + $job_record->save(); + EveApi\Character\ContactList::Update($keyID, $vCode); + + $job_record->output = 'Started ContactNotifications Update'; + $job_record->save(); + EveApi\Character\ContactNotifications::Update($keyID, $vCode); + + $job_record->output = 'Started Contracts Update'; + $job_record->save(); + EveApi\Character\Contracts::Update($keyID, $vCode); + + $job_record->output = 'Started IndustryJobs Update'; + $job_record->save(); + EveApi\Character\IndustryJobs::Update($keyID, $vCode); + + $job_record->output = 'Started MailMessages Update'; + $job_record->save(); + EveApi\Character\MailMessages::Update($keyID, $vCode); + + $job_record->output = 'Started MailingLists Update'; + $job_record->save(); + EveApi\Character\MailingLists::Update($keyID, $vCode); + + $job_record->output = 'Started Notifications Update'; + $job_record->save(); + EveApi\Character\Notifications::Update($keyID, $vCode); + + $job_record->output = 'Started MarketOrders Update'; + $job_record->save(); + EveApi\Character\MarketOrders::Update($keyID, $vCode); + + $job_record->output = 'Started Research Update'; + $job_record->save(); + EveApi\Character\Research::Update($keyID, $vCode); + + $job_record->output = 'Started SkillInTraining Update'; + $job_record->save(); + EveApi\Character\SkillInTraining::Update($keyID, $vCode); + + $job_record->output = 'Started SkillQueue Update'; + $job_record->save(); + EveApi\Character\SkillQueue::Update($keyID, $vCode); + + $job_record->output = 'Started Standings Update'; + $job_record->save(); + EveApi\Character\Standings::Update($keyID, $vCode); + + $job_record->output = 'Started UpcomingCalendarEvents Update'; + $job_record->save(); + EveApi\Character\UpcomingCalendarEvents::Update($keyID, $vCode); + + $job_record->output = 'Started WalletJournal Update'; + $job_record->save(); + EveApi\Character\WalletJournal::Update($keyID, $vCode); + + $job_record->output = 'Started WalletTransactions Update'; + $job_record->save(); + EveApi\Character\WalletTransactions::Update($keyID, $vCode); + + $job_record->status = 'Done'; + $job_record->output = null; + $job_record->save(); + + $job->delete(); + + } catch (\Exception $e) { + + $job_record->status = 'Error'; + $job_record->output = 'Last status: ' . $job_record->output . ' Error: ' . $e->getCode() . ': ' . $e->getMessage() . ' in file ' . $e->getFile() . ' in line ' . $e->getLine(); + $job_record->save(); + + $job->delete(); + } + } +} \ No newline at end of file diff --git a/app/queues/full/EveCorporation.php b/app/queues/full/EveCorporation.php new file mode 100644 index 00000000..2ab44fc2 --- /dev/null +++ b/app/queues/full/EveCorporation.php @@ -0,0 +1,124 @@ +getJobId())->first(); + + // Check that we have a valid jobid + if (!$job_record) { + + // Sometimes the jobs get picked up faster than the submitter could write a + // database entry about it. So, just wait 5 seconds before we come back and + // try again + $job->release(5); + return; + } + + // We place the actual API work in our own try catch so that we can report + // on any critical errors that may have occurred. + + // By default Laravel will requeue a failed job based on --tries, but we + // dont really want failed api jobs to continually poll the API Server + try { + + $job_record->status = 'Working'; + $job_record->save(); + + $job_record->output = 'Started AccountBalance Update'; + $job_record->save(); + EveApi\Corporation\AccountBalance::Update($keyID, $vCode); + + $job_record->output = 'Started AssetList Update'; + $job_record->save(); + EveApi\Corporation\AssetList::Update($keyID, $vCode); + + $job_record->output = 'Started ContactList Update'; + $job_record->save(); + EveApi\Corporation\ContactList::Update($keyID, $vCode); + + $job_record->output = 'Started Contracts Update'; + $job_record->save(); + EveApi\Corporation\Contracts::Update($keyID, $vCode); + + $job_record->output = 'Started CorporationSheet Update'; + $job_record->save(); + EveApi\Corporation\CorporationSheet::Update($keyID, $vCode); + + $job_record->output = 'Started IndustryJobs Update'; + $job_record->save(); + EveApi\Corporation\IndustryJobs::Update($keyID, $vCode); + + $job_record->output = 'Started MarketOrders Update'; + $job_record->save(); + EveApi\Corporation\MarketOrders::Update($keyID, $vCode); + + $job_record->output = 'Started Medals Update'; + $job_record->save(); + EveApi\Corporation\Medals::Update($keyID, $vCode); + + $job_record->output = 'Started MemberMedals Update'; + $job_record->save(); + EveApi\Corporation\MemberMedals::Update($keyID, $vCode); + + $job_record->output = 'Started MemberSecurity Update'; + $job_record->save(); + EveApi\Corporation\MemberSecurity::Update($keyID, $vCode); + + $job_record->output = 'Started MemberSecurityLog Update'; + $job_record->save(); + EveApi\Corporation\MemberSecurityLog::Update($keyID, $vCode); + + $job_record->output = 'Started MemberTracking Update'; + $job_record->save(); + EveApi\Corporation\MemberTracking::Update($keyID, $vCode); + + $job_record->output = 'Started Shareholders Update'; + $job_record->save(); + EveApi\Corporation\Shareholders::Update($keyID, $vCode); + + $job_record->output = 'Started Standings Update'; + $job_record->save(); + EveApi\Corporation\Standings::Update($keyID, $vCode); + + $job_record->output = 'Started StarbaseList Update'; + $job_record->save(); + EveApi\Corporation\StarbaseList::Update($keyID, $vCode); + + $job_record->output = 'Started StarbaseDetail Update'; + $job_record->save(); + EveApi\Corporation\StarbaseDetail::Update($keyID, $vCode); + + $job_record->output = 'Started WalletJournal Update'; + $job_record->save(); + EveApi\Corporation\WalletJournal::Update($keyID, $vCode); + + $job_record->output = 'Started WalletTransactions Update'; + $job_record->save(); + EveApi\Corporation\WalletTransactions::Update($keyID, $vCode); + + $job_record->status = 'Done'; + $job_record->output = null; + $job_record->save(); + + $job->delete(); + + } catch (\Exception $e) { + + $job_record->status = 'Error'; + $job_record->output = 'Last status: ' . $job_record->output . ' Error: ' . $e->getCode() . ': ' . $e->getMessage() . ' in file ' . $e->getFile() . ' in line ' . $e->getLine(); + $job_record->save(); + + $job->delete(); + } + } +} \ No newline at end of file diff --git a/app/queues/full/EveEve.php b/app/queues/full/EveEve.php new file mode 100644 index 00000000..4e63b7f5 --- /dev/null +++ b/app/queues/full/EveEve.php @@ -0,0 +1,65 @@ +getJobId())->first(); + + // Check that we have a valid jobid + if (!$job_record) { + + // Sometimes the jobs get picked up faster than the submitter could write a + // database entry about it. So, just wait 5 seconds before we come back and + // try again + $job->release(5); + return; + } + + // We place the actual API work in our own try catch so that we can report + // on any critical errors that may have occurred. + + // By default Laravel will requeue a failed job based on --tries, but we + // dont really want failed api jobs to continually poll the API Server + try { + + $job_record->status = 'Working'; + $job_record->save(); + + $job_record->output = 'Started RefTypes Update'; + $job_record->save(); + EveApi\Eve\RefTypes::Update(); + + $job_record->output = 'Started ErrorList Update'; + $job_record->save(); + EveApi\Eve\ErrorList::Update(); + + $job_record->output = 'Started ConquerableStationList Update'; + $job_record->save(); + EveApi\Eve\ConquerableStationList::Update(); + + $job_record->output = 'Started AllianceList Update'; + $job_record->save(); + EveApi\Eve\AllianceList::Update(); + + $job_record->status = 'Done'; + $job_record->output = null; + $job_record->save(); + + $job->delete(); + + } catch (\Exception $e) { + + $job_record->status = 'Error'; + $job_record->output = 'Last status: ' . $job_record->output . ' Error: ' . $e->getCode() . ': ' . $e->getMessage() . ' in file ' . $e->getFile() . ' in line ' . $e->getLine(); + $job_record->save(); + + $job->delete(); + } + } +} \ No newline at end of file diff --git a/app/queues/full/EveMap.php b/app/queues/full/EveMap.php new file mode 100644 index 00000000..86c85f43 --- /dev/null +++ b/app/queues/full/EveMap.php @@ -0,0 +1,60 @@ +getJobId())->first(); + + // Check that we have a valid jobid + if (!$job_record) { + + // Sometimes the jobs get picked up faster than the submitter could write a + // database entry about it. So, just wait 5 seconds before we come back and + // try again + $job->release(5); + return; + } + + // We place the actual API work in our own try catch so that we can report + // on any critical errors that may have occurred. + + // By default Laravel will requeue a failed job based on --tries, but we + // dont really want failed api jobs to continually poll the API Server + try { + + $job_record->status = 'Working'; + + $job_record->output = 'Started Sovereignty Update'; + $job_record->save(); + EveApi\Map\Sovereignty::Update(); + + $job_record->output = 'Started Kills Update'; + $job_record->save(); + EveApi\Map\Kills::Update(); + + $job_record->output = 'Started Jumps Update'; + $job_record->save(); + EveApi\Map\Jumps::Update(); + + $job_record->status = 'Done'; + $job_record->output = null; + $job_record->save(); + + $job->delete(); + + } catch (\Exception $e) { + + $job_record->status = 'Error'; + $job_record->output = 'Last status: ' . $job_record->output . ' Error: ' . $e->getCode() . ': ' . $e->getMessage() . ' in file ' . $e->getFile() . ' in line ' . $e->getLine(); + $job_record->save(); + + $job->delete(); + } + } +} \ No newline at end of file diff --git a/app/queues/full/EveServer.php b/app/queues/full/EveServer.php new file mode 100644 index 00000000..59cc63df --- /dev/null +++ b/app/queues/full/EveServer.php @@ -0,0 +1,53 @@ +getJobId())->first(); + + // Check that we have a valid jobid + if (!$job_record) { + + // Sometimes the jobs get picked up faster than the submitter could write a + // database entry about it. So, just wait 5 seconds before we come back and + // try again + $job->release(5); + return; + } + + // We place the actual API work in our own try catch so that we can report + // on any critical errors that may have occurred. + + // By default Laravel will requeue a failed job based on --tries, but we + // dont really want failed api jobs to continually poll the API Server + try { + + $job_record->status = 'Working'; + $job_record->save(); + + $job_record->output = 'Started ServerStatus Update'; + $job_record->save(); + EveApi\Server\ServerStatus::Update(); + + $job_record->status = 'Done'; + $job_record->output = null; + $job_record->save(); + + $job->delete(); + + } catch (\Exception $e) { + + $job_record->status = 'Error'; + $job_record->output = 'Last status: ' . $job_record->output . ' Error: ' . $e->getCode() . ': ' . $e->getMessage() . ' in file ' . $e->getFile() . ' in line ' . $e->getLine(); + $job_record->save(); + + $job->delete(); + } + } +} \ No newline at end of file diff --git a/app/queues/partial/EveCorporation.php b/app/queues/partial/EveCorporation.php new file mode 100644 index 00000000..c87985eb --- /dev/null +++ b/app/queues/partial/EveCorporation.php @@ -0,0 +1,112 @@ +getJobId())->first(); + + // Check that we have a valid jobid + if (!$job_record) { + + // Sometimes the jobs get picked up faster than the submitter could write a + // database entry about it. So, just wait 5 seconds before we come back and + // try again + $job->release(5); + return; + } + + // We place the actual API work in our own try catch so that we can report + // on any critical errors that may have occurred. + + // By default Laravel will requeue a failed job based on --tries, but we + // dont really want failed api jobs to continually poll the API Server + try { + + $job_record->status = 'Working'; + $job_record->save(); + + $job_record->output = 'Started AccountBalance Update'; + $job_record->save(); + EveApi\Corporation\AccountBalance::Update($keyID, $vCode); + + $job_record->output = 'Started ContactList Update'; + $job_record->save(); + EveApi\Corporation\ContactList::Update($keyID, $vCode); + + $job_record->output = 'Started Contracts Update'; + $job_record->save(); + EveApi\Corporation\Contracts::Update($keyID, $vCode); + + $job_record->output = 'Started CorporationSheet Update'; + $job_record->save(); + EveApi\Corporation\CorporationSheet::Update($keyID, $vCode); + + $job_record->output = 'Started IndustryJobs Update'; + $job_record->save(); + EveApi\Corporation\IndustryJobs::Update($keyID, $vCode); + + $job_record->output = 'Started MarketOrders Update'; + $job_record->save(); + EveApi\Corporation\MarketOrders::Update($keyID, $vCode); + + $job_record->output = 'Started Medals Update'; + $job_record->save(); + EveApi\Corporation\Medals::Update($keyID, $vCode); + + $job_record->output = 'Started MemberMedals Update'; + $job_record->save(); + EveApi\Corporation\MemberMedals::Update($keyID, $vCode); + + $job_record->output = 'Started MemberSecurity Update'; + $job_record->save(); + EveApi\Corporation\MemberSecurity::Update($keyID, $vCode); + + $job_record->output = 'Started MemberSecurityLog Update'; + $job_record->save(); + EveApi\Corporation\MemberSecurityLog::Update($keyID, $vCode); + + $job_record->output = 'Started MemberTracking Update'; + $job_record->save(); + EveApi\Corporation\MemberTracking::Update($keyID, $vCode); + + $job_record->output = 'Started Shareholders Update'; + $job_record->save(); + EveApi\Corporation\Shareholders::Update($keyID, $vCode); + + $job_record->output = 'Started Standings Update'; + $job_record->save(); + EveApi\Corporation\Standings::Update($keyID, $vCode); + + $job_record->output = 'Started StarbaseList Update'; + $job_record->save(); + EveApi\Corporation\StarbaseList::Update($keyID, $vCode); + + $job_record->output = 'Started StarbaseDetail Update'; + $job_record->save(); + EveApi\Corporation\StarbaseDetail::Update($keyID, $vCode); + + $job_record->status = 'Done'; + $job_record->output = null; + $job_record->save(); + + $job->delete(); + + } catch (\Exception $e) { + + $job_record->status = 'Error'; + $job_record->output = 'Last status: ' . $job_record->output . ' Error: ' . $e->getCode() . ': ' . $e->getMessage() . ' in file ' . $e->getFile() . ' in line ' . $e->getLine(); + $job_record->save(); + + $job->delete(); + } + } +} \ No newline at end of file diff --git a/app/queues/partial/EveCorporationAssets.php b/app/queues/partial/EveCorporationAssets.php new file mode 100644 index 00000000..970294c2 --- /dev/null +++ b/app/queues/partial/EveCorporationAssets.php @@ -0,0 +1,56 @@ +getJobId())->first(); + + // Check that we have a valid jobid + if (!$job_record) { + + // Sometimes the jobs get picked up faster than the submitter could write a + // database entry about it. So, just wait 5 seconds before we come back and + // try again + $job->release(5); + return; + } + + // We place the actual API work in our own try catch so that we can report + // on any critical errors that may have occurred. + + // By default Laravel will requeue a failed job based on --tries, but we + // dont really want failed api jobs to continually poll the API Server + try { + + $job_record->status = 'Working'; + $job_record->save(); + + $job_record->output = 'Started AssetList Update'; + $job_record->save(); + EveApi\Corporation\AssetList::Update($keyID, $vCode); + + $job_record->status = 'Done'; + $job_record->output = null; + $job_record->save(); + + $job->delete(); + + } catch (\Exception $e) { + + $job_record->status = 'Error'; + $job_record->output = 'Last status: ' . $job_record->output . ' Error: ' . $e->getCode() . ': ' . $e->getMessage() . ' in file ' . $e->getFile() . ' in line ' . $e->getLine(); + $job_record->save(); + + $job->delete(); + } + } +} \ No newline at end of file diff --git a/app/queues/partial/EveCorporationWallet.php b/app/queues/partial/EveCorporationWallet.php new file mode 100644 index 00000000..bb848db4 --- /dev/null +++ b/app/queues/partial/EveCorporationWallet.php @@ -0,0 +1,60 @@ +getJobId())->first(); + + // Check that we have a valid jobid + if (!$job_record) { + + // Sometimes the jobs get picked up faster than the submitter could write a + // database entry about it. So, just wait 5 seconds before we come back and + // try again + $job->release(5); + return; + } + + // We place the actual API work in our own try catch so that we can report + // on any critical errors that may have occurred. + + // By default Laravel will requeue a failed job based on --tries, but we + // dont really want failed api jobs to continually poll the API Server + try { + + $job_record->status = 'Working'; + $job_record->save(); + + $job_record->output = 'Started WalletJournal Update'; + $job_record->save(); + EveApi\Corporation\WalletJournal::Update($keyID, $vCode); + + $job_record->output = 'Started WalletTransactions Update'; + $job_record->save(); + EveApi\Corporation\WalletTransactions::Update($keyID, $vCode); + + $job_record->status = 'Done'; + $job_record->output = null; + $job_record->save(); + + $job->delete(); + + } catch (\Exception $e) { + + $job_record->status = 'Error'; + $job_record->output = 'Last status: ' . $job_record->output . ' Error: ' . $e->getCode() . ': ' . $e->getMessage() . ' in file ' . $e->getFile() . ' in line ' . $e->getLine(); + $job_record->save(); + + $job->delete(); + } + } +} \ No newline at end of file diff --git a/app/routes.php b/app/routes.php new file mode 100644 index 00000000..39b4e072 --- /dev/null +++ b/app/routes.php @@ -0,0 +1,38 @@ + 'account'), function() +{ + + Route::controller('user', 'UserController'); + Route::controller('password', 'RemindersController'); + Route::controller('register', 'RegisterController'); + +}); + + +Route::group(array('before' => 'auth|csrf'), function() { + + Route::get('/', 'HomeController@showIndex'); + + Route::controller('api-key', 'ApiKeyController'); + Route::controller('dashboard', 'DashboardController'); + Route::controller('mail', 'MailController'); + Route::controller('character', 'CharacterController'); + Route::controller('corporation', 'CorporationController'); + Route::controller('queue', 'QueueController'); + + Route::controller('helpers', 'HelperController'); + Route::controller('debug', 'DebugController'); + +}); diff --git a/app/services/validators/APIKeyValidator.php b/app/services/validators/APIKeyValidator.php new file mode 100644 index 00000000..ea1bb65a --- /dev/null +++ b/app/services/validators/APIKeyValidator.php @@ -0,0 +1,10 @@ + 'required|numeric', + 'vCode' => 'required|min:64', + ); + +} \ No newline at end of file diff --git a/app/services/validators/Validator.php b/app/services/validators/Validator.php new file mode 100644 index 00000000..570b45fb --- /dev/null +++ b/app/services/validators/Validator.php @@ -0,0 +1,26 @@ +data = $data ?: \Input::all(); + } + + public function passes() + { + $validation = \Validator::make($this->data, static::$rules); + + if ($validation->passes()) return true; + + $this->errors = $validation->messages(); + + return false; + } +} \ No newline at end of file diff --git a/app/start/artisan.php b/app/start/artisan.php new file mode 100644 index 00000000..464ab14e --- /dev/null +++ b/app/start/artisan.php @@ -0,0 +1,30 @@ +client->request('GET', '/'); + + $this->assertTrue($this->client->getResponse()->isOk()); + } + +} \ No newline at end of file diff --git a/app/tests/TestCase.php b/app/tests/TestCase.php new file mode 100644 index 00000000..d367fe53 --- /dev/null +++ b/app/tests/TestCase.php @@ -0,0 +1,19 @@ + + + +
+

All Characters @if (count($characters) > 0) ({{ count($characters) }}) @endif

+
+
+ +
+ +
+
+
+
+ +
+ + @foreach(array_chunk($characters, 4) as $character_row) +
+ @foreach($character_row as $character) +
+ + + +
+
+
    +
  • Name: {{ $character->characterName }}
  • +
  • Corp: {{ $character->corporationName }}
  • +
  • + @if ($character->isOk == 1) + Key Ok + @else + Key not Ok + @endif +
  • +
  • + @if (strlen($character->trainingEndTime) > 0) + Training Ends: {{ Carbon\Carbon::parse($character->trainingEndTime)->diffForHumans() }} + @endif +
  • +
+
+ @endforeach +
+
+ @endforeach + +
+ + +@stop diff --git a/app/views/character/view.blade.php b/app/views/character/view.blade.php new file mode 100644 index 00000000..47893dc7 --- /dev/null +++ b/app/views/character/view.blade.php @@ -0,0 +1,591 @@ +@extends('layouts.masterLayout') + +@section('html_title', 'View Character') + +@section('page_content') + + +
+
+ +
+
+

Character Details for {{ $character->characterName }}

+
+
+
+
+
+
+ +
+
+
+
+

Character Overview

+
+
+
+
+
+
Name
+
{{ $character->characterName }}
+ +
Corporation
+
{{ $character->corporationName }}
+ +
Race, Booldline, Sex
+
{{ $character->race }}, {{ $character->bloodLine }}, {{ $character->gender }}
+ +
Date of Birth
+
{{ $character->DoB }} ({{ Carbon\Carbon::parse($character->DoB)->diffForHumans() }})
+
+
+
+
+
+
+
+

Other Characters on Key

+
+
+
+
+ @if (count($other_characters) > 0) + @foreach ($other_characters as $alt) +
+
+ + + +
+
+
    +
  • Name: {{ $alt->characterName }}
  • +
  • Corp: {{ $alt->corporationName }}
  • +
  • + @if (strlen($alt->trainingEndTime) > 0) + Training Ends: {{ Carbon\Carbon::parse($alt->trainingEndTime)->diffForHumans() }} + @endif +
  • +
+
+
+ @endforeach + @else + No other known characters on this key. + @endif +
+
+
+
+
+
+
+
+ +{{-- details such as character sheet, skills, mail, wallet etc etc here --}} +
+
+ + +
+
+@stop + +@section('javascript') + +@stop \ No newline at end of file diff --git a/app/views/corporation/membertracking/listmembertracking.blade.php b/app/views/corporation/membertracking/listmembertracking.blade.php new file mode 100644 index 00000000..6f6e5336 --- /dev/null +++ b/app/views/corporation/membertracking/listmembertracking.blade.php @@ -0,0 +1,23 @@ +@extends('layouts.masterLayout') + +@section('html_title', 'All Corporations Member Tracking') + +@section('page_content') + +@foreach ($corporations as $corp) +
+
+

+ {{ $corp->corporationName }} +

+

+ From character: {{ $corp->characterName }} +

+
+ + View Member Tracking + +
+@endforeach + +@stop diff --git a/app/views/corporation/membertracking/membertracking.blade.php b/app/views/corporation/membertracking/membertracking.blade.php new file mode 100644 index 00000000..5ef79c6f --- /dev/null +++ b/app/views/corporation/membertracking/membertracking.blade.php @@ -0,0 +1,62 @@ +@extends('layouts.masterLayout') + +@section('html_title', 'Corporation Member Tracking') + +@section('page_content') + +
+
+

All Members @if (count($members) > 0) ({{ count($members) }}) @endif

+
+
+ +
+ +
+
+
+
+ +
+ + @foreach(array_chunk($members, 4) as $character_row) +
+ @foreach($character_row as $character) +
+ + + +
+
+
    +
  • + Name: {{ $character->name }} + @if (strlen($character->title) > 0) {{-- display the title if its set --}} + {{ $character->title }} + @endif +
  • +
  • Joined: {{ Carbon\Carbon::parse($character->startDateTime)->diffForHumans() }}
  • +
  • Last Logon: {{ Carbon\Carbon::parse($character->logonDateTime)->diffForHumans() }}
  • +
  • Last Logoff: {{ Carbon\Carbon::parse($character->logoffDateTime)->diffForHumans() }}
  • +
  • Location: {{ $character->location }}
  • +
  • Ship: {{ $character->shipType }}
  • +
  • + @if ($character->isOk == 1) + Key Ok + @else + Key not Ok + @endif + @if (strlen($character->keyID) > 0) + + @endif +
  • +
+
+ @endforeach +
+
+ @endforeach + +
+
+@stop diff --git a/app/views/corporation/starbase/liststarbase.blade.php b/app/views/corporation/starbase/liststarbase.blade.php new file mode 100644 index 00000000..c7f4b091 --- /dev/null +++ b/app/views/corporation/starbase/liststarbase.blade.php @@ -0,0 +1,23 @@ +@extends('layouts.masterLayout') + +@section('html_title', 'All Corporation Startbases') + +@section('page_content') + +@foreach ($corporations as $corp) +
+
+

+ {{ $corp->corporationName }} +

+

+ From character: {{ $corp->characterName }} +

+
+ + View Corporation Starbases + +
+@endforeach + +@stop diff --git a/app/views/corporation/starbase/starbase.blade.php b/app/views/corporation/starbase/starbase.blade.php new file mode 100644 index 00000000..dc143501 --- /dev/null +++ b/app/views/corporation/starbase/starbase.blade.php @@ -0,0 +1,113 @@ +@extends('layouts.masterLayout') + +@section('html_title', 'Startbase Details') + +@section('page_content') + + @foreach (array_chunk($starbases, 3) as $starbase) + +
+ + @foreach ($starbase as $details) + + {{-- find the starbases name in the $item_locations array --}} + {{--*/$posname = null/*--}} + @foreach ($item_locations[$details->moonID] as $name_finder) + @if ($name_finder['itemID'] == $details->itemID) + {{--*/$posname = $name_finder['itemName']/*--}} + @endif + @endforeach + + {{-- process the rest of the html --}} +
+ +
+ @endforeach +
+ @endforeach + +@stop + diff --git a/app/views/corporation/walletjournal/listjournals.blade.php b/app/views/corporation/walletjournal/listjournals.blade.php new file mode 100644 index 00000000..7d9d845a --- /dev/null +++ b/app/views/corporation/walletjournal/listjournals.blade.php @@ -0,0 +1,23 @@ +@extends('layouts.masterLayout') + +@section('html_title', 'All Corporations Journals') + +@section('page_content') + +@foreach ($corporations as $corp) +
+
+

+ {{ $corp->corporationName }} +

+

+ From character: {{ $corp->characterName }} +

+
+ + View Corporation Wallet Journal + +
+@endforeach + +@stop diff --git a/app/views/corporation/walletjournal/walletjournal.blade.php b/app/views/corporation/walletjournal/walletjournal.blade.php new file mode 100644 index 00000000..c3855ae9 --- /dev/null +++ b/app/views/corporation/walletjournal/walletjournal.blade.php @@ -0,0 +1,61 @@ +@extends('layouts.masterLayout') + +@section('html_title', 'Corporation Wallet Journal') + +@section('page_content') + +
+
+ +
+
+

Wallet Journal for: {{ $corporation_name->corporationName }}

+
+
    + {{ $wallet_journal->links() }} +
+
+
+
+ + + + + + + + + + + + @foreach ($wallet_journal as $e) + amount < 0)class="danger" @endif> + + + + + + + + + @endforeach + + +
DateWallet DivisionTypeOwner1 NameOwner2 NameAmountBalance
+ + {{ Carbon\Carbon::parse($e->date)->diffForHumans() }} + + {{ $e->description }}{{ $e->refTypeName }}{{ $e->ownerName1 }}{{ $e->ownerName2 }} + @if ($e->amount < 0) + {{ number_format($e->amount, 2, '.', ' ') }} + @else + {{ number_format($e->amount, 2, '.', ' ') }} + @endif + {{ number_format($e->balance, 2, '.', ' ') }}
+
+
{{ $wallet_journal->links() }}
+
+
+
+ +@stop diff --git a/app/views/corporation/wallettransactions/listtransactions.blade.php b/app/views/corporation/wallettransactions/listtransactions.blade.php new file mode 100644 index 00000000..b840cef4 --- /dev/null +++ b/app/views/corporation/wallettransactions/listtransactions.blade.php @@ -0,0 +1,23 @@ +@extends('layouts.masterLayout') + +@section('html_title', 'All Corporations Transactions') + +@section('page_content') + +@foreach ($corporations as $corp) +
+
+

+ {{ $corp->corporationName }} +

+

+ From character: {{ $corp->characterName }} +

+
+ + View Corporation Wallet Transactions + +
+@endforeach + +@stop diff --git a/app/views/corporation/wallettransactions/wallettransactions.blade.php b/app/views/corporation/wallettransactions/wallettransactions.blade.php new file mode 100644 index 00000000..b6c4b725 --- /dev/null +++ b/app/views/corporation/wallettransactions/wallettransactions.blade.php @@ -0,0 +1,55 @@ +@extends('layouts.masterLayout') + +@section('html_title', 'Corporation Wallet Transactions') + +@section('page_content') + +
+
+ +
+
+

Wallet Transactions for: {{ $corporation_name->corporationName }}

+
+
    + {{ $wallet_transactions->links() }} +
+
+
+
+ + + + + + + + + + + + @foreach ($wallet_transactions as $e) + transactionType == 'buy')class="danger" @endif> + + + + + + + + + @endforeach + + +
DateWallet DivisionTypeOwner1 NameOwner2 NameAmountBalance
+ + {{ Carbon\Carbon::parse($e->transactionDateTime)->diffForHumans() }} + + {{ $e->quantity }}{{ $e->typeName }}{{ number_format($e->price, 2, '.', ' ') }} {{ $e->clientName }}{{ $e->transactionType }}{{ $e->stationName }}
+
+
{{ $wallet_transactions->links() }}
+
+
+
+ +@stop diff --git a/app/views/debug/ajax/result.blade.php b/app/views/debug/ajax/result.blade.php new file mode 100644 index 00000000..2db6ce6f --- /dev/null +++ b/app/views/debug/ajax/result.blade.php @@ -0,0 +1,73 @@ +@include('layouts.components.flash') + +@if (isset($exception)) + +
+
+
+
+

API Call Exception Raised

+
+ + +
+
+
+ The API call failed with error code {{ $exception->getCode() }} +

The Error was: {{ $exception->getMessage() }}

+
+
+
+
+@endif + +@if (isset($call_sample)) +
+
+
+
+

API Call Structure

+
+ + +
+
+
+ The pheal instance was probably called with: +

+ KeyID: {{ $call_sample['keyID'] }}
+ vCode: {{ $call_sample['vCode'] }}

+

+

+ PHP Function:
+

$pheal->{{ $call_sample['scope'] }}scope->{{ $call_sample['call'] }}({{ print_r($call_sample['args'], true) }})
+

+
+
+
+
+@endif + +@if (isset($response)) +
+
+
+
+

+ Raw Response as PHP Array + @if (isset($response['cachedUntil'])) + + Cached result expires: {{ Carbon\Carbon::parse($response['cachedUntil'])->diffForHumans() }} + + @endif +

+
+
+
+{{ print_r($response, true) }}
+			    	
+
+
+
+
+@endif \ No newline at end of file diff --git a/app/views/debug/api.blade.php b/app/views/debug/api.blade.php new file mode 100644 index 00000000..eec1f16b --- /dev/null +++ b/app/views/debug/api.blade.php @@ -0,0 +1,199 @@ +@extends('layouts.masterLayout') + +@section('html_title', 'API Debugger') + +@section('page_content') + +
+ +
+ +
+
+

API Details

+
+ +
+ + {{ Form::open(array('class' => 'form-horizontal', 'id' => 'api-form')) }} +
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ +
+ {{ Form::close() }} + +
+
+ +
+
+ + + +
+ +
+ +@stop + +@section('javascript') + +@stop \ No newline at end of file diff --git a/app/views/emails/auth/reminder.blade.php b/app/views/emails/auth/reminder.blade.php new file mode 100644 index 00000000..c02c884c --- /dev/null +++ b/app/views/emails/auth/reminder.blade.php @@ -0,0 +1,13 @@ + + + + + + +

SeAT Password Reset

+ +
+ To reset your password, complete this form: {{ URL::action('RemindersController@getReset', array($token)) }}. +
+ + \ No newline at end of file diff --git a/app/views/errors/notFound.blade.php b/app/views/errors/notFound.blade.php new file mode 100644 index 00000000..a2c316a6 --- /dev/null +++ b/app/views/errors/notFound.blade.php @@ -0,0 +1,18 @@ +@extends('layouts.minimalLayout') +@section('page_content') +
+
404
+ +
+

Page not found...

+
+ +
+@stop diff --git a/app/views/home.blade.php b/app/views/home.blade.php new file mode 100644 index 00000000..0592d944 --- /dev/null +++ b/app/views/home.blade.php @@ -0,0 +1,48 @@ +@extends('layouts.masterLayout') + +@section('html_title', 'Home') + +@section('page_content') + +
+
+ +
+
+

+ {{ Carbon\Carbon::parse($server->currentTime)->diffForHumans() }} +

+

+ Last Server Status Check +

+
+
+
+
+ +
+
+

+ {{ $server->onlinePlayers }} +

+

+ Online Players +

+
+
+
+
+ +
+
+

+ {{ $server->serverOpen }} +

+

+ Server Online? +

+
+
+
+
+@stop diff --git a/app/views/keys/ajax/check.blade.php b/app/views/keys/ajax/check.blade.php new file mode 100644 index 00000000..7584c9a2 --- /dev/null +++ b/app/views/keys/ajax/check.blade.php @@ -0,0 +1,114 @@ + +@include('layouts.components.flash') + +{{-- process errors --}} +@if (!is_object($key_info)) +
+

Error: Unable to get API Key Info /account/APIKeyInfo.xml.aspx

+

The error was: {{ $key_info['error'] }}

+
+@endif + +@if (!is_object($status_info)) +
+

Error: Unable to get Account Status /account/AccountStatus.xml.aspx

+

The error was: {{ $key_info['error'] }}

+
+@endif + +{{-- process db existance check --}} +@if ($existance > 0) +
+

Key already exists in the database

+

Adding it here will simply reactive it if it is disabled.

+
+@else +
+

Key does not exist in the database

+

Adding it here will make it part of the scheduled updates via the backend.

+
+@endif + +{{-- process the ACTUAL info --}} +
+
+ + + + {{-- key time accounts --}} +
    +
  • This account has logged into EVE related services {{ $status_info->logonCount }} times
  • +
  • + + This account has been online a total of + {{ $status_info->logonMinutes }} minutes, {{ round(((int)$status_info->logonMinutes/60),0) }} hours or {{ round(((int)$status_info->logonMinutes/60)/24,0) }} days +
  • +
+ + {{-- key activity and accessmask details --}} +
    + @if (Carbon\Carbon::parse($status_info->paidUntil)->lte(\Carbon\Carbon::now())) +
  • This account is not active and expired {{ Carbon\Carbon::parse($status_info->paidUntil)->diffForHumans() }}
  • + @else +
  • This account is active and will expire on {{ $status_info->paidUntil }} which is {{ Carbon\Carbon::parse($status_info->paidUntil)->diffForHumans() }}
  • + @endif + + @if( strlen($key_info->key->expires) == 0) +
  • This key will never expire
  • + @else +
  • This key will expire on {{ $key_info->key->expires }} which is {{ Carbon\Carbon::parse($key_info->key->expires)->diffForHumans() }}
  • + @endif + +
  • This key type is {{ $key_info->key->type }}
  • + + @if ($key_info->key->type == 'Corporation') + @if ($key_info->key->accessMask == 67108863) {{-- full corporation api key? --}} +
  • This key has a full corporation Access Mask of: {{ $key_info->key->accessMask }}
  • + @else +
  • This key has a partial corporation Access Mask of: {{ $key_info->key->accessMask }}
  • + @endif + @else + @if ($key_info->key->accessMask == 268435455) {{-- full character/account api key? --}} +
  • This key has a full character/account Access Mask of: {{ $key_info->key->accessMask }}
  • + @else +
  • This key has a partial character/account Access Mask of: {{ $key_info->key->accessMask }}
  • + @endif + @endif +
+ +
+
+
+

A Job will be queued to update all key information

+

Adding this key will queue a job to update its information immediately

+ {{ HTML::linkAction('ApiKeyController@getAdd', 'Add this Key', array('keyID'=> $keyID, 'vCode' => $vCode), array('class' => 'btn btn-primary')) }} +
+
+
+ +
+ +
+
+ {{-- key characters --}} +

Characters on key {{ $keyID }}

+ @foreach ($key_info->key->characters as $character) +
+
+ +
+
+
+

{{ $character->characterName }}

+ {{ $character->corporationName }} +
+
+
+ @endforeach + +
+
+

Access Mask Details:

+ Todoā„¢ +
+
diff --git a/app/views/keys/ajax/errors.blade.php b/app/views/keys/ajax/errors.blade.php new file mode 100644 index 00000000..670f7120 --- /dev/null +++ b/app/views/keys/ajax/errors.blade.php @@ -0,0 +1,2 @@ + +@include('layouts.components.flash') diff --git a/app/views/keys/all.blade.php b/app/views/keys/all.blade.php new file mode 100644 index 00000000..468f934c --- /dev/null +++ b/app/views/keys/all.blade.php @@ -0,0 +1,71 @@ +@extends('layouts.masterLayout') + +@section('html_title', 'All Keys') + +@section('page_content') + + +
+ + +
+

All API Keys @if (count($key_info) > 0) ({{ count($key_info) }}) @endif

+
+
+ +
+ +
+
+
+
+ +
+ + + + + + + + + + + + + + @foreach($key_info as $key) + + 1) class="danger" @endif> + + + + + + + + + @endforeach + + +
KeyIDTypeAccess MaskExpiresCharacters On Key
{{ $key['keyID'] }}{{ $key['type'] }}{{ $key['accessMask'] }}{{ $key['expires_human'] }} + @if (isset($key['characters'])) + @foreach($key['characters'] as $char) + + + {{ $char['characterName'] }} + + @endforeach + @else + No known characters for this keyID, maybe its still updating or entirely invalid/expired. + @endif + + +
+
+
+ +@stop diff --git a/app/views/keys/detail.blade.php b/app/views/keys/detail.blade.php new file mode 100644 index 00000000..4d818b42 --- /dev/null +++ b/app/views/keys/detail.blade.php @@ -0,0 +1,230 @@ +@extends('layouts.masterLayout') +@section('html_title', 'Key Details') + +@section('page_content') + +
+
+ +
+
+

+ {{ $key_information->keyID }} +

+

+ Key ID +

+
+
+
+
+ +
+
+

+ @if (strlen($key_information->type) > 0) + {{ $key_information->type }} + @else + Unknown + @endif +

+

+ Key Type +

+
+
+
+
+ +
+
+

+ {{ count($key_characters) }} +

+

+ Characters on key +

+
+
+
+
+ + @if ($key_information->isOk == 1) +
+ @else +
+ @endif + +
+

+ {{ $key_information->isOk }} +

+

+ @if ($key_information->isOk == 1) + Key is OK + @else + Key is NOT ok + @endif +

+
+
+
+
+ +
+ +
+
+ +
+
+

Characters On Key

+
+ + +
+
+
+ @if (count($key_characters) > 0) + @foreach ($key_characters as $character) +
+
+ + + +
+
+

{{ $character->characterName }}

+

{{ $character->corporationName }}

+
+
+ @endforeach + @else + No known characters on this key + @endif +
+
+
+ +
+ +
+
+

Recent Update Jobs

+
+ + +
+
+
+ + + + + + + + + + @foreach ($recent_jobs as $job) + + + + + + + + @endforeach + +
ScheduledAPIScopeStatus
+ + {{ Carbon\Carbon::parse($job->created_at)->diffForHumans() }} + + {{ $job->api }}{{ $job->scope }}{{ $job->status }} + @if (strlen($job->output) > 0) + + @endif +
+
+
+
+ {{-- just provide the update now for character keys --}} + @if ($key_information->keyID <> 'Corporation') + + @endif +
+
+ +
+ +
+
+

Banned Calls

+
+ + +
+
+
+ + + + + + + + + + @foreach ($key_bans as $ban) + + + + + + + + @endforeach + +
ScheduledAccess MaskAPIScope
+ + {{ Carbon\Carbon::parse($ban->created_at)->diffForHumans() }} + + {{ $ban->accessMask }}{{ $ban->api }}{{ $ban->scope }} + @if (strlen($ban->reason) > 0) + + @endif +
+
+
+
+
+ +@stop + +@section('javascript') + + +@stop \ No newline at end of file diff --git a/app/views/keys/new.blade.php b/app/views/keys/new.blade.php new file mode 100644 index 00000000..e8909672 --- /dev/null +++ b/app/views/keys/new.blade.php @@ -0,0 +1,123 @@ +@extends('layouts.masterLayout') +@section('html_title', 'New Key') + +@section('page_content') + +
+
+

Add New API Key

+
+ +
+ + {{ Form::open(array('class' => 'form-horizontal', 'id' => 'key-form')) }} +
+ + +
+ +
+
+ + {{ Form::text('keyID', null, array('id' => 'keyID', 'class' => 'form-control', 'placeholder' => 'Key ID'), 'required', 'autofocus') }} +
+
+
+ + +
+ +
+
+ + {{ Form::text('vCode', null, array('id' => 'vCode', 'class' => ' form-control', 'placeholder' => 'vCode'), 'required') }} +
+
+
+ + +
+ +
+ +
+
+ +
+ {{ Form::close() }} + +
+
+ + + + +@stop + +@section('javascript') + +@stop \ No newline at end of file diff --git a/app/views/layouts/components/flash.blade.php b/app/views/layouts/components/flash.blade.php new file mode 100644 index 00000000..48332766 --- /dev/null +++ b/app/views/layouts/components/flash.blade.php @@ -0,0 +1,25 @@ +@if ($errors->has()) + @foreach ($errors->all() as $error) +
+ + + Error! {{ $error }} +
+ @endforeach +@endif + +@if(Session::has('success')) +
+ + + Success! {{ Session::get('success') }} +
+@endif + +@if(Session::has('warning')) +
+ + + Warning! {{ Session::get('warning') }} +
+@endif \ No newline at end of file diff --git a/app/views/layouts/components/footer.blade.php b/app/views/layouts/components/footer.blade.php new file mode 100644 index 00000000..8c15df19 --- /dev/null +++ b/app/views/layouts/components/footer.blade.php @@ -0,0 +1 @@ + diff --git a/app/views/layouts/components/header.blade.php b/app/views/layouts/components/header.blade.php new file mode 100644 index 00000000..d2fe07f9 --- /dev/null +++ b/app/views/layouts/components/header.blade.php @@ -0,0 +1,66 @@ + +
+ + + +
diff --git a/app/views/layouts/components/sidebar.blade.php b/app/views/layouts/components/sidebar.blade.php new file mode 100644 index 00000000..b8e5905d --- /dev/null +++ b/app/views/layouts/components/sidebar.blade.php @@ -0,0 +1,72 @@ + + diff --git a/app/views/layouts/masterLayout.blade.php b/app/views/layouts/masterLayout.blade.php new file mode 100644 index 00000000..6888e068 --- /dev/null +++ b/app/views/layouts/masterLayout.blade.php @@ -0,0 +1,109 @@ + + + + + + + @if (trim($__env->yieldContent('html_title'))) + @yield('html_title') | + @endif SeAT + + + + + + + + + + + + + + + + + + + + @include('layouts.components.header') + +
+ + @include('layouts.components.sidebar') + + + +
+ + + + + + + + + + + + + + + + + + @yield('javascript') + + \ No newline at end of file diff --git a/app/views/layouts/minimalLayout.blade.php b/app/views/layouts/minimalLayout.blade.php new file mode 100644 index 00000000..b41d6b99 --- /dev/null +++ b/app/views/layouts/minimalLayout.blade.php @@ -0,0 +1,66 @@ + + + + + + @if (trim($__env->yieldContent('html_title'))) + @yield('html_title') | + @endif SeAT + + + + + + + + + + + + + + + +
+ + @if ($errors->has()) + @foreach ($errors->all() as $error) +
+ + + Error! {{ $error }} +
+ @endforeach + @endif + + @if(Session::has('success')) +
+ + + Success! {{ Session::get('success') }} +
+ @endif + + @if(Session::has('warning')) +
+ + + Warning! {{ Session::get('warning') }} +
+ @endif + + + @yield('page_content') + +
+ + + + + + + + \ No newline at end of file diff --git a/app/views/mail/read.blade.php b/app/views/mail/read.blade.php new file mode 100644 index 00000000..fa6e2329 --- /dev/null +++ b/app/views/mail/read.blade.php @@ -0,0 +1,126 @@ +@extends('layouts.masterLayout') + +@section('html_title', 'Mail Timeline') + +@section('page_content') + + + +{{-- open a empty form to get a crsf token --}} +{{ Form::open(array()) }} {{ Form::close() }} + +
+
+ +
+
+

+ {{ $message->title }} + + From: {{ $message->senderName }} sent about {{ Carbon\Carbon::parse($message->sentDate)->diffForHumans() }} + @ {{ $message->sentDate }} + | + + {{-- corporations --}} + @if (strlen($message->toCorpOrAllianceID) > 0 && count(explode(',', $message->toCorpOrAllianceID)) > 0) + To Corp/Alliance: + @foreach (explode(',', $message->toCorpOrAllianceID) as $corp_alliance) + {{ $corp_alliance }} + @endforeach + @endif + + {{-- characters --}} + @if (strlen($message->toCharacterIDs) > 0 && count(explode(',', $message->toCharacterIDs)) > 0) + To Characters: + @foreach (explode(',', $message->toCharacterIDs) as $characterID) + {{ $characterID }} + @endforeach + @endif + + {{-- mailing lists --}} + @if (strlen($message->toListID) > 0 && count(explode(',', $message->toListID)) > 0) + To Mailing List: + @foreach (explode(',', $message->toListID) as $list) + {{ $list }} + @endforeach + @endif + + +

+
+ +
+
+ {{ $message->body }} +
+
+ +
+ +
+
+ +@stop + +@section('javascript') + +@stop \ No newline at end of file diff --git a/app/views/mail/subjects.blade.php b/app/views/mail/subjects.blade.php new file mode 100644 index 00000000..70924862 --- /dev/null +++ b/app/views/mail/subjects.blade.php @@ -0,0 +1,66 @@ +@extends('layouts.masterLayout') + +@section('html_title', 'Mail Subjects') + +@section('page_content') + +
+
+ +
+
+

All Mail By Subject

+
+
    + {{ $mail->links() }} +
+
+
+
+ + + + + + + + + + + + @foreach ($mail as $message) + + + + + + + + + @endforeach + + +
#DateFromToSubject
{{ $message->messageID }} + + {{ Carbon\Carbon::parse($message->sentDate)->diffForHumans() }} + + {{ $message->senderName }} + @if (strlen($message->toCorpOrAllianceID) > 0) + {{ count(explode(',', $message->toCorpOrAllianceID)) }} Corporation(s) / Alliance(s) + @endif + @if (strlen($message->toCharacterIDs) > 0) + {{ count(explode(',', $message->toCharacterIDs)) }} Character(s) + @endif + @if (strlen($message->toListID) > 0) + {{ count(explode(',', $message->toListID)) }} Mailing List(s) + @endif + {{ $message->title }} + {{ HTML::linkAction('MailController@getRead', 'Permalink', array('messageID' => $message->messageID ), array('class' => 'btn btn-primary btn-xs pull-right')) }} +
+
+
{{ $mail->links() }}
+
+
+
+ +@stop diff --git a/app/views/mail/timeline.blade.php b/app/views/mail/timeline.blade.php new file mode 100644 index 00000000..09c3ce3e --- /dev/null +++ b/app/views/mail/timeline.blade.php @@ -0,0 +1,147 @@ +@extends('layouts.masterLayout') + +@section('html_title', 'Mail Timeline') + +@section('page_content') + + + +{{-- open a empty form to get a crsf token --}} +{{ Form::open(array()) }} {{ Form::close() }} + +
+
+ + {{-- display day changes from this reference day --}} + {{-- */$day = Carbon\Carbon::now()->dayOfYear;/* --}} + + + @foreach ($mail as $message) + + @if ( Carbon\Carbon::parse($message->sentDate)->dayOfYear < $day) + {{-- */$day = Carbon\Carbon::parse($message->sentDate)->dayOfYear;/* --}} +

+ + Mail from from the day + {{ Carbon\Carbon::parse($message->sentDate)->toFormattedDateString() }} + which was about + {{ Carbon\Carbon::parse($message->sentDate)->diffForHumans() }} + +

+ @endif + +
+
+

+ {{ $message->title }}
+ + From: {{ $message->senderName }} sent about {{ Carbon\Carbon::parse($message->sentDate)->diffForHumans() }} + @ {{ $message->sentDate }} + | + + {{-- corporations --}} + @if (strlen($message->toCorpOrAllianceID) > 0 && count(explode(',', $message->toCorpOrAllianceID)) > 0) + To Corp/Alliance: + @foreach (explode(',', $message->toCorpOrAllianceID) as $corp_alliance) + {{ $corp_alliance }} + @endforeach + @endif + + {{-- characters --}} + @if (strlen($message->toCharacterIDs) > 0 && count(explode(',', $message->toCharacterIDs)) > 0) + To Characters: + @foreach (explode(',', $message->toCharacterIDs) as $characterID) + {{ $characterID }} + @endforeach + @endif + + {{-- mailing lists --}} + @if (strlen($message->toListID) > 0 && count(explode(',', $message->toListID)) > 0) + To Mailing List: + @foreach (explode(',', $message->toListID) as $list) + {{ $list }} + @endforeach + @endif + + +

+
+ +
+
+ {{ $message->body }} +
+
+ +
+ @endforeach + +
{{ $mail->links() }}
+
+
+ +@stop + +@section('javascript') + +@stop \ No newline at end of file diff --git a/app/views/password/remind.blade.php b/app/views/password/remind.blade.php new file mode 100644 index 00000000..05bbbdd5 --- /dev/null +++ b/app/views/password/remind.blade.php @@ -0,0 +1,29 @@ +@extends('layouts.minimalLayout') + +@section('html_title', 'Password Reset') + +@section('page_content') + +
+
SeAT | Password Reset
+ + {{ Form::open(array('action' => 'RemindersController@postRemind')) }} + +
+

Please enter your email address to receive a password reset link.

+
+ {{ Form::text('email', null, array('class' => 'form-control', 'placeholder' => 'Email Address'), 'required', 'autofocus') }} +
+ +
+ + + + {{ Form::close() }} +
+@stop diff --git a/app/views/password/reset.blade.php b/app/views/password/reset.blade.php new file mode 100644 index 00000000..58229b1a --- /dev/null +++ b/app/views/password/reset.blade.php @@ -0,0 +1,41 @@ +@extends('layouts.minimalLayout') + +@section('html_title', 'Password Reset') + +@section('page_content') + +
+
SeAT | Password Reset
+ + {{ Form::open(array('action' => 'RemindersController@postReset')) }} + +
+

+ Please fill out the below form to reset your password. For security reasons, please ensure that you enter the email address + that this link was sent to originally as well. +

+

Passwords must be at least six (6) characters long

+ + {{ Form::hidden('token', $token) }} + +
+ {{ Form::text('email', null, array('class' => 'form-control', 'placeholder' => 'Email Address'), 'required', 'autofocus') }} +
+
+ {{ Form::password('password', array('class' => 'form-control', 'placeholder' => 'Password')) }} +
+
+ {{ Form::password('password_confirmation', array('class' => 'form-control', 'placeholder' => 'Password Confirmation')) }} +
+
+ + + + {{ Form::close() }} +
+@stop diff --git a/app/views/queue/status.blade.php b/app/views/queue/status.blade.php new file mode 100644 index 00000000..80bfea6b --- /dev/null +++ b/app/views/queue/status.blade.php @@ -0,0 +1,286 @@ +@extends('layouts.masterLayout') + +@section('html_title', 'Queue Status') + +@section('page_content') + +
+
+
+
+

+ {{ $redis_count }} +

+

+ Jobs in the Redis Queue, with a Redis status of: {{ $redis_status }} +

+
+
+
+
+ +
+
+ +
+
+

+ {{ $db_queue_count }} +

+

+ Queued Jobs +

+
+
+
+
+ +
+
+

+ {{ $db_done_count }} +

+

+ Done Jobs +

+
+
+
+
+ +
+
+

+ {{ $db_working_count }} +

+

+ Working Jobs +

+
+
+
+
+ +
+
+

+ {{ $db_error_count }} +

+

+ Error Jobs +

+
+
+
+
+
+
+
+ +
+
+

Last Error Messages

+
+ + +
+
+
+ @if (count($db_errors) > 0) + + + + + + + + + + + + @foreach ($db_errors as $error) + + + + + + + + + + @endforeach + +
OwnerScopeAPIStatusCreatedUpdated
{{ $error->ownerID }}{{ $error->scope }}{{ $error->api }}{{ $error->output }}{{ Carbon\Carbon::parse($error->created_at)->diffForHumans() }}{{ Carbon\Carbon::parse($error->updated_at)->diffForHumans() }}
+ @else +

No Job Errors

+ @endif +
+
+
+
+ +
+
+

Current Working Jobs

+
+ + +
+
+
+ @if (count($db_working) > 0) + + + + + + + + + + + @foreach ($db_working as $work) + + + + + + + + + @endforeach + +
OwnerScopeAPIStatusCreatedUpdated
{{ $work->ownerID }}{{ $work->scope }}{{ $work->api }}{{ $work->output }}{{ Carbon\Carbon::parse($work->created_at)->diffForHumans() }}{{ Carbon\Carbon::parse($work->updated_at)->diffForHumans() }}
+ @else + @if ($db_queue_count > 0) +

No Working Jobs, but there are jobs in the queue. Are the workers started?

+ @else +

No Working Jobs

+ @endif + @endif +
+
+
+
+
+
+

Queued Jobs

+
+ + +
+
+
+ @if (count($db_queue) > 0) + + + + + + + + + + @foreach ($db_queue as $queue) + + + + + + + + + @endforeach + +
OwnerScopeAPICreatedUpdated
{{ $queue->ownerID }}{{ $queue->scope }}{{ $queue->api }}{{ $queue->output }}{{ Carbon\Carbon::parse($queue->created_at)->diffForHumans() }}{{ Carbon\Carbon::parse($queue->updated_at)->diffForHumans() }}
+ @else + @if ($db_queue_count > 0) +

No Working Jobs, but there are jobs in the queue. Are the workers started?

+ @else +

No Working Jobs

+ @endif + @endif +
+
+
+
+@stop + +@section('javascript') + +@stop \ No newline at end of file diff --git a/app/views/register/register.blade.php b/app/views/register/register.blade.php new file mode 100644 index 00000000..20556317 --- /dev/null +++ b/app/views/register/register.blade.php @@ -0,0 +1,18 @@ +@extends('layouts.minimalLayout') +@section('page_content') +
+
Sorry
+ +
+

Signups are currently not enabled.

+
+ +
+@stop diff --git a/app/views/user/login.blade.php b/app/views/user/login.blade.php new file mode 100644 index 00000000..7f21b400 --- /dev/null +++ b/app/views/user/login.blade.php @@ -0,0 +1,32 @@ +@extends('layouts.minimalLayout') + +@section('html_title', 'Sign In') + +@section('page_content') + +
+
SeAT | Sign In
+ + {{ Form::open(array('action' => 'UserController@postSignIn')) }} + +
+
+ {{ Form::text('username', null, array('class' => 'form-control', 'placeholder' => 'User ID'), 'required', 'autofocus') }} +
+
+ {{ Form::password('password', array('class' => 'form-control', 'placeholder' => 'Password')) }} +
+
+ {{ Form::checkbox('remember_me', 'yes') }} Remember me +
+
+ + + + {{ Form::close() }} +
+@stop diff --git a/artisan b/artisan new file mode 100755 index 00000000..36bb2d98 --- /dev/null +++ b/artisan @@ -0,0 +1,74 @@ +#!/usr/bin/env php +setRequestForConsoleEnvironment(); + +$artisan = Illuminate\Console\Application::start($app); + +/* +|-------------------------------------------------------------------------- +| Run The Artisan Application +|-------------------------------------------------------------------------- +| +| When we run the console application, the current CLI command will be +| executed in this console and the response sent back to a terminal +| or another output device for the developers. Here goes nothing! +| +*/ + +$status = $artisan->run(); + +/* +|-------------------------------------------------------------------------- +| Shutdown The Application +|-------------------------------------------------------------------------- +| +| Once Artisan has finished running. We will fire off the shutdown events +| so that any final work may be done by the application before we shut +| down the process. This is the last thing to happen to the request. +| +*/ + +$app->shutdown(); + +exit($status); \ No newline at end of file diff --git a/bootstrap/autoload.php b/bootstrap/autoload.php new file mode 100644 index 00000000..6b329312 --- /dev/null +++ b/bootstrap/autoload.php @@ -0,0 +1,75 @@ + __DIR__.'/../app', + + /* + |-------------------------------------------------------------------------- + | Public Path + |-------------------------------------------------------------------------- + | + | The public path contains the assets for your web application, such as + | your JavaScript and CSS files, and also contains the primary entry + | point for web requests into these applications from the outside. + | + */ + + 'public' => __DIR__.'/../public', + + /* + |-------------------------------------------------------------------------- + | Base Path + |-------------------------------------------------------------------------- + | + | The base path is the root of the Laravel installation. Most likely you + | will not need to change this value. But, if for some wild reason it + | is necessary you will do so here, just proceed with some caution. + | + */ + + 'base' => __DIR__.'/..', + + /* + |-------------------------------------------------------------------------- + | Storage Path + |-------------------------------------------------------------------------- + | + | The storage path is used by Laravel to store cached Blade views, logs + | and other pieces of information. You may modify the path here when + | you want to change the location of this directory for your apps. + | + */ + + 'storage' => __DIR__.'/../app/storage', + +); diff --git a/bootstrap/start.php b/bootstrap/start.php new file mode 100644 index 00000000..7eeea501 --- /dev/null +++ b/bootstrap/start.php @@ -0,0 +1,72 @@ +detectEnvironment(array( + + 'local' => array('your-machine-name'), + +)); + +/* +|-------------------------------------------------------------------------- +| Bind Paths +|-------------------------------------------------------------------------- +| +| Here we are binding the paths configured in paths.php to the app. You +| should not be changing these here. If you need to change these you +| may do so within the paths.php file and they will be bound here. +| +*/ + +$app->bindInstallPaths(require __DIR__.'/paths.php'); + +/* +|-------------------------------------------------------------------------- +| Load The Application +|-------------------------------------------------------------------------- +| +| Here we will load this Illuminate application. We will keep this in a +| separate location so we can isolate the creation of an application +| from the actual running of the application with a given request. +| +*/ + +$framework = $app['path.base'].'/vendor/laravel/framework/src'; + +require $framework.'/Illuminate/Foundation/start.php'; + +/* +|-------------------------------------------------------------------------- +| Return The Application +|-------------------------------------------------------------------------- +| +| This script returns the application instance. The instance is given to +| the calling script so we can separate the building of the instances +| from the actual running of the application and sending responses. +| +*/ + +return $app; diff --git a/composer.json b/composer.json new file mode 100644 index 00000000..ddb62bf6 --- /dev/null +++ b/composer.json @@ -0,0 +1,43 @@ +{ + "name": "laravel/laravel", + "description": "The Laravel Framework.", + "keywords": ["framework", "laravel"], + "license": "MIT", + "require": { + "laravel/framework": "4.1.*", + "3rdpartyeve/phealng": "0.3.5", + "pda/pheanstalk": "dev-master", + "indatus/dispatcher": "dev-master" + }, + "autoload": { + "classmap": [ + "app/commands", + "app/commands/scheduled", + "app/controllers", + "app/models", + "app/queues", + "app/eveapi", + "app/database/migrations", + "app/database/seeds", + "app/services", + "app/tests/TestCase.php" + ] + }, + "scripts": { + "post-install-cmd": [ + "php artisan clear-compiled", + "php artisan optimize" + ], + "post-update-cmd": [ + "php artisan clear-compiled", + "php artisan optimize" + ], + "post-create-project-cmd": [ + "php artisan key:generate" + ] + }, + "config": { + "preferred-install": "dist" + }, + "minimum-stability": "stable" +} diff --git a/docs/INSTALL_Centos.md b/docs/INSTALL_Centos.md new file mode 100644 index 00000000..fde9e912 --- /dev/null +++ b/docs/INSTALL_Centos.md @@ -0,0 +1,129 @@ +## SeAT - Simple (or Stupid) EVE Online API Tool ## + +### Introduction ### +SeAT attempts to be a EVE Onlineā„¢ Corporation Management Tool written in PHP using the [Laravel][1] Framework. If the fact that its written in PHP makes you mad or want to complain by telling us how bad PHP is (cause you read in online where & someone told you its bad), then I'm pretty happy that we have come this far. If not, well, read on :) + +### Requirements ### +Installing SeAT *should* be relatively simple. At a high level, the main requirements for SeAT is: + + - [PHP (5.3+)][2] + - [Apache][3] + - [Redis][4] + - [supervisord][5] + - [MySQL][6] + +SeAT was developed for Linux and has been tested to work fine on CentOS. Chances are you could get it going pretty easily on many other Linux distros, so feel free to contribute docs with install guides. As far as windows support goes... well.... + +### Installation ### +The following installation assumes you are using CentOS. For the Debian/Ubuntu folk, most of the `yum install` commands will probably end up being things like `apt-get install`. + +#### 1. Install & Configure MySQL #### +For CentOS, installation is pretty simple: +As `root`, run: + - `yum install mysql-server` + - `mysql_secure_installation`, choosing a strong password for your `root` mysql user + - `chkconfig mysqld on` + - `/etc/init.d/mysqld start` +Next, we will add a user for SeAT and configure a password for it. +As any user, run: + - `mysql -uroot -p`. Enter the `root` MySQL password you chose in the previous step. + - On the `mysql>` prompt: `create database seat;` + - `grant all on seat.* to seat@localhost identified by 'securepassword';` + - Press `crtl`+`d` to log out of the prompt. + +#### 2. Install & Configure PHP / Apache #### +PHP & MySQL is pretty easy too: + - `yum install httpd php-mysql php-process` + - `chkconfig httpd on` + - `/etc/init.d/httpd start` + +#### 3. Install & Configure Redis #### +Same thing for Redis + - `yum install redis` + - `chkconfig redis on` + - `/etc/init.d/redis start` + +#### 4. Get SeAT #### +Finally, we can get to the SeAT stuff itself. You are going to want to clone the repository. As this is a Git repository, make sure you have `git` installed. + - `yum install git` + +Next, clone the respoitory somwhere on disk. I'll reccomend `/var/www`: + - `cd /var/www` + - `git clone https://github.com/eve-seat/seat.git` + - `sudo chmod -R guo+w app/storage` to ensure that the web server can write to the storage location + +After seat is downloaded, we need to get composer to help us install the applications dependencies and generate autoload files: + - `cd /var/www` + - `curl -sS https://getcomposer.org/installer | php` + - `php composer.phar install` + +#### 5. Get EVE SDE's #### +Again, assuming you used `/var/www`, a tool to download the required static data exports can be found in `/var/www/seat/evesde/update_sde.sh`. +This tool can be run with: + - `sh /var/www/seat/evesde/update_sde.sh` + +Once it completes the downloads, a directory with a name starting with `SeAT-` will be located in `/tmp` on your machine. This directory containts static data that can just be imported into your database. The command will look something like: + +`mysql -u seat -p seat < /var/SeAT-109831-39871098278970987/*.sql` + +Once the import has been completed, you can safely delete the `/tmp/SeAT-*` directory. + +#### 6. Configure SeAT #### +SeAT configuration lives in `app/config`. Assuming you cloned to `/var/www`, the configs will be in `/var/www/seat/app/config`. + +Edit the fowlling files: + - database.php + - cache.php + +#### 7. Install & Configure supervisord #### +Supervisor will be used to keep the workers alive that need to process API jobs. The amount of workers that you start I guess depends on how many keys you have to process. For me, 4 workers seem to work just fine. Set it up by running: + - `yum install supervisor` + - `chkconfig supervisord on` + +We now have to configure the actual workers. We go this by adding `program` configuration blocks to `/etc/supervisord.conf`. A sample configuration for this block is located in `docs/` and can simply be added to the bottom of the existing configuration file. Note that the sample has the program defined as `[program:seat1]`. If you want to run 4 workers, you need to add this to the `supervisord.conf` *4* times. So you will have 4 blocks with incrementing numbers ie. `[program:seat1]`, `[program:seat2]`, `[program:seat3]` & `[program:seat4]`. + +Once this is done, save the file and start supervisord with `/etc/init.d/supervisord start`. + +You can checkup on the status of the workers with `supervisorctl status`: + +``` +[root@server ~]# supervisorctl status +seat1 RUNNING pid 23583, uptime 1 day, 0:18:27 +seat2 RUNNING pid 23584, uptime 1 day, 0:18:27 +seat3 RUNNING pid 23585, uptime 1 day, 0:18:27 +seat4 RUNNING pid 23582, uptime 1 day, 0:18:27 +``` + +SeAT should now process jobs that enter the job queue. + +#### 8. Setup cron #### +Setup the cronjob for SeAT. This job should run as a user that has access to SeAT's location: + - `crontab -e` + - Paste this line: `* * * * * php scheduled:run 1>> /dev/null 2>&1` + +#### 9. Security ##### +The web interface has a default password of `seat!admin` and it is *highly* reccomended that you change this using the `seat:reset` artisan command: + +```bash +$ php artisan seat:reset +WARNING!!! This will RESET the current Administrator password! + +What is the new password to use for the admin user? : +Retype that password please: +The passwords match. Resetting to the new 12 char one. +Password has been changed successfully. +``` + +You should regenerate the applications security key: + +```bash +$ php artisan key:generate +Application key [YWIs6jkLtVRjhuAENP21KxW7FHD7M0LZ] set successfully. +``` + + [1]: http://laravel.com/ + [2]: http://www.php.net/ + [3]: http://httpd.apache.org/ + [4]: http://redis.io/ + [5]: http://supervisord.org/ + [6]: http://www.mysql.com/ \ No newline at end of file diff --git a/docs/INSTALL_short.md b/docs/INSTALL_short.md new file mode 100644 index 00000000..26575908 --- /dev/null +++ b/docs/INSTALL_short.md @@ -0,0 +1,42 @@ +## SeAT - Simple (or Stupid) EVE Online API Tool ## + +### Introduction ### +SeAT attempts to be a EVE Onlineā„¢ Corporation Management Tool written in PHP using the [Laravel][1] Framework. If the fact that its written in PHP makes you mad or want to complain by telling us how bad PHP is (cause you read in online where & someone told you its bad), then I'm pretty happy that we have come this far. If not, well, read on :) + +### Requirements ### +Installing SeAT *should* be relatively simple. At a high level, the main requirements for SeAT is: + + - [PHP (5.3+)][2] + - [Apache][3] + - [Redis][4] + - [supervisord][5] + - [MySQL][6] + +SeAT was developed for Linux and has been tested to work fine on CentOS. Chances are you could get it going pretty easily on many other Linux distros, so feel free to contribute docs with install guides. As far as windows support goes... well.... + +### Installation ### +The quick and dirty to install SeAT: + +- Create a MySQL Database, i.e. `seat` with a user for SeAT to use. +- Install a web server such as Apache together with PHP & MySQL support +- Install Redis +- Clone the SeAT repository into a webroot such as `/var/www/seat` +- Get [composer](https://getcomposer.org/) and run `composer install` from the project root to install its dependencies. +- Get and import the EVE SDE's using the `evesde/update_sde.sh` script. +- Configure SeAT to match your environment. Files of interest are `app/config/database.php` and `app/config/cache.php` +- Run the database migration and seeding scripts with `php artisan migrate` & `php artisan db:seed` +- Install `supervisord` and edit the config to start workers to process queued jobs. A sample worker config is included in `docs/`. See note below +- Setup the SeAT cronjob: `* * * * * php scheduled:run 1>> /dev/null 2>&1` +- Regenerate the application security key with `php artisan key:generate` + +The web interface has a default password of `seat!admin` and it is *highly* reccomended that you change this using the `seat:reset` artisan command + +Note: +With supervisord 2 you need to copy the sample and rename to seat2, seat3 etc to start multipe workers. supervisord 3 I beleive introduces a `numprocs` option, that you can just specify to start multiple workers. + + [1]: http://laravel.com/ + [2]: http://www.php.net/ + [3]: http://httpd.apache.org/ + [4]: http://redis.io/ + [5]: http://supervisord.org/ + [6]: http://www.mysql.com/ \ No newline at end of file diff --git a/docs/supervisord-sample.conf b/docs/supervisord-sample.conf new file mode 100644 index 00000000..c6fbe31c --- /dev/null +++ b/docs/supervisord-sample.conf @@ -0,0 +1,11 @@ +[program:seat1] +command=/usr/bin/php /var/www/vhosts/seat/artisan queue:listen --timeout=3600 --tries 1 +directory=/var/www/vhosts/seat +stopwaitsecs=600 +user=apache +stdout_logfile=/var/log/seat_out.log +stdout_logfile_maxbytes=100MB +stdout_logfile_backups=10 +stderr_logfile=/var/log/seat_err.log +stderr_logfile_maxbytes=100MB +stderr_logfile_backups=5 \ No newline at end of file diff --git a/evesde/.gitignore b/evesde/.gitignore new file mode 100644 index 00000000..3d043cfe --- /dev/null +++ b/evesde/.gitignore @@ -0,0 +1,4 @@ +* +!required_sde +!update_sde.sh +!.gitignore \ No newline at end of file diff --git a/evesde/required_sde b/evesde/required_sde new file mode 100644 index 00000000..9ad35f7e --- /dev/null +++ b/evesde/required_sde @@ -0,0 +1,20 @@ +dgmTypeAttributes +invBlueprintTypes +invCategories +invContrabandTypes +invControlTowerResourcePurposes +invControlTowerResources +invFlags +invGroups +invItems +invMarketGroups +invMetaGroups +invMetaTypes +invNames +invPositions +invTypeMaterials +invTypeReactions +invTypes +invUniqueNames +mapDenormalize +staStations diff --git a/evesde/update_sde.sh b/evesde/update_sde.sh new file mode 100644 index 00000000..9692c5b3 --- /dev/null +++ b/evesde/update_sde.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +# 2013 - Leon Jacobs +# SeAT + +# This script should pull the latest static data as per $DUMPS from +# https://www.fuzzwork.co.uk/dump/ based in the expansion parameter + +URL="https://www.fuzzwork.co.uk/dump/" +EXPANSION="rubicon-1.3-95173" +EXTENTION="sql" +DUMPS="required_sde" +TEMPFILE=/tmp/SeAT-$(date | md5sum | awk '{ print $1 }') + +# check how many lines in $DUMPS for a form of progress +echo "We have $(wc -l $DUMPS | awk '{ print $1 }') static datadump files to do." +COUNT=$(wc -l $DUMPS | awk '{ print $1 }') +PROGRESS=1 + +# make the working directory in /tmp +echo "Creating temp directory $TEMPFILE" +mkdir -p $TEMPFILE + +# download each files +while read p; do + + echo "$PROGRESS/$COUNT - Getting dump $p from '$URL$EXPANSION/$p.$EXTENTION.bz2' .." + curl -s "$URL$EXPANSION/$p.$EXTENTION.bz2" > $TEMPFILE/$p.$EXTENTION.bz2 + + echo " Extracting $TEMPFILE/$p.$EXTENTION.bz2 ..." + bzip2 -d $TEMPFILE/$p.$EXTENTION.bz2 + + # increment progress + PROGRESS=$[PROGRESS + 1] + +done < $DUMPS + +# list $TEMPFILE +echo "Done, here is the contents of $TEMPFILE" +ls -lah $TEMPFILE + +# suggest MySQL import command +echo "Import the .sql thats in $TEMPFILE with something like:" +echo "mysql -u seat -p seat < $TEMPFILE/*.sql" diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 00000000..c42dc4f7 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,18 @@ + + + + + ./app/tests/ + + + \ No newline at end of file diff --git a/public/.htaccess b/public/.htaccess new file mode 100644 index 00000000..77827ae7 --- /dev/null +++ b/public/.htaccess @@ -0,0 +1,15 @@ + + + Options -MultiViews + + + RewriteEngine On + + # Redirect Trailing Slashes... + RewriteRule ^(.*)/$ /$1 [L,R=301] + + # Handle Front Controller... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + diff --git a/public/assets/css/app.css b/public/assets/css/app.css new file mode 100755 index 00000000..e7287b4d --- /dev/null +++ b/public/assets/css/app.css @@ -0,0 +1,2716 @@ +@import url(http://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,300italic,400italic,600italic); + +@import url(http://fonts.googleapis.com/css?family=Kaushan+Script); +/*! + * AdminLTE v1.0 + * Author: AlmsaeedStudio.com + * License: Open source - MIT + * Please visit http://opensource.org/licenses/MIT for more information +!*/ +/* + Core: General style +---------------------------- +*/ +html, +body { + overflow-x: hidden!important; + font-family: 'Source Sans Pro', sans-serif; + -webkit-font-smoothing: antialiased; + min-height: 100%; + background: #f9f9f9; +} +a { + color: #3c8dbc; +} +a:hover, +a:active, +a:focus { + outline: none; + text-decoration: none; + color: #72afd2; +} +/* Layouts */ +.wrapper { + min-height: 100%; +} +.wrapper:before, +.wrapper:after { + display: table; + content: " "; +} +.wrapper:after { + clear: both; +} +/* Header */ +body > .header { + position: absolute; + top: 0; + left: 0; + right: 0; + z-index: 1030; +} +/* Define 2 column template */ +.right-side, +.left-side { + min-height: 100%; + display: block; +} +/*right side - contins main content*/ +.right-side { + background-color: #f9f9f9; + margin-left: 220px; +} +/*left side - contains sidebar*/ +.left-side { + position: absolute; + width: 220px; + top: 0; +} +@media screen and (min-width: 992px) { + .left-side { + top: 50px; + } + /*Right side strech mode*/ + .right-side.strech { + margin-left: 0; + } + .right-side.strech > .content-header { + margin-top: 0px; + } + /* Left side collapse */ + .left-side.collapse-left { + left: -220px; + } +} +/*Give content full width on xs screens*/ +@media screen and (max-width: 992px) { + .right-side { + margin-left: 0; + } +} +/* + By default the layout is not fixed but if you add the class .fixed to the body element + the sidebar and the navbar will automatically become poisitioned fixed +*/ +body.fixed > .header, +body.fixed .left-side, +body.fixed .navbar { + position: fixed; +} +body.fixed > .header { + top: 0; + right: 0; + left: 0; +} +body.fixed .navbar { + left: 0; + right: 0; +} +body.fixed .wrapper { + margin-top: 50px; +} +/* Content */ +.content { + padding: 20px 15px; + /*background: #f9f9f9;*/ +} +/* Utility */ +/* H1 - H6 font */ +h1, +h2, +h3, +h4, +h5, +h6, +.h1, +.h2, +.h3, +.h4, +.h5, +.h6 { + font-family: 'Source Sans Pro', sans-serif; +} +/* Page Header */ +.page-header { + margin: 10px 0 20px 0; + font-size: 22px; +} +.page-header > small { + color: #666; + display: block; + margin-top: 5px; +} +/* All images should be responsive */ +img { + max-width: 100%important; +} +.sort-highlight { + background: #f4f4f4; + border: 1px dashed #ddd; + margin-bottom: 10px; +} +/* 10px padding and margins */ +.pad { + padding: 10px; +} +.margin { + margin: 10px; +} +/* Display inline */ +.inline { + display: inline; + width: auto; +} +/* Background colors */ +.bg-red, +.bg-yellow, +.bg-aqua, +.bg-blue, +.bg-light-blue, +.bg-green, +.bg-navy, +.bg-teal, +.bg-olive, +.bg-lime, +.bg-orange, +.bg-fuchsia, +.bg-purple, +.bg-maroon, +.bg-black { + color: #f9f9f9 !important; +} +.bg-gray { + background-color: #eaeaec !important; +} +.bg-black { + background-color: #222222 !important; +} +.bg-red { + background-color: #f56954 !important; +} +.bg-yellow { + background-color: #f39c12 !important; +} +.bg-aqua { + background-color: #00c0ef !important; +} +.bg-blue { + background-color: #0073b7 !important; +} +.bg-light-blue { + background-color: #3c8dbc !important; +} +.bg-green { + background-color: #00a65a !important; +} +.bg-navy { + background-color: #001f3f !important; +} +.bg-teal { + background-color: #39cccc !important; +} +.bg-olive { + background-color: #3d9970 !important; +} +.bg-lime { + background-color: #01ff70 !important; +} +.bg-orange { + background-color: #ff851b !important; +} +.bg-fuchsia { + background-color: #f012be !important; +} +.bg-purple { + background-color: #932ab6 !important; +} +.bg-maroon { + background-color: #85144b !important; +} +/* Text colors */ +.text-red { + color: #f56954 !important; +} +.text-yellow { + color: #f39c12 !important; +} +.text-aqua { + color: #00c0ef !important; +} +.text-blue { + color: #0073b7 !important; +} +.text-light-blue { + color: #3c8dbc !important; +} +.text-green { + color: #00a65a !important; +} +.text-navy { + color: #001f3f !important; +} +.text-teal { + color: #39cccc !important; +} +.text-olive { + color: #3d9970 !important; +} +.text-lime { + color: #01ff70 !important; +} +.text-orange { + color: #ff851b !important; +} +.text-fuchsia { + color: #f012be !important; +} +.text-purple { + color: #932ab6 !important; +} +.text-maroon { + color: #85144b !important; +} +/*Hide elements by display none only*/ +.hide { + display: none !important; +} +/* Remove borders */ +.no-border { + border: 0px !important; +} +/* Remove padding */ +.no-padding { + padding: 0px !important; +} +/* Remove margins */ +.no-margin { + margin: 0px !important; +} +/* Remove box shadow */ +.no-shadow { + box-shadow: none!important; +} +/* Don't display when printing */ +@media print { + .no-print { + display: none; + } + .left-side, + .header, + .content-header { + display: none; + } + .right-side { + margin: 0; + } +} +/* Remove border radius */ +.flat { + -webkit-border-radius: 0 !important; + -moz-border-radius: 0 !important; + border-radius: 0 !important; +} +/* Change the color of the striped tables */ +.table-striped > tbody > tr:nth-child(odd) > td, +.table-striped > tbody > tr:nth-child(odd) > th { + background-color: #f3f4f5; +} +/* .text-center in tables */ +table.text-center td, +table.text-center th { + text-align: center; +} +/* _fix for sparkline tooltip */ +.jqstooltip { + padding: 5px!important; + width: auto!important; + height: auto!important; +} +/* + Components: navbar, logo and content header +------------------------------------------------- +*/ +body > .header { + position: relative; + max-height: 100px; + z-index: 1030; +} +body > .header .navbar { + height: 50px; + margin-bottom: 0; + margin-left: 220px; +} +body > .header .navbar .sidebar-toggle { + float: left; + padding: 9px 5px; + margin-top: 8px; + margin-right: 0; + margin-bottom: 8px; + margin-left: 5px; + background-color: transparent; + background-image: none; + border: 1px solid transparent; + -webkit-border-radius: 0 !important; + -moz-border-radius: 0 !important; + border-radius: 0 !important; +} +body > .header .navbar .sidebar-toggle:hover .icon-bar { + background: #f6f6f6; +} +body > .header .navbar .sidebar-toggle .icon-bar { + display: block; + width: 22px; + height: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +body > .header .navbar .sidebar-toggle .icon-bar + .icon-bar { + margin-top: 4px; +} +body > .header .navbar .nav > li.user > a { + font-weight: bold; +} +body > .header .navbar .nav > li.user > a > .fa, +body > .header .navbar .nav > li.user > a > .glyphicon, +body > .header .navbar .nav > li.user > a > .ion { + margin-right: 5px; +} +body > .header .navbar .nav > li > a > .label { + -webkit-border-radius: 50%; + -moz-border-radius: 50%; + border-radius: 50%; + position: absolute; + top: 7px; + right: 2px; + font-size: 10px; + font-weight: normal; + width: 15px; + height: 15px; + line-height: 1.0em; + text-align: center; + padding: 2px; +} +body > .header .navbar .nav > li > a:hover > .label { + top: 3px; +} +body > .header .logo { + float: left; + font-size: 20px; + line-height: 50px; + text-align: center; + padding: 0 10px; + width: 220px; + /*font-family: 'Kaushan Script', cursive;*/ + font-weight: 500; + height: 50px; + display: block; +} +body > .header .logo .icon { + margin-right: 10px; +} +.right-side > .content-header { + position: relative; + padding: 15px 15px 10px 20px; +} +.right-side > .content-header > h1 { + margin: 0; + font-size: 24px; +} +.right-side > .content-header > h1 > small { + font-size: 15px; + display: inline-block; + padding-left: 4px; + font-weight: 300; +} +.right-side > .content-header > .breadcrumb { + float: right; + background: transparent; + margin-top: 0px; + margin-bottom: 0; + font-size: 12px; + padding: 7px 5px; + position: absolute; + top: 15px; + right: 10px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} +.right-side > .content-header > .breadcrumb > li > a { + color: #444; + text-decoration: none; +} +.right-side > .content-header > .breadcrumb > li > a > .fa, +.right-side > .content-header > .breadcrumb > li > a > .glyphicon, +.right-side > .content-header > .breadcrumb > li > a > .ion { + margin-right: 5px; +} +.right-side > .content-header > .breadcrumb > li + li:before { + content: '>\00a0'; +} +@media screen and (max-width: 767px) { + .right-side > .content-header > .breadcrumb { + position: relative; + margin-top: 5px; + top: 0; + right: 0; + float: none; + background: #efefef; + } +} +@media (max-width: 767px) { + .navbar .navbar-nav > li { + float: left; + } + .navbar-nav { + margin: 0; + float: left; + } + .navbar-nav > li > a { + padding-top: 15px; + padding-bottom: 15px; + line-height: 20px; + } + .navbar .navbar-right { + float: right; + } +} +@media screen and (max-width: 560px) { + body > .header { + position: relative; + } + body > .header .logo, + body > .header .navbar { + width: 100%; + float: none; + position: relative!important; + } + body > .header .navbar { + margin: 0; + } + body.fixed > .header { + position: fixed; + } + body.fixed > .wrapper, + body.fixed .sidebar-offcanvas { + margin-top: 100px!important; + } +} +/* + Component: Sidebar +-------------------------- +*/ +.sidebar { + margin-bottom: 5px; +} +.sidebar .sidebar-form input:focus { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + border-color: transparent!important; +} +.sidebar .sidebar-menu { + list-style: none; + margin: 0; + padding: 0; +} +.sidebar .sidebar-menu > li { + margin: 0; + padding: 0; +} +.sidebar .sidebar-menu > li > a { + padding: 12px 5px 12px 15px; + display: block; +} +.sidebar .sidebar-menu > li > a > .fa, +.sidebar .sidebar-menu > li > a > .glyphicon, +.sidebar .sidebar-menu > li > a > .ion { + width: 20px; +} +.sidebar .sidebar-menu .treeview-menu { + display: none; + list-style: none; + padding: 0; + margin: 0; +} +.sidebar .sidebar-menu .treeview-menu > li { + margin: 0; +} +.sidebar .sidebar-menu .treeview-menu > li > a { + padding: 5px 5px 5px 15px; + display: block; + font-size: 14px; + margin: 0px 0px; +} +.sidebar .sidebar-menu .treeview-menu > li > a > .fa, +.sidebar .sidebar-menu .treeview-menu > li > a > .glyphicon, +.sidebar .sidebar-menu .treeview-menu > li > a > .ion { + width: 20px; +} +.user-panel { + padding: 10px; +} +.user-panel:before, +.user-panel:after { + display: table; + content: " "; +} +.user-panel:after { + clear: both; +} +.user-panel > .image > img { + width: 45px; + height: 45px; +} +.user-panel > .info { + font-weight: 600; + padding: 5px 5px 5px 15px; + font-size: 14px; + line-height: 1; +} +.user-panel > .info > p { + margin-bottom: 9px; +} +.user-panel > .info > a { + text-decoration: none; + padding-right: 5px; + margin-top: 3px; + font-size: 11px; + font-weight: normal; +} +.user-panel > .info > a > .fa, +.user-panel > .info > a > .ion, +.user-panel > .info > a > .glyphicon { + margin-right: 3px; +} +/* + * Off Canvas + * -------------------------------------------------- + * Gives us the push menu effect + */ +@media screen and (max-width: 992px) { + .relative { + position: relative; + } + .row-offcanvas-right .sidebar-offcanvas { + right: -220px; + } + .row-offcanvas-left .sidebar-offcanvas { + left: -220px; + } + .row-offcanvas-right.active { + right: 220px; + } + .row-offcanvas-left.active { + left: 220px; + } + .sidebar-offcanvas { + left: 0; + } + body.fixed .sidebar-offcanvas { + margin-top: 50px; + left: -220px; + } + body.fixed .row-offcanvas-left.active .navbar { + left: 220px !important; + right: 0; + } + body.fixed .row-offcanvas-left.active .sidebar-offcanvas { + left: 0px; + } +} +/* + Dropdown menus +---------------------------- +*/ +/*Dropdowns in general*/ +.dropdown-menu { + -webkit-box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.1); + box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.1); + z-index: 2300; +} +.dropdown-menu > li > a > .glyphicon, +.dropdown-menu > li > a > .fa, +.dropdown-menu > li > a > .ion { + margin-right: 10px; +} +.dropdown-menu > li > a:hover { + background-color: #3c8dbc; + color: #f9f9f9; +} +/*Drodown in navbars*/ +.skin-blue .navbar .dropdown-menu > li > a { + color: #444444; +} +/* + Navbar custom dropdown menu +------------------------------------ +*/ +.navbar-nav > .notifications-menu > .dropdown-menu, +.navbar-nav > .messages-menu > .dropdown-menu, +.navbar-nav > .tasks-menu > .dropdown-menu { + width: 280px; + padding: 0 0 0 0!important; + margin: 0!important; + top: 100%; + border: 1px solid #dfdfdf; + -webkit-border-radius: 4px !important; + -moz-border-radius: 4px !important; + border-radius: 4px !important; +} +.navbar-nav > .notifications-menu > .dropdown-menu > li.header, +.navbar-nav > .messages-menu > .dropdown-menu > li.header, +.navbar-nav > .tasks-menu > .dropdown-menu > li.header { + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 0; + -webkit-border-bottom-left-radius: 0; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 0; + -moz-border-radius-bottomleft: 0; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + background-color: #ffffff; + padding: 7px 10px; + border-bottom: 1px solid #f4f4f4; + color: #444444; + font-size: 14px; +} +.navbar-nav > .notifications-menu > .dropdown-menu > li.header:after, +.navbar-nav > .messages-menu > .dropdown-menu > li.header:after, +.navbar-nav > .tasks-menu > .dropdown-menu > li.header:after { + bottom: 100%; + left: 92%; + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; + pointer-events: none; + border-color: rgba(255, 255, 255, 0); + border-bottom-color: #ffffff; + border-width: 7px; + margin-left: -7px; +} +.navbar-nav > .notifications-menu > .dropdown-menu > li.footer > a, +.navbar-nav > .messages-menu > .dropdown-menu > li.footer > a, +.navbar-nav > .tasks-menu > .dropdown-menu > li.footer > a { + -webkit-border-top-left-radius: 0px; + -webkit-border-top-right-radius: 0px; + -webkit-border-bottom-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-topleft: 0px; + -moz-border-radius-topright: 0px; + -moz-border-radius-bottomright: 4px; + -moz-border-radius-bottomleft: 4px; + border-top-left-radius: 0px; + border-top-right-radius: 0px; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + font-size: 12px; + background-color: #f4f4f4; + padding: 7px 10px; + border-bottom: 1px solid #eeeeee; + color: #444444; + text-align: center; +} +.navbar-nav > .notifications-menu > .dropdown-menu > li.footer > a:hover, +.navbar-nav > .messages-menu > .dropdown-menu > li.footer > a:hover, +.navbar-nav > .tasks-menu > .dropdown-menu > li.footer > a:hover { + background: #f4f4f4; + text-decoration: none; + font-weight: normal; +} +.navbar-nav > .notifications-menu > .dropdown-menu > li .menu, +.navbar-nav > .messages-menu > .dropdown-menu > li .menu, +.navbar-nav > .tasks-menu > .dropdown-menu > li .menu { + margin: 0; + padding: 0; + list-style: none; + overflow-x: hidden; +} +.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a, +.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a, +.navbar-nav > .tasks-menu > .dropdown-menu > li .menu > li > a { + display: block; + white-space: nowrap; + /* Prevent text from breaking */ + + border-bottom: 1px solid #f4f4f4; +} +.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a:hover, +.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a:hover, +.navbar-nav > .tasks-menu > .dropdown-menu > li .menu > li > a:hover { + background: #f6f6f6; + text-decoration: none; +} +.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a { + font-size: 12px; + color: #444444; +} +.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a > .glyphicon, +.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a > .fa, +.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a > .ion { + font-size: 20px; + width: 50px; + text-align: center; + padding: 15px 0px; + margin-right: 5px; + /* Default background and font colors */ + + background: #00c0ef; + color: #f9f9f9; + /* Fallback for browsers that doesn't support rgba */ + + color: rgba(255, 255, 255, 0.7); +} +.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a > .glyphicon.danger, +.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a > .fa.danger, +.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a > .ion.danger { + background: #f56954; +} +.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a > .glyphicon.warning, +.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a > .fa.warning, +.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a > .ion.warning { + background: #f39c12; +} +.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a > .glyphicon.success, +.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a > .fa.success, +.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a > .ion.success { + background: #00a65a; +} +.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a > .glyphicon.info, +.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a > .fa.info, +.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a > .ion.info { + background: #00c0ef; +} +.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a { + margin: 0px; + line-height: 20px; + padding: 10px 5px 10px 5px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a > div > img { + margin: auto 10px auto auto; + width: 40px; + height: 40px; + border: 1px solid #dddddd; +} +.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a > h4 { + padding: 0; + margin: 0 0 0 45px; + color: #444444; + font-size: 15px; +} +.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a > h4 > small { + color: #999999; + font-size: 10px; + float: right; +} +.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a > p { + margin: 0 0 0 45px; + font-size: 12px; + color: #888888; +} +.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a:before, +.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a:after { + display: table; + content: " "; +} +.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a:after { + clear: both; +} +.navbar-nav > .tasks-menu > .dropdown-menu > li .menu > li > a { + padding: 10px; +} +.navbar-nav > .tasks-menu > .dropdown-menu > li .menu > li > a > h3 { + font-size: 14px; + padding: 0; + margin: 0 0 10px 0; + color: #666666; +} +.navbar-nav > .tasks-menu > .dropdown-menu > li .menu > li > a > .progress { + padding: 0; + margin: 0; +} +.navbar-nav > .user-menu > .dropdown-menu { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + padding: 1px 0 0 0; + border-top-width: 0; + width: 280px; +} +.navbar-nav > .user-menu > .dropdown-menu:after { + bottom: 100%; + right: 10px; + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; + pointer-events: none; + border-color: rgba(255, 255, 255, 0); + border-bottom-color: #ffffff; + border-width: 10px; + margin-left: -10px; +} +.navbar-nav > .user-menu > .dropdown-menu > li.user-header { + height: 175px; + padding: 10px; + background: #3c8dbc; + text-align: center; +} +.navbar-nav > .user-menu > .dropdown-menu > li.user-header > img { + z-index: 5; + height: 90px; + width: 90px; + border: 8px solid; + border-color: transparent; + border-color: rgba(255, 255, 255, 0.2); +} +.navbar-nav > .user-menu > .dropdown-menu > li.user-header > p { + z-index: 5; + color: #f9f9f9; + color: rgba(255, 255, 255, 0.8); + font-size: 17px; + text-shadow: 2px 2px 3px #333333; + margin-top: 10px; +} +.navbar-nav > .user-menu > .dropdown-menu > li.user-header > p > small { + display: block; + font-size: 12px; +} +.navbar-nav > .user-menu > .dropdown-menu > li.user-body { + padding: 15px; + border-bottom: 1px solid #f4f4f4; + border-top: 1px solid #dddddd; +} +.navbar-nav > .user-menu > .dropdown-menu > li.user-body:before, +.navbar-nav > .user-menu > .dropdown-menu > li.user-body:after { + display: table; + content: " "; +} +.navbar-nav > .user-menu > .dropdown-menu > li.user-body:after { + clear: both; +} +.navbar-nav > .user-menu > .dropdown-menu > li.user-body > div > a { + color: #0073b7; +} +.navbar-nav > .user-menu > .dropdown-menu > li.user-footer { + background-color: #f9f9f9; + padding: 10px; +} +.navbar-nav > .user-menu > .dropdown-menu > li.user-footer:before, +.navbar-nav > .user-menu > .dropdown-menu > li.user-footer:after { + display: table; + content: " "; +} +.navbar-nav > .user-menu > .dropdown-menu > li.user-footer:after { + clear: both; +} +.navbar-nav > .user-menu > .dropdown-menu > li.user-footer .btn-default { + color: #666666; +} +/* Add fade animation to dropdown menus */ +.open > .dropdown-menu { + animation-name: fadeAnimation; + animation-duration: .7s; + animation-iteration-count: 1; + animation-timing-function: ease; + animation-fill-mode: forwards; + -webkit-animation-name: fadeAnimation; + -webkit-animation-duration: .7s; + -webkit-animation-iteration-count: 1; + -webkit-animation-timing-function: ease; + -webkit-animation-fill-mode: forwards; + -moz-animation-name: fadeAnimation; + -moz-animation-duration: .7s; + -moz-animation-iteration-count: 1; + -moz-animation-timing-function: ease; + -moz-animation-fill-mode: forwards; +} +@keyframes fadeAnimation { + from { + opacity: 0; + top: 120%; + } + to { + opacity: 1; + top: 100%; + } +} +@-webkit-keyframes fadeAnimation { + from { + opacity: 0; + top: 120%; + } + to { + opacity: 1; + top: 100%; + } +} +/* Fix dropdown menu for small screens to display correctly on small screens */ +@media screen and (max-width: 767px) { + .navbar-nav > .notifications-menu > .dropdown-menu, + .navbar-nav > .user-menu > .dropdown-menu, + .navbar-nav > .tasks-menu > .dropdown-menu, + .navbar-nav > .messages-menu > .dropdown-menu { + position: absolute; + top: 100%; + right: 0; + left: auto; + border-right: 1px solid #dddddd; + border-bottom: 1px solid #dddddd; + border-left: 1px solid #dddddd; + background: #ffffff; + } +} +/* Fix menu positions on xs screens to appear correctly and fully */ +@media screen and (max-width: 480px) { + .navbar-nav > .notifications-menu > .dropdown-menu > li.header, + .navbar-nav > .tasks-menu > .dropdown-menu > li.header, + .navbar-nav > .messages-menu > .dropdown-menu > li.header { + /* Remove arrow from the top */ + } + .navbar-nav > .notifications-menu > .dropdown-menu > li.header:after, + .navbar-nav > .tasks-menu > .dropdown-menu > li.header:after, + .navbar-nav > .messages-menu > .dropdown-menu > li.header:after { + border-width: 0px!important; + } + .navbar-nav > .tasks-menu > .dropdown-menu { + position: absolute; + right: -120px; + left: auto; + } + .navbar-nav > .notifications-menu > .dropdown-menu { + position: absolute; + right: -170px; + left: auto; + } + .navbar-nav > .messages-menu > .dropdown-menu { + position: absolute; + right: -210px; + left: auto; + } +} +/* + All form elements including input, select, textarea etc. +----------------------------------------------------------------- +*/ +.form-control { + -webkit-border-radius: 0px !important; + -moz-border-radius: 0px !important; + border-radius: 0px !important; + box-shadow: none; +} +.form-control:focus { + border-color: #3c8dbc !important; + box-shadow: none; +} +.form-group.has-success label { + color: #00a65a; +} +.form-group.has-success .form-control { + border-color: #00a65a !important; + box-shadow: none; +} +.form-group.has-warning label { + color: #f39c12; +} +.form-group.has-warning .form-control { + border-color: #f39c12 !important; + box-shadow: none; +} +.form-group.has-error label { + color: #f56954; +} +.form-group.has-error .form-control { + border-color: #f56954 !important; + box-shadow: none; +} +/* Input group */ +.input-group .input-group-addon { + border-radius: 0; + background-color: #f4f4f4; +} +/* button groups */ +.btn-group-vertical .btn.btn-flat:first-of-type, +.btn-group-vertical .btn.btn-flat:last-of-type { + border-radius: 0; +} +/* Checkbox and radio inputs */ +.checkbox, +.radio { + padding-left: 0; +} +/* + Compenent: Progress bars +-------------------------------- +*/ +/* size variation */ +.progress.sm { + height: 10px; +} +.progress.xs { + height: 7px; +} +/* Vertical bars */ +.progress.vertical { + position: relative; + width: 30px; + height: 200px; + display: inline-block; + margin-right: 10px; +} +.progress.vertical > .progress-bar { + width: 100%!important; + position: absolute; + bottom: 0; +} +.progress.vertical.sm { + width: 20px; +} +.progress.vertical.xs { + width: 10px; +} +/* Remove margins from progress bars when put in a table */ +.table tr > td .progress { + margin: 0; +} +.progress-bar-light-blue, +.progress-bar-primary { + background-color: #3c8dbc; +} +.progress-striped .progress-bar-light-blue, +.progress-striped .progress-bar-primary { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-green, +.progress-bar-success { + background-color: #00a65a; +} +.progress-striped .progress-bar-green, +.progress-striped .progress-bar-success { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-aqua, +.progress-bar-info { + background-color: #00c0ef; +} +.progress-striped .progress-bar-aqua, +.progress-striped .progress-bar-info { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-yellow, +.progress-bar-warning { + background-color: #f39c12; +} +.progress-striped .progress-bar-yellow, +.progress-striped .progress-bar-warning { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-red, +.progress-bar-danger { + background-color: #f56954; +} +.progress-striped .progress-bar-red, +.progress-striped .progress-bar-danger { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +/* + Component: Small boxes +*/ +.small-box { + position: relative; + display: block; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + margin-bottom: 15px; +} +.small-box > .inner { + padding: 10px; +} +.small-box > .small-box-footer { + position: relative; + text-align: center; + padding: 3px 0; + color: #fff; + color: rgba(255, 255, 255, 0.8); + display: block; + z-index: 10; + background: rgba(0, 0, 0, 0.1); + text-decoration: none; +} +.small-box > .small-box-footer:hover { + color: #fff; + background: rgba(0, 0, 0, 0.15); +} +.small-box h3 { + font-size: 38px; + font-weight: bold; + margin: 0 0 10px 0; + white-space: nowrap; + padding: 0; +} +.small-box p { + font-size: 15px; +} +.small-box p > small { + display: block; + color: #f9f9f9; + font-size: 13px; + margin-top: 5px; +} +.small-box h3, +.small-box p { + z-index: 5px; +} +.small-box .icon { + position: absolute; + top: auto; + bottom: 5px; + right: 5px; + z-index: 0; + font-size: 90px; + color: rgba(0, 0, 0, 0.15); +} +.small-box:hover { + text-decoration: none; + color: #f9f9f9; +} +.small-box:hover .icon { + animation-name: tansformAnimation; + animation-duration: .5s; + animation-iteration-count: 1; + animation-timing-function: ease; + animation-fill-mode: forwards; + -webkit-animation-name: tansformAnimation; + -webkit-animation-duration: .5s; + -webkit-animation-iteration-count: 1; + -webkit-animation-timing-function: ease; + -webkit-animation-fill-mode: forwards; + -moz-animation-name: tansformAnimation; + -moz-animation-duration: .5s; + -moz-animation-iteration-count: 1; + -moz-animation-timing-function: ease; + -moz-animation-fill-mode: forwards; +} +@keyframes tansformAnimation { + from { + font-size: 90px; + } + to { + font-size: 100px; + } +} +@-webkit-keyframes tansformAnimation { + from { + font-size: 90px; + } + to { + font-size: 100px; + } +} +@media screen and (max-width: 480px) { + .small-box { + text-align: center; + } + .small-box .icon { + display: none; + } + .small-box p { + font-size: 12px; + } +} +/* + component: Boxes +------------------------- +*/ +.box { + position: relative; + background: #ffffff; + border-top: 2px solid #c1c1c1; + margin-bottom: 20px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + width: 100%; + box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1); +} +.box.box-primary { + border-top-color: #3c8dbc; +} +.box.box-info { + border-top-color: #00c0ef; +} +.box.box-danger { + border-top-color: #f56954; +} +.box.box-warning { + border-top-color: #f39c12; +} +.box.box-success { + border-top-color: #00a65a; +} +.box.height-control .box-body { + max-height: 300px; + overflow: auto; +} +.box .box-header { + position: relative; + -webkit-border-top-left-radius: 3px; + -webkit-border-top-right-radius: 3px; + -webkit-border-bottom-right-radius: 0; + -webkit-border-bottom-left-radius: 0; + -moz-border-radius-topleft: 3px; + -moz-border-radius-topright: 3px; + -moz-border-radius-bottomright: 0; + -moz-border-radius-bottomleft: 0; + border-top-left-radius: 3px; + border-top-right-radius: 3px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + border-bottom: 0px solid #f4f4f4; + color: #444; + padding-bottom: 10px; +} +.box .box-header:before, +.box .box-header:after { + display: table; + content: " "; +} +.box .box-header:after { + clear: both; +} +.box .box-header > .fa, +.box .box-header > .glyphicon, +.box .box-header > .ion, +.box .box-header .box-title { + display: inline-block; + padding: 10px 0px 10px 10px; + margin: 0; + font-size: 20px; + font-weight: 400; + float: left; + cursor: default; +} +.box .box-header a { + color: #444; +} +.box .box-header > .box-tools { + padding: 5px 10px 5px 5px; +} +.box .box-body { + padding: 10px; + -webkit-border-top-left-radius: 0; + -webkit-border-top-right-radius: 0; + -webkit-border-bottom-right-radius: 3px; + -webkit-border-bottom-left-radius: 3px; + -moz-border-radius-topleft: 0; + -moz-border-radius-topright: 0; + -moz-border-radius-bottomright: 3px; + -moz-border-radius-bottomleft: 3px; + border-top-left-radius: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.box .box-body > table, +.box .box-body > .table { + margin-bottom: 0; +} +.box .box-body.chart-responsive { + width: 100%; + overflow: hidden; +} +.box .box-body > .chart { + position: relative; + overflow: hidden; + width: 100%; +} +.box .box-body > .chart svg, +.box .box-body > .chart canvas { + width: 100%!important; +} +.box .box-body .fc { + margin-top: 5px; +} +.box .box-body .fc-header-title h2 { + font-size: 15px; + line-height: 1.6em; + color: #666; + margin-left: 10px; +} +.box .box-body .fc-header-right { + padding-right: 10px; +} +.box .box-body .fc-header-left { + padding-left: 10px; +} +.box .box-body .fc-widget-header { + background: #fafafa; + box-shadow: inset 0px -3px 1px rgba(0, 0, 0, 0.02); +} +.box .box-body .fc-grid { + width: 100%; + border: 0; +} +.box .box-body .fc-widget-header:first-of-type, +.box .box-body .fc-widget-content:first-of-type { + border-left: 0; + border-right: 0; +} +.box .box-body .fc-widget-header:last-of-type, +.box .box-body .fc-widget-content:last-of-type { + border-right: 0; +} +.box .box-body .table { + margin-bottom: 0; +} +.box .box-body .full-width-chart { + margin: -19px; +} +.box .box-body.no-padding .full-width-chart { + margin: -9px; +} +.box .box-footer { + border-top: 1px solid #f4f4f4; + -webkit-border-top-left-radius: 0; + -webkit-border-top-right-radius: 0; + -webkit-border-bottom-right-radius: 3px; + -webkit-border-bottom-left-radius: 3px; + -moz-border-radius-topleft: 0; + -moz-border-radius-topright: 0; + -moz-border-radius-bottomright: 3px; + -moz-border-radius-bottomleft: 3px; + border-top-left-radius: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; + padding: 10px; + background-color: #ffffff; +} +.box.box-solid { + border-top: 0px; +} +.box.box-solid > .box-header { + padding-bottom: 0px!important; +} +.box.box-solid > .box-header .btn.btn-default { + background: transparent; +} +.box.box-solid.box-primary > .box-header { + color: #fff; + background: #3c8dbc; + background-color: #3c8dbc; +} +.box.box-solid.box-primary > .box-header a { + color: #444; +} +.box.box-solid.box-info > .box-header { + color: #fff; + background: #00c0ef; + background-color: #00c0ef; +} +.box.box-solid.box-info > .box-header a { + color: #444; +} +.box.box-solid.box-danger > .box-header { + color: #fff; + background: #f56954; + background-color: #f56954; +} +.box.box-solid.box-danger > .box-header a { + color: #444; +} +.box.box-solid.box-warning > .box-header { + color: #fff; + background: #f39c12; + background-color: #f39c12; +} +.box.box-solid.box-warning > .box-header a { + color: #444; +} +.box.box-solid.box-success > .box-header { + color: #fff; + background: #00a65a; + background-color: #00a65a; +} +.box.box-solid.box-success > .box-header a { + color: #444; +} +.box.box-solid > .box-header > .box-tools > .btn { + border: 0; + box-shadow: none; +} +.box.box-solid.collapsed-box .box-header { + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.box.box-solid[class*='bg'] > .box-header { + color: #fff; +} +.box .box-group > .box { + margin-bottom: 5px; +} +.box .knob-label { + text-align: center; + color: #333; + font-weight: 100; + font-size: 12px; + margin-bottom: 0.3em; +} +.box .todo-list { + margin: 0; + padding: 0px 0px; + list-style: none; +} +.box .todo-list > li { + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + padding: 10px; + background: #f3f4f5; + margin-bottom: 2px; + border-left: 2px solid #e6e7e8; + color: #444; +} +.box .todo-list > li:last-of-type { + margin-bottom: 0; +} +.box .todo-list > li.danger { + border-left-color: #f56954; +} +.box .todo-list > li.warning { + border-left-color: #f39c12; +} +.box .todo-list > li.info { + border-left-color: #00c0ef; +} +.box .todo-list > li.success { + border-left-color: #00a65a; +} +.box .todo-list > li.primary { + border-left-color: #3c8dbc; +} +.box .todo-list > li > input[type='checkbox'] { + margin: 0 10px 0 5px; +} +.box .todo-list > li .text { + display: inline-block; + margin-left: 5px; + font-weight: 600; +} +.box .todo-list > li .label { + margin-left: 10px; + font-size: 9px; +} +.box .todo-list > li .tools { + display: none; + float: right; + color: #f56954; +} +.box .todo-list > li .tools > .fa, +.box .todo-list > li .tools > .glyphicon, +.box .todo-list > li .tools > .ion { + margin-right: 5px; + cursor: pointer; +} +.box .todo-list > li:hover .tools { + display: inline-block; +} +.box .todo-list > li.done { + color: #999; +} +.box .todo-list > li.done .text { + text-decoration: line-through; + font-weight: 500; +} +.box .todo-list > li.done .label { + background: #eaeaec !important; +} +.box .todo-list .handle { + display: inline-block; + cursor: move; + margin: 0 5px; +} +.box .chat { + padding: 5px 20px 5px 10px; +} +.box .chat .item { + margin-bottom: 10px; +} +.box .chat .item:before, +.box .chat .item:after { + display: table; + content: " "; +} +.box .chat .item:after { + clear: both; +} +.box .chat .item > img { + width: 40px; + height: 40px; + border: 2px solid transparent; + -webkit-border-radius: 50% !important; + -moz-border-radius: 50% !important; + border-radius: 50% !important; +} +.box .chat .item > img.online { + border: 2px solid #00a65a; +} +.box .chat .item > img.offline { + border: 2px solid #f56954; +} +.box .chat .item > .message { + margin-left: 55px; + margin-top: -40px; +} +.box .chat .item > .message > .name { + display: block; + font-weight: 600; +} +.box .chat .item > .attachment { + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + background: #f0f0f0; + margin-left: 65px; + margin-right: 15px; + padding: 10px; +} +.box .chat .item > .attachment > h4 { + margin: 0 0 5px 0; + font-weight: 600; + font-size: 14px; +} +.box .chat .item > .attachment > p, +.box .chat .item > .attachment > .filename { + font-weight: 600; + font-size: 13px; + font-style: italic; + margin: 0; +} +.box .chat .item > .attachment:before, +.box .chat .item > .attachment:after { + display: table; + content: " "; +} +.box .chat .item > .attachment:after { + clear: both; +} +.box > .overlay, +.box > .loading-img { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +.box > .overlay { + z-index: 1010; + background: rgba(255, 255, 255, 0.7); +} +.box > .overlay.dark { + background: rgba(0, 0, 0, 0.5); +} +.box > .loading-img { + z-index: 1020; + background: transparent url('../img/ajax-loader1.gif') 50% 50% no-repeat; +} +/* +Component: timeline +-------------------- +*/ + +/* + Component: Buttons +------------------------- +*/ +.btn { + font-weight: 500; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + border: 1px solid transparent; + -webkit-box-shadow: inset 0px -2px 0px 0px rgba(0, 0, 0, 0.09); + -moz-box-shadow: inset 0px -2px 0px 0px rgba(0, 0, 0, 0.09); + box-shadow: inset 0px -1px 0px 0px rgba(0, 0, 0, 0.09); +} +.btn.btn-default { + background-color: #fafafa; + color: #666; + border-color: #ddd; + border-bottom-color: #ddd; +} +.btn.btn-default:hover, +.btn.btn-default:active, +.btn.btn-default.hover { + background-color: #f4f4f4!important; +} +.btn.btn-default.btn-flat { + border-bottom-color: #d9dadc; +} +.btn.btn-primary { + background-color: #3c8dbc; + border-color: #367fa9; +} +.btn.btn-primary:hover, +.btn.btn-primary:active, +.btn.btn-primary.hover { + background-color: #367fa9; +} +.btn.btn-success { + background-color: #00a65a; + border-color: #008d4c; +} +.btn.btn-success:hover, +.btn.btn-success:active, +.btn.btn-success.hover { + background-color: #008d4c; +} +.btn.btn-info { + background-color: #00c0ef; + border-color: #00acd6; +} +.btn.btn-info:hover, +.btn.btn-info:active, +.btn.btn-info.hover { + background-color: #00acd6; +} +.btn.btn-danger { + background-color: #f56954; + border-color: #f4543c; +} +.btn.btn-danger:hover, +.btn.btn-danger:active, +.btn.btn-danger.hover { + background-color: #f4543c; +} +.btn.btn-warning { + background-color: #f39c12; + border-color: #e08e0b; +} +.btn.btn-warning:hover, +.btn.btn-warning:active, +.btn.btn-warning.hover { + background-color: #e08e0b; +} +.btn.btn-sm { + font-size: 12px; +} +.btn.btn-lg { + padding: 10px 16px; +} +.btn.btn-block { + font-size: 15px; + padding: 10px; +} +.btn.btn-block.btn-sm { + font-size: 13px; + padding: 7px; +} +.btn.btn-flat { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + border-width: 1px; +} +.btn:active { + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + -moz-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} +.btn:focus { + outline: none; +} +.btn.btn-file { + position: relative; + width: 120px; + height: 35px; + overflow: hidden; +} +.btn.btn-file > input[type='file'] { + display: block !important; + width: 100% !important; + height: 35px !important; + opacity: 0 !important; + position: absolute; + top: -10px; + cursor: pointer; +} +.btn.btn-app { + position: relative; + padding: 15px 5px; + margin: 0 0 10px 10px; + min-width: 80px; + height: 60px; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + text-align: center; + color: #666; + border: 1px solid #ddd; + background-color: #fafafa; + font-size: 12px; +} +.btn.btn-app > .fa, +.btn.btn-app > .glyphicon, +.btn.btn-app > .ion { + font-size: 20px; + display: block; +} +.btn.btn-app:hover { + background: #f4f4f4; + color: #444; + border-color: #aaa; +} +.btn.btn-app:active, +.btn.btn-app:focus { + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + -moz-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} +.btn.btn-app > .badge { + position: absolute; + top: -3px; + right: -10px; + font-size: 10px; + font-weight: 400; +} +.btn.btn-social { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + opacity: 0.9; + padding: 0; +} +.btn.btn-social > .fa { + padding: 10px 0; + width: 40px; +} +.btn.btn-social > .fa + span { + border-left: 1px solid rgba(255, 255, 255, 0.3); +} +.btn.btn-social span { + padding: 10px; +} +.btn.btn-social:hover { + opacity: 1; +} +.btn.btn-circle { + width: 30px; + height: 30px; + line-height: 30px; + padding: 0; + -webkit-border-radius: 50%; + -moz-border-radius: 50%; + border-radius: 50%; +} +/* + Component: callout +------------------------ +*/ +.callout { + margin: 0 0 20px 0; + padding: 15px 30px 15px 15px; + border-left: 5px solid #eee; +} +.callout h4 { + margin-top: 0; +} +.callout p:last-child { + margin-bottom: 0; +} +.callout code, +.callout .highlight { + background-color: #fff; +} +.callout.callout-danger { + background-color: #fcf2f2; + border-color: #dFb5b4; +} +.callout.callout-warning { + background-color: #fefbed; + border-color: #f1e7bc; +} +.callout.callout-info { + background-color: #f0f7fd; + border-color: #d0e3f0; +} +.callout.callout-danger h4 { + color: #B94A48; +} +.callout.callout-warning h4 { + color: #C09853; +} +.callout.callout-info h4 { + color: #3A87AD; +} +/* + Component: alert +------------------------ +*/ +.alert { + padding-left: 30px; + margin-left: 15px; + position: relative; +} +.alert > .fa, +.alert > .glyphicon { + position: absolute; + left: -15px; + top: -15px; + width: 35px; + height: 35px; + -webkit-border-radius: 50%; + -moz-border-radius: 50%; + border-radius: 50%; + line-height: 35px; + text-align: center; + background: inherit; + border: inherit; +} +/* + Component: Navs +*/ +/* NAV PILLS */ +.nav.nav-pills > li > a { + border-top: 3px solid transparent; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + color: #444; +} +.nav.nav-pills > li > a > .fa, +.nav.nav-pills > li > a > .glyphicon, +.nav.nav-pills > li > a > .ion { + margin-right: 5px; +} +.nav.nav-pills > li.active > a, +.nav.nav-pills > li.active > a:hover { + background-color: #f6f6f6; + border-top-color: #3c8dbc; + color: #444; +} +.nav.nav-pills > li.active > a { + font-weight: 600; +} +.nav.nav-pills > li > a:hover { + background-color: #f6f6f6; +} +.nav.nav-pills.nav-stacked > li > a { + border-top: 0; + border-left: 3px solid transparent; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + color: #444; +} +.nav.nav-pills.nav-stacked > li.active > a, +.nav.nav-pills.nav-stacked > li.active > a:hover { + background-color: #f6f6f6; + border-left-color: #3c8dbc; + color: #444; +} +.nav.nav-pills.nav-stacked > li.header { + border-bottom: 1px solid #ddd; + color: #777; + margin-bottom: 10px; + padding: 5px 10px; + text-transform: uppercase; +} +/* NAV TABS */ +.nav-tabs-custom { + margin-bottom: 20px; + background: #fff; + box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1); +} +.nav-tabs-custom > .nav-tabs { + margin: 0; + border-bottom-color: #f4f4f4; +} +.nav-tabs-custom > .nav-tabs > li { + border-top: 3px solid transparent; + margin-bottom: -2px; + margin-right: 5px; +} +.nav-tabs-custom > .nav-tabs > li > a { + -webkit-border-radius: 0 !important; + -moz-border-radius: 0 !important; + border-radius: 0 !important; +} +.nav-tabs-custom > .nav-tabs > li > a, +.nav-tabs-custom > .nav-tabs > li > a:hover { + background: transparent; + margin: 0; +} +.nav-tabs-custom > .nav-tabs > li:not(.active) > a:hover, +.nav-tabs-custom > .nav-tabs > li:not(.active) > a:focus, +.nav-tabs-custom > .nav-tabs > li:not(.active) > a:active { + border-color: transparent; +} +.nav-tabs-custom > .nav-tabs > li.active { + border-top-color: #3c8dbc; +} +.nav-tabs-custom > .nav-tabs > li.active > a, +.nav-tabs-custom > .nav-tabs > li.active:hover > a { + background-color: #fff; +} +.nav-tabs-custom > .nav-tabs > li.active > a { + border-top: 0; + border-left-color: #f4f4f4; + border-right-color: #f4f4f4; +} +.nav-tabs-custom > .nav-tabs > li:first-of-type { + margin-left: 0px; +} +.nav-tabs-custom > .nav-tabs > li:first-of-type.active > a { + border-left-width: 0; +} +.nav-tabs-custom > .nav-tabs.pull-right { + float: none!important; +} +.nav-tabs-custom > .nav-tabs.pull-right > li { + float: right; +} +.nav-tabs-custom > .nav-tabs.pull-right > li:first-of-type { + margin-right: 0px; +} +.nav-tabs-custom > .nav-tabs.pull-right > li:first-of-type.active > a { + border-left-width: 1px; + border-right-width: 0px; +} +.nav-tabs-custom > .nav-tabs > li.header { + font-weight: 400; + line-height: 35px; + padding: 0 10px; + font-size: 20px; + color: #444; + cursor: default; +} +.nav-tabs-custom > .nav-tabs > li.header > .fa, +.nav-tabs-custom > .nav-tabs > li.header > .glyphicon, +.nav-tabs-custom > .nav-tabs > li.header > .ion { + margin-right: 10px; +} +.nav-tabs-custom > .tab-content { + background: #fff; + padding: 10px; +} +/* PAGINATION */ +.pagination > li > a { + background: #fafafa; + color: #666; + -webkit-box-shadow: inset 0px -2px 0px 0px rgba(0, 0, 0, 0.09); + -moz-box-shadow: inset 0px -2px 0px 0px rgba(0, 0, 0, 0.09); + box-shadow: inset 0px -1px 0px 0px rgba(0, 0, 0, 0.09); +} +.pagination > li:first-of-type a, +.pagination > li:last-of-type a { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +/* + Component: Mailbox +*/ +.mailbox .table-mailbox { + border-left: 1px solid #ddd; + border-right: 1px solid #ddd; + border-bottom: 1px solid #ddd; +} +.mailbox .table-mailbox tr.unread > td { + background-color: rgba(0, 0, 0, 0.05); + color: #000; + font-weight: 600; +} +.mailbox .table-mailbox tr > td > .fa.fa-star, +.mailbox .table-mailbox tr > td > .fa.fa-star-o, +.mailbox .table-mailbox tr > td > .glyphicon.glyphicon-star, +.mailbox .table-mailbox tr > td > .glyphicon.glyphicon-star-empty { + color: #f39c12; + cursor: pointer; +} +.mailbox .table-mailbox tr > td.small-col { + width: 30px; +} +.mailbox .table-mailbox tr > td.name { + width: 150px; + font-weight: 600; +} +.mailbox .table-mailbox tr > td.time { + text-align: right; + width: 100px; +} +.mailbox .table-mailbox tr > td { + white-space: nowrap; +} +.mailbox .table-mailbox tr > td > a { + color: #444; +} +@media screen and (max-width: 767px) { + .mailbox .nav-stacked > li:not(.header) { + float: left; + width: 50%; + } + .mailbox .nav-stacked > li:not(.header).header { + border: 0!important; + } + .mailbox .search-form { + margin-top: 10px; + } +} +/* + Page: locked screen +*/ +/* ADD THIS CLASS TO THE TAG */ +.lockscreen { + background: url(../img/blur-background09.jpg) repeat center center fixed; + -webkit-background-size: cover; + -moz-background-size: cover; + -o-background-size: cover; + background-size: cover; +} +/* Remove the background from the body element */ +.lockscreen > body { + background: transparent; +} +/* We will put the dynamically generated digital clock here */ +.lockscreen .headline { + color: #fff; + text-shadow: 1px 3px 5px rgba(0, 0, 0, 0.5); + font-weight: 300; + -webkit-font-smoothing: antialiased !important; + opacity: 0.8; + margin: 10px 0 30px 0; + font-size: 90px; +} +@media screen and (max-width: 480px) { + .lockscreen .headline { + font-size: 60px; + margin-bottom: 40px; + } +} +/* User name [optional] */ +.lockscreen .lockscreen-name { + text-align: center; + font-weight: 600; + font-size: 16px; +} +/* Will contain the image and the sign in form */ +.lockscreen-item { + padding: 0; + background: #fff; + position: relative; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + margin: 10px auto; + width: 290px; +} +.lockscreen-item:before, +.lockscreen-item:after { + display: table; + content: " "; +} +.lockscreen-item:after { + clear: both; +} +/* User image */ +.lockscreen-item > .lockscreen-image { + position: absolute; + left: -10px; + top: -30px; + background: #fff; + padding: 10px; + -webkit-border-radius: 50%; + -moz-border-radius: 50%; + border-radius: 50%; + z-index: 10; +} +.lockscreen-item > .lockscreen-image > img { + width: 70px; + height: 70px; + -webkit-border-radius: 50%; + -moz-border-radius: 50%; + border-radius: 50%; +} +/* Contains the password input and the login button */ +.lockscreen-item > .lockscreen-credentials { + margin-left: 80px; +} +.lockscreen-item > .lockscreen-credentials input { + border: 0 !important; +} +.lockscreen-item > .lockscreen-credentials .btn { + background-color: #fff; + border: 0; +} +/* Extra to give the user an option to navigate the website [optional]*/ +.lockscreen-link { + margin-top: 30px; + text-align: center; +} +/* + Page: register and login +*/ +.form-box { + width: 360px; + margin: 90px auto 0 auto; +} +.form-box .header { + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 0; + -webkit-border-bottom-left-radius: 0; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 0; + -moz-border-radius-bottomleft: 0; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + background: #3d9970; + box-shadow: inset 0px -3px 0px rgba(0, 0, 0, 0.2); + padding: 20px 10px; + text-align: center; + font-size: 26px; + font-weight: 300; + color: #fff; +} +.form-box .body, +.form-box .footer { + padding: 10px 20px; + background: #fff; + color: #444; +} +.form-box .body > .form-group, +.form-box .footer > .form-group { + margin-top: 20px; +} +.form-box .body > .form-group > input, +.form-box .footer > .form-group > input { + border: #fff; +} +.form-box .body > .btn, +.form-box .footer > .btn { + margin-bottom: 10px; +} +.form-box .footer { + -webkit-border-top-left-radius: 0; + -webkit-border-top-right-radius: 0; + -webkit-border-bottom-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-topleft: 0; + -moz-border-radius-topright: 0; + -moz-border-radius-bottomright: 4px; + -moz-border-radius-bottomleft: 4px; + border-top-left-radius: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} +@media (max-width: 767px) { + .form-box { + width: 90%; + } +} +/* + Page: 404 and 500 error pages +------------------------------------ +*/ +.error-page { + width: 600px; + margin: 20px auto 0 auto; +} +@media screen and (max-width: 767px) { + .error-page { + width: 100%; + } +} +.error-page > .headline { + float: left; + font-size: 100px; + font-weight: 300; +} +@media screen and (max-width: 767px) { + .error-page > .headline { + float: none; + text-align: center; + } +} +.error-page > .error-content { + margin-left: 190px; + display: block; +} +@media screen and (max-width: 767px) { + .error-page > .error-content { + margin-left: 0; + } +} +.error-page > .error-content > h3 { + font-weight: 300; + font-size: 25px; +} +@media screen and (max-width: 767px) { + .error-page > .error-content > h3 { + text-align: center; + } +} +.error-page:before, +.error-page:after { + display: table; + content: " "; +} +.error-page:after { + clear: both; +} +/* + Page: Invoice +*/ +.invoice { + position: relative; + width: 90%; + margin: 10px auto; + background: #fff; + border: 1px solid #f4f4f4; +} +.invoice-title { + margin-top: 0; +} +/* Enhancement for printing */ +@media print { + .invoice { + width: 100%; + border: 0; + margin: 0; + padding: 0; + } + .invoice-col { + float: left; + width: 33.3333333%; + } + .table-responsive { + overflow: auto; + } + .table-responsive > .table tr th, + .table-responsive > .table tr td { + white-space: normal!important; + } +} +/* + Skins + ----- +*/ +/* + Skin Blue + --------- +*/ +/* skin-blue navbar */ +.skin-blue .navbar { + background-color: #3c8dbc; +} +.skin-blue .navbar .nav a { + color: rgba(255, 255, 255, 0.8); +} +.skin-blue .navbar .nav > li > a:hover, +.skin-blue .navbar .nav > li > a:active, +.skin-blue .navbar .nav > li > a:focus, +.skin-blue .navbar .nav .open > a, +.skin-blue .navbar .nav .open > a:hover, +.skin-blue .navbar .nav .open > a:focus { + background: rgba(0, 0, 0, 0.1); + color: #f6f6f6; +} +.skin-blue .navbar .navbar-right > .nav { + margin-right: 10px; +} +.skin-blue .navbar .sidebar-toggle .icon-bar { + background: rgba(255, 255, 255, 0.8); +} +.skin-blue .navbar .sidebar-toggle:hover .icon-bar { + background: #f6f6f6 !important; +} +/* skin-blue logo */ +.skin-blue .logo { + background-color: #367fa9; + color: #f9f9f9; +} +.skin-blue .logo > a { + color: #f9f9f9; +} +.skin-blue .logo:hover { + background: #357ca5; +} +/* skin-blue content header */ +.skin-blue .right-side > .content-header { + background: #fbfbfb; + box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1); +} +/* Skin-blue user panel */ +.skin-blue .user-panel > .image > img { + border: 1px solid #dfdfdf; +} +.skin-blue .user-panel > .info, +.skin-blue .user-panel > .info > a { + color: #555555; +} +/* skin-blue sidebar */ +.skin-blue .sidebar { + border-bottom: 1px solid #fff; +} +.skin-blue .sidebar > .sidebar-menu > li { + border-top: 1px solid #fff; + border-bottom: 1px solid #dbdbdb; +} +.skin-blue .sidebar > .sidebar-menu > li:first-of-type { + border-top: 1px solid #dbdbdb; +} +.skin-blue .sidebar > .sidebar-menu > li:first-of-type > a { + border-top: 1px solid #fff; +} +.skin-blue .sidebar > .sidebar-menu > li > a { + margin-right: 1px; +} +.skin-blue .sidebar > .sidebar-menu > li > a:hover, +.skin-blue .sidebar > .sidebar-menu > li.active > a { + color: #222; + background: #f9f9f9; +} +.skin-blue .sidebar > .sidebar-menu > li > .treeview-menu { + margin: 0 1px; + background: #f9f9f9; +} +.skin-blue .left-side { + background: #f4f4f4; + -webkit-box-shadow: inset -3px 0px 8px -4px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset -3px 0px 8px -4px rgba(0, 0, 0, 0.1); + box-shadow: inset -3px 0px 8px -4px rgba(0, 0, 0, 0.07); +} +.skin-blue .sidebar a { + color: #555555; +} +.skin-blue .sidebar a:hover { + text-decoration: none; +} +.skin-blue .treeview-menu > li > a { + color: #777; +} +.skin-blue .treeview-menu > li.active > a, +.skin-blue .treeview-menu > li > a:hover { + color: #111; +} +.skin-blue .sidebar-form { + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + border: 1px solid #dbdbdb; + margin: 10px 10px; +} +.skin-blue .sidebar-form input[type="text"], +.skin-blue .sidebar-form .btn { + box-shadow: none; + background-color: #fafafa; + border: 1px solid #fafafa; + height: 35px; +} +.skin-blue .sidebar-form input[type="text"] { + color: #666; + -webkit-border-top-left-radius: 2px !important; + -webkit-border-top-right-radius: 0 !important; + -webkit-border-bottom-right-radius: 0 !important; + -webkit-border-bottom-left-radius: 2px !important; + -moz-border-radius-topleft: 2px !important; + -moz-border-radius-topright: 0 !important; + -moz-border-radius-bottomright: 0 !important; + -moz-border-radius-bottomleft: 2px !important; + border-top-left-radius: 2px !important; + border-top-right-radius: 0 !important; + border-bottom-right-radius: 0 !important; + border-bottom-left-radius: 2px !important; +} +.skin-blue .sidebar-form input[type="text"]:focus, +.skin-blue .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + background-color: #fff; + color: #666; +} +.skin-blue .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + border-left-color: #fff; +} +.skin-blue .sidebar-form .btn { + color: #999; + -webkit-border-top-left-radius: 0 !important; + -webkit-border-top-right-radius: 2px !important; + -webkit-border-bottom-right-radius: 2px !important; + -webkit-border-bottom-left-radius: 0 !important; + -moz-border-radius-topleft: 0 !important; + -moz-border-radius-topright: 2px !important; + -moz-border-radius-bottomright: 2px !important; + -moz-border-radius-bottomleft: 0 !important; + border-top-left-radius: 0 !important; + border-top-right-radius: 2px !important; + border-bottom-right-radius: 2px !important; + border-bottom-left-radius: 0 !important; +} +/* + Skin Black + -------- +*/ +/* skin-black navbar */ +.skin-black .navbar { + background-color: #ffffff; + border-bottom: 1px solid #eee; +} +.skin-black .navbar .nav a { + color: #333333; +} +.skin-black .navbar .nav > li > a:hover, +.skin-black .navbar .nav > li > a:active, +.skin-black .navbar .nav > li > a:focus, +.skin-black .navbar .nav .open > a, +.skin-black .navbar .nav .open > a:hover, +.skin-black .navbar .nav .open > a:focus { + background: #ffffff; + color: #999999; +} +.skin-black .navbar .navbar-right > .nav { + margin-right: 10px; +} +.skin-black .navbar .sidebar-toggle .icon-bar { + background: #333333; +} +.skin-black .navbar .sidebar-toggle:hover .icon-bar { + background: #999999 !important; +} +/* skin-black logo */ +.skin-black .logo { + background-color: #333333; + color: #f9f9f9; +} +.skin-black .logo > a { + color: #f9f9f9; +} +.skin-black .logo:hover { + background: #303030; +} +/* skin-black content header */ +.skin-black .right-side > .content-header { + background: transparent; + box-shadow: none; +} +/* Skin-red user panel */ +.skin-black .user-panel > .image > img { + border: 1px solid #444; +} +.skin-black .user-panel > .info, +.skin-black .user-panel > .info > a { + color: #eee; +} +/* skin-black sidebar */ +.skin-black .sidebar { + border-bottom: 1px solid #333; +} +.skin-black .sidebar > .sidebar-menu > li { + border-top: 1px solid #333; + border-bottom: 0px solid #444; +} +.skin-black .sidebar > .sidebar-menu > li:first-of-type { + border-top: 1px solid #444; +} +.skin-black .sidebar > .sidebar-menu > li:first-of-type > a { + border-top: 0px solid #333; +} +.skin-black .sidebar > .sidebar-menu > li > a { + margin-right: 1px; +} +.skin-black .sidebar > .sidebar-menu > li > a:hover, +.skin-black .sidebar > .sidebar-menu > li.active > a { + color: #f6f6f6; + background: #444; +} +.skin-black .sidebar > .sidebar-menu > li > .treeview-menu { + margin: 0 1px; + background: #444; +} +.skin-black .left-side { + background: #333; +} +.skin-black .sidebar a { + color: #eee; +} +.skin-black .sidebar a:hover { + text-decoration: none; +} +.skin-black .treeview-menu > li > a { + color: #ccc; +} +.skin-black .treeview-menu > li.active > a, +.skin-black .treeview-menu > li > a:hover { + color: #fff; +} +.skin-black .sidebar-form { + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + border: 0px solid #555; + margin: 10px 10px; +} +.skin-black .sidebar-form input[type="text"], +.skin-black .sidebar-form .btn { + box-shadow: none; + background-color: rgba(255, 255, 255, 0.1); + border: 0 solid rgba(255, 255, 255, 0.1); + height: 35px; + outline: none; +} +.skin-black .sidebar-form input[type="text"] { + color: #666; + -webkit-border-top-left-radius: 2px !important; + -webkit-border-top-right-radius: 0 !important; + -webkit-border-bottom-right-radius: 0 !important; + -webkit-border-bottom-left-radius: 2px !important; + -moz-border-radius-topleft: 2px !important; + -moz-border-radius-topright: 0 !important; + -moz-border-radius-bottomright: 0 !important; + -moz-border-radius-bottomleft: 2px !important; + border-top-left-radius: 2px !important; + border-top-right-radius: 0 !important; + border-bottom-right-radius: 0 !important; + border-bottom-left-radius: 2px !important; +} +.skin-black .sidebar-form input[type="text"]:focus, +.skin-black .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + background-color: #444; + border: 0; +} +.skin-black .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + border-left: 0; +} +.skin-black .sidebar-form .btn { + color: #999; + -webkit-border-top-left-radius: 0 !important; + -webkit-border-top-right-radius: 2px !important; + -webkit-border-bottom-right-radius: 2px !important; + -webkit-border-bottom-left-radius: 0 !important; + -moz-border-radius-topleft: 0 !important; + -moz-border-radius-topright: 2px !important; + -moz-border-radius-bottomright: 2px !important; + -moz-border-radius-bottomleft: 0 !important; + border-top-left-radius: 0 !important; + border-top-right-radius: 2px !important; + border-bottom-right-radius: 2px !important; + border-bottom-left-radius: 0 !important; + border-left: 0; +} +/*! + * iCheck v1.0.1, http://git.io/arlzeA + * ================================= + * Powerful jQuery and Zepto plugin for checkboxes and radio buttons customization + * + * (c) 2013 Damir Sultanov, http://fronteed.com + * MIT Licensed + */ +/* iCheck plugin Minimal skin, black +----------------------------------- */ +.icheckbox_minimal, +.iradio_minimal { + display: inline-block; + *display: inline; + vertical-align: middle; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: rgba(255, 255, 255, 0.7) url(iCheck/minimal/minimal.png) no-repeat; + border: none; + cursor: pointer; +} +.icheckbox_minimal { + background-position: 0 0; +} +.icheckbox_minimal.hover { + background-position: -20px 0; +} +.icheckbox_minimal.checked { + background-position: -40px 0; +} +.icheckbox_minimal.disabled { + background-position: -60px 0; + cursor: default; +} +.icheckbox_minimal.checked.disabled { + background-position: -80px 0; +} +.iradio_minimal { + background-position: -100px 0; +} +.iradio_minimal.hover { + background-position: -120px 0; +} +.iradio_minimal.checked { + background-position: -140px 0; +} +.iradio_minimal.disabled { + background-position: -160px 0; + cursor: default; +} +.iradio_minimal.checked.disabled { + background-position: -180px 0; +} +/* Retina support */ +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (-moz-min-device-pixel-ratio: 1.5), only screen and (-o-min-device-pixel-ratio: 3/2), only screen and (min-device-pixel-ratio: 1.5) { + .icheckbox_minimal, + .iradio_minimal { + background-image: url('iCheck/minimal/minimal@2x.png'); + -webkit-background-size: 200px 20px; + background-size: 200px 20px; + } +} +.pace .pace-progress { + background: #00c0ef; + position: fixed; + z-index: 2000; + top: 0; + left: 0; + height: 2px; + -webkit-transition: width 1s; + -moz-transition: width 1s; + -o-transition: width 1s; + transition: width 1s; +} +.pace-inactive { + display: none; +} diff --git a/public/assets/css/bootstrap.min.css b/public/assets/css/bootstrap.min.css new file mode 100755 index 00000000..c547283b --- /dev/null +++ b/public/assets/css/bootstrap.min.css @@ -0,0 +1,7 @@ +/*! + * Bootstrap v3.0.3 (http://getbootstrap.com) + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + */ + +/*! normalize.css v2.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a{background:transparent}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0;font-size:2em}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{height:0;-moz-box-sizing:content-box;box-sizing:content-box}mark{color:#000;background:#ff0}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid #c0c0c0}legend{padding:0;border:0}button,input,select,textarea{margin:0;font-family:inherit;font-size:100%}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{padding:0;box-sizing:border-box}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:2cm .5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}img{vertical-align:middle}.img-responsive{display:block;height:auto;max-width:100%}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{margin-top:20px;margin-bottom:10px}h1 small,h2 small,h3 small,h1 .small,h2 .small,h3 .small{font-size:65%}h4,h5,h6{margin-top:10px;margin-bottom:10px}h4 small,h5 small,h6 small,h4 .small,h5 .small,h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4}@media(min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}.text-muted{color:#999}.text-primary{color:#428bca}.text-primary:hover{color:#3071a9}.text-warning{color:#8a6d3b}.text-warning:hover{color:#66512c}.text-danger{color:#a94442}.text-danger:hover{color:#843534}.text-success{color:#3c763d}.text-success:hover{color:#2b542c}.text-info{color:#31708f}.text-info:hover{color:#245269}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}.list-inline>li:first-child{padding-left:0}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:bold}dd{margin-left:0}@media(min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{font-size:17.5px;font-weight:300;line-height:1.25}blockquote p:last-child{margin-bottom:0}blockquote small,blockquote .small{display:block;line-height:1.428571429;color:#999}blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small,blockquote.pull-right .small{text-align:right}blockquote.pull-right small:before,blockquote.pull-right .small:before{content:''}blockquote.pull-right small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.428571429}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;white-space:nowrap;background-color:#f9f2f4;border-radius:4px}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}@media(min-width:768px){.container{width:750px}}@media(min-width:992px){.container{width:970px}}@media(min-width:1200px){.container{width:1170px}}.row{margin-right:-15px;margin-left:-15px}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666666666666%}.col-xs-10{width:83.33333333333334%}.col-xs-9{width:75%}.col-xs-8{width:66.66666666666666%}.col-xs-7{width:58.333333333333336%}.col-xs-6{width:50%}.col-xs-5{width:41.66666666666667%}.col-xs-4{width:33.33333333333333%}.col-xs-3{width:25%}.col-xs-2{width:16.666666666666664%}.col-xs-1{width:8.333333333333332%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666666666666%}.col-xs-pull-10{right:83.33333333333334%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666666666666%}.col-xs-pull-7{right:58.333333333333336%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666666666667%}.col-xs-pull-4{right:33.33333333333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.666666666666664%}.col-xs-pull-1{right:8.333333333333332%}.col-xs-pull-0{right:0}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666666666666%}.col-xs-push-10{left:83.33333333333334%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666666666666%}.col-xs-push-7{left:58.333333333333336%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666666666667%}.col-xs-push-4{left:33.33333333333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.666666666666664%}.col-xs-push-1{left:8.333333333333332%}.col-xs-push-0{left:0}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666666666666%}.col-xs-offset-10{margin-left:83.33333333333334%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666666666666%}.col-xs-offset-7{margin-left:58.333333333333336%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666666666667%}.col-xs-offset-4{margin-left:33.33333333333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.666666666666664%}.col-xs-offset-1{margin-left:8.333333333333332%}.col-xs-offset-0{margin-left:0}@media(min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666666666666%}.col-sm-10{width:83.33333333333334%}.col-sm-9{width:75%}.col-sm-8{width:66.66666666666666%}.col-sm-7{width:58.333333333333336%}.col-sm-6{width:50%}.col-sm-5{width:41.66666666666667%}.col-sm-4{width:33.33333333333333%}.col-sm-3{width:25%}.col-sm-2{width:16.666666666666664%}.col-sm-1{width:8.333333333333332%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-0{right:0}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666666666666%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-0{left:0}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666666666666%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-0{margin-left:0}}@media(min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666666666666%}.col-md-10{width:83.33333333333334%}.col-md-9{width:75%}.col-md-8{width:66.66666666666666%}.col-md-7{width:58.333333333333336%}.col-md-6{width:50%}.col-md-5{width:41.66666666666667%}.col-md-4{width:33.33333333333333%}.col-md-3{width:25%}.col-md-2{width:16.666666666666664%}.col-md-1{width:8.333333333333332%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666666666666%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-0{right:0}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666666666666%}.col-md-push-10{left:83.33333333333334%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666666666666%}.col-md-push-7{left:58.333333333333336%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666666666667%}.col-md-push-4{left:33.33333333333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.666666666666664%}.col-md-push-1{left:8.333333333333332%}.col-md-push-0{left:0}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666666666666%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-0{margin-left:0}}@media(min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666666666666%}.col-lg-10{width:83.33333333333334%}.col-lg-9{width:75%}.col-lg-8{width:66.66666666666666%}.col-lg-7{width:58.333333333333336%}.col-lg-6{width:50%}.col-lg-5{width:41.66666666666667%}.col-lg-4{width:33.33333333333333%}.col-lg-3{width:25%}.col-lg-2{width:16.666666666666664%}.col-lg-1{width:8.333333333333332%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-0{right:0}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666666666666%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-0{left:0}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666666666666%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-0{margin-left:0}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*="col-"]{position:static;display:table-column;float:none}table td[class*="col-"],table th[class*="col-"]{display:table-cell;float:none}.table>thead>tr>.active,.table>tbody>tr>.active,.table>tfoot>tr>.active,.table>thead>.active>td,.table>tbody>.active>td,.table>tfoot>.active>td,.table>thead>.active>th,.table>tbody>.active>th,.table>tfoot>.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>.active:hover,.table-hover>tbody>.active:hover>td,.table-hover>tbody>.active:hover>th{background-color:#e8e8e8}.table>thead>tr>.success,.table>tbody>tr>.success,.table>tfoot>tr>.success,.table>thead>.success>td,.table>tbody>.success>td,.table>tfoot>.success>td,.table>thead>.success>th,.table>tbody>.success>th,.table>tfoot>.success>th{background-color:#dff0d8}.table-hover>tbody>tr>.success:hover,.table-hover>tbody>.success:hover>td,.table-hover>tbody>.success:hover>th{background-color:#d0e9c6}.table>thead>tr>.danger,.table>tbody>tr>.danger,.table>tfoot>tr>.danger,.table>thead>.danger>td,.table>tbody>.danger>td,.table>tfoot>.danger>td,.table>thead>.danger>th,.table>tbody>.danger>th,.table>tfoot>.danger>th{background-color:#f2dede}.table-hover>tbody>tr>.danger:hover,.table-hover>tbody>.danger:hover>td,.table-hover>tbody>.danger:hover>th{background-color:#ebcccc}.table>thead>tr>.warning,.table>tbody>tr>.warning,.table>tfoot>tr>.warning,.table>thead>.warning>td,.table>tbody>.warning>td,.table>tfoot>.warning>td,.table>thead>.warning>th,.table>tbody>.warning>th,.table>tfoot>.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>.warning:hover,.table-hover>tbody>.warning:hover>td,.table-hover>tbody>.warning:hover>th{background-color:#faf2cc}@media(max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:scroll;overflow-y:hidden;border:1px solid #ddd;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}select[multiple],select[size]{height:auto}select optgroup{font-family:inherit;font-size:inherit;font-style:inherit}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}input[type="number"]::-webkit-outer-spin-button,input[type="number"]::-webkit-inner-spin-button{height:auto}output{display:block;padding-top:7px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6)}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}textarea.form-control{height:auto}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;padding-left:20px;margin-top:10px;margin-bottom:10px;vertical-align:middle}.radio label,.checkbox label{display:inline;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:normal;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm{height:auto}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:46px;line-height:46px}textarea.input-lg{height:auto}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.form-control-static{margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media(min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block}.form-inline select.form-control{width:auto}.form-inline .radio,.form-inline .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:none;margin-left:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-control-static{padding-top:7px}@media(min-width:768px){.form-horizontal .control-label{text-align:right}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:normal;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#fff}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-primary .badge{color:#428bca;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-link{font-weight:normal;color:#428bca;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons-halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';-webkit-font-smoothing:antialiased;font-style:normal;font-weight:normal;line-height:1;-moz-osx-font-smoothing:grayscale}.glyphicon:empty{width:1em}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media(min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar .btn-group{float:left}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group,.btn-toolbar>.btn-group+.btn-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-bottom-left-radius:4px;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child>.btn:last-child,.btn-group-vertical>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;border-collapse:separate;table-layout:fixed}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*="col-"]{float:none;padding-right:0;padding-left:0}.input-group .form-control{width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:normal;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;white-space:nowrap}.input-group-btn:first-child>.btn{margin-right:-1px}.input-group-btn:last-child>.btn{margin-left:-1px}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-4px}.input-group-btn>.btn:hover,.input-group-btn>.btn:active{z-index:2}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}@media(min-width:768px){.navbar{border-radius:4px}}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}@media(min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse.in{overflow-y:auto}@media(min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-right:0;padding-left:0}}.container>.navbar-header,.container>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media(min-width:768px){.container>.navbar-header,.container>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media(min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media(min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media(min-width:768px){.navbar>.container .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media(min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media(max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media(min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}.navbar-nav.navbar-right:last-child{margin-right:-15px}}@media(min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}@media(min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block}.navbar-form select.form-control{width:auto}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{float:none;margin-left:0}}@media(max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media(min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-form.navbar-right:last-child{margin-right:-15px}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-nav.pull-right>li>.dropdown-menu,.navbar-nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media(min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}.navbar-text.navbar-right:last-child{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#ccc}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}@media(max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}@media(max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.428571429;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{background-color:#eee}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:#808080}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#999;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;font-size:21px;font-weight:200;line-height:2.1428571435;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{line-height:1;color:inherit}.jumbotron p{line-height:1.4}.container .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img,.thumbnail a>img{display:block;height:auto;max-width:100%;margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}a.list-group-item.active .list-group-item-heading,a.list-group-item.active:hover .list-group-item-heading,a.list-group-item.active:focus .list-group-item-heading{color:inherit}a.list-group-item.active .list-group-item-text,a.list-group-item.active:hover .list-group-item-text,a.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0}.panel>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table>tbody:first-child th,.panel>.table>tbody:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:last-child>th,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:last-child>td,.panel>.table-responsive>.table-bordered>thead>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-group .panel{margin-bottom:0;overflow:hidden;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#faebcc}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#ebccd1}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ebccd1}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:auto;overflow-y:scroll}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{position:relative;z-index:1050;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{min-height:16.428571429px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{padding:19px 20px 20px;margin-top:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media screen and (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}}.tooltip{position:absolute;z-index:1030;display:block;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0;content:" "}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0;content:" "}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0;content:" "}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0;content:" "}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;height:auto;max-width:100%;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);opacity:.5;filter:alpha(opacity=50)}.carousel-control.left{background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.5) 0),color-stop(rgba(0,0,0,0.0001) 100%));background-image:linear-gradient(to right,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.0001) 0),color-stop(rgba(0,0,0,0.5) 100%));background-image:linear-gradient(to right,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;outline:0;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicons-chevron-left,.carousel-control .glyphicons-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,tr.visible-xs,th.visible-xs,td.visible-xs{display:none!important}@media(max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-xs.visible-sm{display:block!important}table.visible-xs.visible-sm{display:table}tr.visible-xs.visible-sm{display:table-row!important}th.visible-xs.visible-sm,td.visible-xs.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-xs.visible-md{display:block!important}table.visible-xs.visible-md{display:table}tr.visible-xs.visible-md{display:table-row!important}th.visible-xs.visible-md,td.visible-xs.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-xs.visible-lg{display:block!important}table.visible-xs.visible-lg{display:table}tr.visible-xs.visible-lg{display:table-row!important}th.visible-xs.visible-lg,td.visible-xs.visible-lg{display:table-cell!important}}.visible-sm,tr.visible-sm,th.visible-sm,td.visible-sm{display:none!important}@media(max-width:767px){.visible-sm.visible-xs{display:block!important}table.visible-sm.visible-xs{display:table}tr.visible-sm.visible-xs{display:table-row!important}th.visible-sm.visible-xs,td.visible-sm.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-sm.visible-md{display:block!important}table.visible-sm.visible-md{display:table}tr.visible-sm.visible-md{display:table-row!important}th.visible-sm.visible-md,td.visible-sm.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-sm.visible-lg{display:block!important}table.visible-sm.visible-lg{display:table}tr.visible-sm.visible-lg{display:table-row!important}th.visible-sm.visible-lg,td.visible-sm.visible-lg{display:table-cell!important}}.visible-md,tr.visible-md,th.visible-md,td.visible-md{display:none!important}@media(max-width:767px){.visible-md.visible-xs{display:block!important}table.visible-md.visible-xs{display:table}tr.visible-md.visible-xs{display:table-row!important}th.visible-md.visible-xs,td.visible-md.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-md.visible-sm{display:block!important}table.visible-md.visible-sm{display:table}tr.visible-md.visible-sm{display:table-row!important}th.visible-md.visible-sm,td.visible-md.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-md.visible-lg{display:block!important}table.visible-md.visible-lg{display:table}tr.visible-md.visible-lg{display:table-row!important}th.visible-md.visible-lg,td.visible-md.visible-lg{display:table-cell!important}}.visible-lg,tr.visible-lg,th.visible-lg,td.visible-lg{display:none!important}@media(max-width:767px){.visible-lg.visible-xs{display:block!important}table.visible-lg.visible-xs{display:table}tr.visible-lg.visible-xs{display:table-row!important}th.visible-lg.visible-xs,td.visible-lg.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-lg.visible-sm{display:block!important}table.visible-lg.visible-sm{display:table}tr.visible-lg.visible-sm{display:table-row!important}th.visible-lg.visible-sm,td.visible-lg.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-lg.visible-md{display:block!important}table.visible-lg.visible-md{display:table}tr.visible-lg.visible-md{display:table-row!important}th.visible-lg.visible-md,td.visible-lg.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}.hidden-xs{display:block!important}table.hidden-xs{display:table}tr.hidden-xs{display:table-row!important}th.hidden-xs,td.hidden-xs{display:table-cell!important}@media(max-width:767px){.hidden-xs,tr.hidden-xs,th.hidden-xs,td.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-xs.hidden-sm,tr.hidden-xs.hidden-sm,th.hidden-xs.hidden-sm,td.hidden-xs.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-xs.hidden-md,tr.hidden-xs.hidden-md,th.hidden-xs.hidden-md,td.hidden-xs.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-xs.hidden-lg,tr.hidden-xs.hidden-lg,th.hidden-xs.hidden-lg,td.hidden-xs.hidden-lg{display:none!important}}.hidden-sm{display:block!important}table.hidden-sm{display:table}tr.hidden-sm{display:table-row!important}th.hidden-sm,td.hidden-sm{display:table-cell!important}@media(max-width:767px){.hidden-sm.hidden-xs,tr.hidden-sm.hidden-xs,th.hidden-sm.hidden-xs,td.hidden-sm.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-sm,tr.hidden-sm,th.hidden-sm,td.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-sm.hidden-md,tr.hidden-sm.hidden-md,th.hidden-sm.hidden-md,td.hidden-sm.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-sm.hidden-lg,tr.hidden-sm.hidden-lg,th.hidden-sm.hidden-lg,td.hidden-sm.hidden-lg{display:none!important}}.hidden-md{display:block!important}table.hidden-md{display:table}tr.hidden-md{display:table-row!important}th.hidden-md,td.hidden-md{display:table-cell!important}@media(max-width:767px){.hidden-md.hidden-xs,tr.hidden-md.hidden-xs,th.hidden-md.hidden-xs,td.hidden-md.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-md.hidden-sm,tr.hidden-md.hidden-sm,th.hidden-md.hidden-sm,td.hidden-md.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-md,tr.hidden-md,th.hidden-md,td.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-md.hidden-lg,tr.hidden-md.hidden-lg,th.hidden-md.hidden-lg,td.hidden-md.hidden-lg{display:none!important}}.hidden-lg{display:block!important}table.hidden-lg{display:table}tr.hidden-lg{display:table-row!important}th.hidden-lg,td.hidden-lg{display:table-cell!important}@media(max-width:767px){.hidden-lg.hidden-xs,tr.hidden-lg.hidden-xs,th.hidden-lg.hidden-xs,td.hidden-lg.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-lg.hidden-sm,tr.hidden-lg.hidden-sm,th.hidden-lg.hidden-sm,td.hidden-lg.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-lg.hidden-md,tr.hidden-lg.hidden-md,th.hidden-lg.hidden-md,td.hidden-lg.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-lg,tr.hidden-lg,th.hidden-lg,td.hidden-lg{display:none!important}}.visible-print,tr.visible-print,th.visible-print,td.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}.hidden-print,tr.hidden-print,th.hidden-print,td.hidden-print{display:none!important}} \ No newline at end of file diff --git a/public/assets/css/font-awesome.min.css b/public/assets/css/font-awesome.min.css new file mode 100755 index 00000000..449d6ac5 --- /dev/null +++ b/public/assets/css/font-awesome.min.css @@ -0,0 +1,4 @@ +/*! + * Font Awesome 4.0.3 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.0.3');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.0.3') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff?v=4.0.3') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.0.3') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.0.3#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.3333333333333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.2857142857142858em;text-align:center}.fa-ul{padding-left:0;margin-left:2.142857142857143em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.142857142857143em;width:2.142857142857143em;top:.14285714285714285em;text-align:center}.fa-li.fa-lg{left:-1.8571428571428572em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:spin 2s infinite linear;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;animation:spin 2s infinite linear}@-moz-keyframes spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)}100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0%{-ms-transform:rotate(0deg)}100%{-ms-transform:rotate(359deg)}}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0,mirror=1);-webkit-transform:scale(-1,1);-moz-transform:scale(-1,1);-ms-transform:scale(-1,1);-o-transform:scale(-1,1);transform:scale(-1,1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2,mirror=1);-webkit-transform:scale(1,-1);-moz-transform:scale(1,-1);-ms-transform:scale(1,-1);-o-transform:scale(1,-1);transform:scale(1,-1)}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-asc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-desc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-reply-all:before{content:"\f122"}.fa-mail-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"} \ No newline at end of file diff --git a/public/assets/css/select2-bootstrap.css b/public/assets/css/select2-bootstrap.css new file mode 100644 index 00000000..90997107 --- /dev/null +++ b/public/assets/css/select2-bootstrap.css @@ -0,0 +1,87 @@ +.form-control .select2-choice { + border: 0; + border-radius: 2px; +} + +.form-control .select2-choice .select2-arrow { + border-radius: 0 2px 2px 0; +} + +.form-control.select2-container { + height: auto !important; + padding: 0px; +} + +.form-control.select2-container.select2-dropdown-open { + border-color: #5897FB; + border-radius: 3px 3px 0 0; +} + +.form-control .select2-container.select2-dropdown-open .select2-choices { + border-radius: 3px 3px 0 0; +} + +.form-control.select2-container .select2-choices { + border: 0 !important; + border-radius: 3px; +} + +.control-group.warning .select2-container .select2-choice, +.control-group.warning .select2-container .select2-choices, +.control-group.warning .select2-container-active .select2-choice, +.control-group.warning .select2-container-active .select2-choices, +.control-group.warning .select2-dropdown-open.select2-drop-above .select2-choice, +.control-group.warning .select2-dropdown-open.select2-drop-above .select2-choices, +.control-group.warning .select2-container-multi.select2-container-active .select2-choices { + border: 1px solid #C09853 !important; +} + +.control-group.warning .select2-container .select2-choice div { + border-left: 1px solid #C09853 !important; + background: #FCF8E3 !important; +} + +.control-group.error .select2-container .select2-choice, +.control-group.error .select2-container .select2-choices, +.control-group.error .select2-container-active .select2-choice, +.control-group.error .select2-container-active .select2-choices, +.control-group.error .select2-dropdown-open.select2-drop-above .select2-choice, +.control-group.error .select2-dropdown-open.select2-drop-above .select2-choices, +.control-group.error .select2-container-multi.select2-container-active .select2-choices { + border: 1px solid #B94A48 !important; +} + +.control-group.error .select2-container .select2-choice div { + border-left: 1px solid #B94A48 !important; + background: #F2DEDE !important; +} + +.control-group.info .select2-container .select2-choice, +.control-group.info .select2-container .select2-choices, +.control-group.info .select2-container-active .select2-choice, +.control-group.info .select2-container-active .select2-choices, +.control-group.info .select2-dropdown-open.select2-drop-above .select2-choice, +.control-group.info .select2-dropdown-open.select2-drop-above .select2-choices, +.control-group.info .select2-container-multi.select2-container-active .select2-choices { + border: 1px solid #3A87AD !important; +} + +.control-group.info .select2-container .select2-choice div { + border-left: 1px solid #3A87AD !important; + background: #D9EDF7 !important; +} + +.control-group.success .select2-container .select2-choice, +.control-group.success .select2-container .select2-choices, +.control-group.success .select2-container-active .select2-choice, +.control-group.success .select2-container-active .select2-choices, +.control-group.success .select2-dropdown-open.select2-drop-above .select2-choice, +.control-group.success .select2-dropdown-open.select2-drop-above .select2-choices, +.control-group.success .select2-container-multi.select2-container-active .select2-choices { + border: 1px solid #468847 !important; +} + +.control-group.success .select2-container .select2-choice div { + border-left: 1px solid #468847 !important; + background: #DFF0D8 !important; +} diff --git a/public/assets/css/select2-spinner.gif b/public/assets/css/select2-spinner.gif new file mode 100644 index 0000000000000000000000000000000000000000..5b33f7e54f4e55b6b8774d86d96895db9af044b4 GIT binary patch literal 1849 zcma*odr(tX9tZI2z31lM+(&YVk%mZ}5P~KlG2s=WSbGzm0!x7^P##Mnh7t-jP!X0Q zk_SQ}Po-L1tlDK;6l?(>v)e5ZBQx4|Y-Q?nr@Px3?9h(3ZWr3^tj=`TP57gKr87N$ zp2wWee1GRRCwo_xahnw)5cxNPJbCg2L6DV|6`#+yw6v6!mDS$f9-JvFD^n;GQ&UrZ zzh5jCkByB101O60U0q#p_1BM>Cv-vP?&s4@g_((4_1L=L$(a91)0=J91Gas#R{McE znYG^9*0A5YZ>#;~+Wkn(W5B0^yELIYLP!K}mB~<)AM@1&nqekynuaEGqPrzoH|KodRXJy)%+w_fu3nE5>@Bd_b zqC$EQ;{c`T&?EsNO|igL9gC7Ygxv?aQUEXMq?~>wg{EyW;VcJ37CUF#HjrT=KQO_* zS>M9yydXk18D(+QDJ1>r);Lav_uYKp$T?4vr{Q$lTo&pKv^?(>L-)G2*lwH!Ah7k? z7oH<8h-(KTKt5V6$8gF)C7Io&P5=SjTh)=zV=E2EUhQZP##L8S{d%UK>>+y82>+FV+#^BzW7u3F)Bb>=lYQ%%j`F>ASe zo*cw@V#u6T`A2He;70mR(V&iV&-7{qP~=SRf&jm9-T{*ZeZ}$rd0#6c&fLG^xJcf5 z+p<`wJYgW+_s*V{uI$nMB;%8`S_3>PfGOj3Rq}@Cx^+j?rk92fANSFDBYnOqQ>Vdj z)(|$AhP4t&Lb=Gvo2#3Gl%9<=Gv`Mz?Po@P4iLF!x}GUWJICDlFk-hS^Whyh7x~VH z@0vD1>HYD4&e+~yzS*-sFR{9`{QEEZO1zg7>R&7cHts-6j!xHVdA8eI+ZlVzd%`es zJT@$#GX(gvCJ1oJN%yLBK}{V=V;seo;!w|Yte!W1%5qLNFWqvZW>h&IiH+oPT=b@E zPhGzv5=(Un*X>v`>%8h_nj^NdYcE6NHS_ifkCV$*D)Tqrbu`s;<=t<4 zAHNqNV?6(g<1PY-w@#I-WYFViz?9TrkMr)u0g`O`u|>T;k|2sV*YF^punvT;$SuTy{j3Gv)yqD!R_CF>yR)MzmmYS5v+~R zXAdD%ng9?df;wd8GxR#%3O+gz};Vo;)sK%Bj-q>Oq%R7JU-KD?vYu>#2UjaDo z&8$>5xW~?KPD_#XFToU1hIb*VOMidUr6iYiO0N|i-7s`T8!cFT`rN!^1Pt78J93i6 z5HI1wIM$94m{3SLDvISDe6$ZG1;eq_D9RTaaC>=cO{@Bs>$IlPCPJJ$h$)-3vzNUQ6OsN#_zWxey!_9%hxwH2_dEJi=yY|1c7nDm2_Lm!Cof8-R_+9UkS zcBE(o47yE)oMR(Q=dp1a2wTX5KvvGyLqlWTa7V&!A*|w|)ax~1_~aJ0=_Lilg*0iQk7#ZD EAHN$8j{pDw literal 0 HcmV?d00001 diff --git a/public/assets/css/select2.css b/public/assets/css/select2.css new file mode 100644 index 00000000..4b2a2a82 --- /dev/null +++ b/public/assets/css/select2.css @@ -0,0 +1,646 @@ +/* +Version: 3.4.6 Timestamp: Sat Mar 22 22:30:15 EDT 2014 +*/ +.select2-container { + margin: 0; + position: relative; + display: inline-block; + /* inline-block for ie7 */ + zoom: 1; + *display: inline; + vertical-align: middle; +} + +.select2-container, +.select2-drop, +.select2-search, +.select2-search input { + /* + Force border-box so that % widths fit the parent + container without overlap because of margin/padding. + More Info : http://www.quirksmode.org/css/box.html + */ + -webkit-box-sizing: border-box; /* webkit */ + -moz-box-sizing: border-box; /* firefox */ + box-sizing: border-box; /* css3 */ +} + +.select2-container .select2-choice { + display: block; + height: 26px; + padding: 0 0 0 8px; + overflow: hidden; + position: relative; + + border: 1px solid #aaa; + white-space: nowrap; + line-height: 26px; + color: #444; + text-decoration: none; + + border-radius: 4px; + + background-clip: padding-box; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + background-color: #fff; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.5, #fff)); + background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 50%); + background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 50%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#ffffff', endColorstr = '#eeeeee', GradientType = 0); + background-image: linear-gradient(to top, #eee 0%, #fff 50%); +} + +.select2-container.select2-drop-above .select2-choice { + border-bottom-color: #aaa; + + border-radius: 0 0 4px 4px; + + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.9, #fff)); + background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 90%); + background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 90%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0); + background-image: linear-gradient(to bottom, #eee 0%, #fff 90%); +} + +.select2-container.select2-allowclear .select2-choice .select2-chosen { + margin-right: 42px; +} + +.select2-container .select2-choice > .select2-chosen { + margin-right: 26px; + display: block; + overflow: hidden; + + white-space: nowrap; + + text-overflow: ellipsis; + float: none; + width: auto; +} + +.select2-container .select2-choice abbr { + display: none; + width: 12px; + height: 12px; + position: absolute; + right: 24px; + top: 8px; + + font-size: 1px; + text-decoration: none; + + border: 0; + background: url('select2.png') right top no-repeat; + cursor: pointer; + outline: 0; +} + +.select2-container.select2-allowclear .select2-choice abbr { + display: inline-block; +} + +.select2-container .select2-choice abbr:hover { + background-position: right -11px; + cursor: pointer; +} + +.select2-drop-mask { + border: 0; + margin: 0; + padding: 0; + position: fixed; + left: 0; + top: 0; + min-height: 100%; + min-width: 100%; + height: auto; + width: auto; + opacity: 0; + z-index: 9998; + /* styles required for IE to work */ + background-color: #fff; + filter: alpha(opacity=0); +} + +.select2-drop { + width: 100%; + margin-top: -1px; + position: absolute; + z-index: 9999; + top: 100%; + + background: #fff; + color: #000; + border: 1px solid #aaa; + border-top: 0; + + border-radius: 0 0 4px 4px; + + -webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); + box-shadow: 0 4px 5px rgba(0, 0, 0, .15); +} + +.select2-drop.select2-drop-above { + margin-top: 1px; + border-top: 1px solid #aaa; + border-bottom: 0; + + border-radius: 4px 4px 0 0; + + -webkit-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); + box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); +} + +.select2-drop-active { + border: 1px solid #5897fb; + border-top: none; +} + +.select2-drop.select2-drop-above.select2-drop-active { + border-top: 1px solid #5897fb; +} + +.select2-drop-auto-width { + border-top: 1px solid #aaa; + width: auto; +} + +.select2-drop-auto-width .select2-search { + padding-top: 4px; +} + +.select2-container .select2-choice .select2-arrow { + display: inline-block; + width: 18px; + height: 100%; + position: absolute; + right: 0; + top: 0; + + border-left: 1px solid #aaa; + border-radius: 0 4px 4px 0; + + background-clip: padding-box; + + background: #ccc; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccc), color-stop(0.6, #eee)); + background-image: -webkit-linear-gradient(center bottom, #ccc 0%, #eee 60%); + background-image: -moz-linear-gradient(center bottom, #ccc 0%, #eee 60%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#eeeeee', endColorstr = '#cccccc', GradientType = 0); + background-image: linear-gradient(to top, #ccc 0%, #eee 60%); +} + +.select2-container .select2-choice .select2-arrow b { + display: block; + width: 100%; + height: 100%; + background: url('select2.png') no-repeat 0 1px; +} + +.select2-search { + display: inline-block; + width: 100%; + min-height: 26px; + margin: 0; + padding-left: 4px; + padding-right: 4px; + + position: relative; + z-index: 10000; + + white-space: nowrap; +} + +.select2-search input { + width: 100%; + height: auto !important; + min-height: 26px; + padding: 4px 20px 4px 5px; + margin: 0; + + outline: 0; + font-family: sans-serif; + font-size: 1em; + + border: 1px solid #aaa; + border-radius: 0; + + -webkit-box-shadow: none; + box-shadow: none; + + background: #fff url('select2.png') no-repeat 100% -22px; + background: url('select2.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee)); + background: url('select2.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('select2.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('select2.png') no-repeat 100% -22px, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0; +} + +.select2-drop.select2-drop-above .select2-search input { + margin-top: 4px; +} + +.select2-search input.select2-active { + background: #fff url('select2-spinner.gif') no-repeat 100%; + background: url('select2-spinner.gif') no-repeat 100%, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee)); + background: url('select2-spinner.gif') no-repeat 100%, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('select2-spinner.gif') no-repeat 100%, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('select2-spinner.gif') no-repeat 100%, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0; +} + +.select2-container-active .select2-choice, +.select2-container-active .select2-choices { + border: 1px solid #5897fb; + outline: none; + + -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3); + box-shadow: 0 0 5px rgba(0, 0, 0, .3); +} + +.select2-dropdown-open .select2-choice { + border-bottom-color: transparent; + -webkit-box-shadow: 0 1px 0 #fff inset; + box-shadow: 0 1px 0 #fff inset; + + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + + background-color: #eee; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(0.5, #eee)); + background-image: -webkit-linear-gradient(center bottom, #fff 0%, #eee 50%); + background-image: -moz-linear-gradient(center bottom, #fff 0%, #eee 50%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0); + background-image: linear-gradient(to top, #fff 0%, #eee 50%); +} + +.select2-dropdown-open.select2-drop-above .select2-choice, +.select2-dropdown-open.select2-drop-above .select2-choices { + border: 1px solid #5897fb; + border-top-color: transparent; + + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(0.5, #eee)); + background-image: -webkit-linear-gradient(center top, #fff 0%, #eee 50%); + background-image: -moz-linear-gradient(center top, #fff 0%, #eee 50%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0); + background-image: linear-gradient(to bottom, #fff 0%, #eee 50%); +} + +.select2-dropdown-open .select2-choice .select2-arrow { + background: transparent; + border-left: none; + filter: none; +} +.select2-dropdown-open .select2-choice .select2-arrow b { + background-position: -18px 1px; +} + +.select2-hidden-accessible { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} + +/* results */ +.select2-results { + max-height: 200px; + padding: 0 0 0 4px; + margin: 4px 4px 4px 0; + position: relative; + overflow-x: hidden; + overflow-y: auto; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +.select2-results ul.select2-result-sub { + margin: 0; + padding-left: 0; +} + +.select2-results ul.select2-result-sub > li .select2-result-label { padding-left: 20px } +.select2-results ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 40px } +.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 60px } +.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 80px } +.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 100px } +.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 110px } +.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 120px } + +.select2-results li { + list-style: none; + display: list-item; + background-image: none; +} + +.select2-results li.select2-result-with-children > .select2-result-label { + font-weight: bold; +} + +.select2-results .select2-result-label { + padding: 3px 7px 4px; + margin: 0; + cursor: pointer; + + min-height: 1em; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.select2-results .select2-highlighted { + background: #3875d7; + color: #fff; +} + +.select2-results li em { + background: #feffde; + font-style: normal; +} + +.select2-results .select2-highlighted em { + background: transparent; +} + +.select2-results .select2-highlighted ul { + background: #fff; + color: #000; +} + + +.select2-results .select2-no-results, +.select2-results .select2-searching, +.select2-results .select2-selection-limit { + background: #f4f4f4; + display: list-item; + padding-left: 5px; +} + +/* +disabled look for disabled choices in the results dropdown +*/ +.select2-results .select2-disabled.select2-highlighted { + color: #666; + background: #f4f4f4; + display: list-item; + cursor: default; +} +.select2-results .select2-disabled { + background: #f4f4f4; + display: list-item; + cursor: default; +} + +.select2-results .select2-selected { + display: none; +} + +.select2-more-results.select2-active { + background: #f4f4f4 url('select2-spinner.gif') no-repeat 100%; +} + +.select2-more-results { + background: #f4f4f4; + display: list-item; +} + +/* disabled styles */ + +.select2-container.select2-container-disabled .select2-choice { + background-color: #f4f4f4; + background-image: none; + border: 1px solid #ddd; + cursor: default; +} + +.select2-container.select2-container-disabled .select2-choice .select2-arrow { + background-color: #f4f4f4; + background-image: none; + border-left: 0; +} + +.select2-container.select2-container-disabled .select2-choice abbr { + display: none; +} + + +/* multiselect */ + +.select2-container-multi .select2-choices { + height: auto !important; + height: 1%; + margin: 0; + padding: 0; + position: relative; + + border: 1px solid #aaa; + cursor: text; + overflow: hidden; + + background-color: #fff; + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eee), color-stop(15%, #fff)); + background-image: -webkit-linear-gradient(top, #eee 1%, #fff 15%); + background-image: -moz-linear-gradient(top, #eee 1%, #fff 15%); + background-image: linear-gradient(to bottom, #eee 1%, #fff 15%); +} + +.select2-locked { + padding: 3px 5px 3px 5px !important; +} + +.select2-container-multi .select2-choices { + min-height: 26px; +} + +.select2-container-multi.select2-container-active .select2-choices { + border: 1px solid #5897fb; + outline: none; + + -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3); + box-shadow: 0 0 5px rgba(0, 0, 0, .3); +} +.select2-container-multi .select2-choices li { + float: left; + list-style: none; +} +html[dir="rtl"] .select2-container-multi .select2-choices li +{ + float: right; +} +.select2-container-multi .select2-choices .select2-search-field { + margin: 0; + padding: 0; + white-space: nowrap; +} + +.select2-container-multi .select2-choices .select2-search-field input { + padding: 5px; + margin: 1px 0; + + font-family: sans-serif; + font-size: 100%; + color: #666; + outline: 0; + border: 0; + -webkit-box-shadow: none; + box-shadow: none; + background: transparent !important; +} + +.select2-container-multi .select2-choices .select2-search-field input.select2-active { + background: #fff url('select2-spinner.gif') no-repeat 100% !important; +} + +.select2-default { + color: #999 !important; +} + +.select2-container-multi .select2-choices .select2-search-choice { + padding: 3px 5px 3px 18px; + margin: 3px 0 3px 5px; + position: relative; + + line-height: 13px; + color: #333; + cursor: default; + border: 1px solid #aaaaaa; + + border-radius: 3px; + + -webkit-box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05); + box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05); + + background-clip: padding-box; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + background-color: #e4e4e4; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#f4f4f4', GradientType=0); + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eee)); + background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); + background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); + background-image: linear-gradient(to top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); +} +html[dir="rtl"] .select2-container-multi .select2-choices .select2-search-choice +{ + margin-left: 0; + margin-right: 5px; +} +.select2-container-multi .select2-choices .select2-search-choice .select2-chosen { + cursor: default; +} +.select2-container-multi .select2-choices .select2-search-choice-focus { + background: #d4d4d4; +} + +.select2-search-choice-close { + display: block; + width: 12px; + height: 13px; + position: absolute; + right: 3px; + top: 4px; + + font-size: 1px; + outline: none; + background: url('select2.png') right top no-repeat; +} +html[dir="rtl"] .select2-search-choice-close { + right: auto; + left: 3px; +} + +.select2-container-multi .select2-search-choice-close { + left: 3px; +} + +.select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover { + background-position: right -11px; +} +.select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close { + background-position: right -11px; +} + +/* disabled styles */ +.select2-container-multi.select2-container-disabled .select2-choices { + background-color: #f4f4f4; + background-image: none; + border: 1px solid #ddd; + cursor: default; +} + +.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice { + padding: 3px 5px 3px 5px; + border: 1px solid #ddd; + background-image: none; + background-color: #f4f4f4; +} + +.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close { display: none; + background: none; +} +/* end multiselect */ + + +.select2-result-selectable .select2-match, +.select2-result-unselectable .select2-match { + text-decoration: underline; +} + +.select2-offscreen, .select2-offscreen:focus { + clip: rect(0 0 0 0) !important; + width: 1px !important; + height: 1px !important; + border: 0 !important; + margin: 0 !important; + padding: 0 !important; + overflow: hidden !important; + position: absolute !important; + outline: 0 !important; + left: 0px !important; + top: 0px !important; +} + +.select2-display-none { + display: none; +} + +.select2-measure-scrollbar { + position: absolute; + top: -10000px; + left: -10000px; + width: 100px; + height: 100px; + overflow: scroll; +} + +/* Retina-ize icons */ + +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 2dppx) { + .select2-search input, + .select2-search-choice-close, + .select2-container .select2-choice abbr, + .select2-container .select2-choice .select2-arrow b { + background-image: url('select2x2.png') !important; + background-repeat: no-repeat !important; + background-size: 60px 40px !important; + } + + .select2-search input { + background-position: 100% -21px !important; + } +} diff --git a/public/assets/css/select2.png b/public/assets/css/select2.png new file mode 100644 index 0000000000000000000000000000000000000000..1d804ffb99699b9e030f1010314de0970b5a000d GIT binary patch literal 613 zcmV-r0-F7aP)#WY!I$JQV$)A5aAS1BM||2XVJl=+L1^1S1H% zM-&lx?NZpUrHhn>fk<>POqf2sh40}xxGZfc+t+#Eb(qHy9_3*1(U%t9t)QDnI#YAL(|ACV(>)>6WD-t!8tutHkdb^#3`HzoJG3A2@T`% zA|K@o*b!`R#(7)PWrMFn2))Ca3MR4(zaT`Zr61*kZK5NPnZwQszxh$fyv3?&4c>$q z2m=+yc0dRXRAsPDxF6sD;@rK4JGdR_``1S~o6Xi@2&aR6hcSrEp9HVRzEqVDqBn<1%hR=D4e1f^ra^A|34Cjc=Gny{F(o#MrvPYgZuTJOz(n)-F<| zj()qR;C={)N<0RRvDZ^@6ND+W*}gh-Lip(MDt!(zMSO)!j2j+*hxgzC-e3$@(O2p* zu;+gddm(cZwXTCLx*Ky4THOa*^b^F`woveIeCK^0aR|TJ00000NkvXXu0mjfA#WC6 literal 0 HcmV?d00001 diff --git a/public/assets/fonts/FontAwesome.otf b/public/assets/fonts/FontAwesome.otf new file mode 100755 index 0000000000000000000000000000000000000000..8b0f54e47e1d356dcf1496942a50e228e0f1ee14 GIT binary patch literal 62856 zcmcfp2Y3_5)&LBzEbU6(wGF`%u_do$I-wUs=poc3^xzP>t859|l91%ydy%{4ZewH9 zLNU#OK%5)jlp7M#adH#VlN(Y~MSVYG)7F`Dsts8mQIv>+ztD)dFw+9OVG%`1 zdML`ns?&x=Qnp|IfM+dm&(}ePcdqmf37+Ghm#p%f+FVKQ2*chjkzF#ZB~9w-bef!xGBr6D7h{6UGOP@t%*!8rhr zqTX&D_txFJckW8F88SgJDOYWQiq1}9HpST zU`<34PZ)C!_3}_&M2)6kC53tq%16Wv<;B!kk^fL$a$g&o8ZTNrRL|U3FQqy}Aw%^t z%FjbIl=r0M9>Z`rYKq77t>{++@-k0@oM~*1+}p2(7`Q4V*n=HYq=vsI?g5v}-nP z3|{}}ibb1(*R0;YdDD}@+q7nj-e?F6nlWp}oWMD=X3yOms||yGW^I(#9B4HL0`>*2 zG{Pq6qjlCmi#Eba+D94TAv}p9V_D5%k=nR0b4*~E)oRv<#|upiMk~z0GGmR=Yz-V5 ze^pq5HgIj2Au?HKwVD>qoJsnJx#u=RZ=|+Tk5lVmJ2z1#N=q3aw}vu8YK7c-N>4=y zwHEjdq-Iky;2wVdD3u7c7HAy@>636rQ}I+R6-Jq%%_eFi6$}s_rB+ajpcD*stEugP zo136*FtrWZo1wQ}7%h+r0@$R$MYWppE&yKBVk^ODoieQIXI-PMCWPv3^jr9p7*cDDu9q6%xx{?3;;b@n3omixrmwx*YNmZf9p3xm@i;8 zp?TpJjUB@J0D^@;Vq@WEgcj}}s2gf=U*-SLs=qz||El20$!O-RlsfnS_J9)6lK^rf z@F|+|fem;DctSVzuQ6lCs>g=*`}C{(m-TP#-`gM6ukSbXXY`l%AL#GuKiB_u|L6U` z^xwJVb4z_|(yht2X53nKYvZlGw+y#3Zk69U@CS95u-8E9*x%q${UiIw^e^w<+#lK> z-M_Ej)SuN~+27uOroXrU-Tp88`)^UVM&1epcn{s0b!+*p&9_2tnQmp>swD94ennAt zcir7`_tDR9d~W}I%Sf-0+(^%nvXRn}u#+RjBRxinMp7g0j<_@8_K4p{{5Im&i2f13 zj`+pr(-A+9_-Vw=5kHRjVZ`?%z8i6aJ1^|@`u}w?=l`!y{JYkcahKF7zYy(4XAHaLAh7>kswf;WDJ8 zodnW*&mk}LA4ATyzs;HS z&jMIk)X1SUY8WQ8mk8qz!5gX{ac?|#KNXah-`{R{t;jx;+arrw4mTM?C=b`)g9B|K zKbe$=Z!xqbc>xxr!#G3cIJ_43-sk>0XiMsaXE3e+56S@N-W&nebhy1GS=0t{!`!CB zeXl$`20SDCO)=z#yl@A)%foXM<_FJ&aY(!S?qN9ajLc&>wDpF%>BD`=97%ujZX|^{ zkUJb;(Bvllh3Ak$Tkm1o9O@S+z@h#=rtsbrEayd0}DguL&kx00m+ja=Bpt$)C)Jj(+GE#@N5{qN_YooPx`~Xe7HP3 z{%{$_+eqqQIN>I3Ngv^P)=&zdhx-v8M)G7X!|w&{r;s|*7v>g7Gy(!cXqP3lRov@8 zR1fWh=MwT9Zqok0{>Y@@?`{gwSN{7?L`gvE7m2*?lX6LUm1893w2Pdz9?n{^!(W2e zdWpaFl9b@u0BLprBcj#q)KgjW@7iqlGG5Yvz*k2E1b+8G7f(?i1&vA9XxDLyUk5nmBs6~80?xA;He-^DJ8RN^C1NybWMO6ExxOV&s>OP-SKlxQUu zNxCEtRJdwMgQQb(MDmQ}tmIiqujCEMHOY0!HkBMipnS7>{u``WKCv$?i#JtM9$^4u7g87d5nYqQ>kup*r>4Q>U zI$1hRI!8KRx>mYFs*@&5bEW0dI%&J~sPvTdy!1usRp|%PFQwl}f0q6xb;-PBD%k|t zY}tI-V%aj;YS{+aQ?dwIjLaxYk`>BoWsR~9*)iEk*+tn)va7OpWS_{smHjSrdP+V0 zJk_4#J?D9@_1xwe?HTK7@=Wl|@+|Uf_B`o%#`BWri=J_T=4`v|*&UBhl-L)Zv5p0%+J>@(~s_AL7X`wDx7eUJT&{SSMK z9pETV%t<)~r{X4Z^SBk<7A}m7;^H_fm&|2x`CJ88%QbUt++pq*cal5LUErSMUf^El zUgJLCKIVSme)FQdBwi!E`Us0Q z%p9T98WOazMw1pS4`!>y8fGSUh&Ik-O^&x{%~AT;IIAusHq0EYwdzPtZ?PI<%-T3( zf;Poyj0@2lgv1zcHAY2Q^wEZ}*a%}ZXpR=04ir-WpbZI&wOaLYTC*`MGSZl6h=r8Y z4d>%cq(*NDHzt{4!;(WH^yY|Ityyc*hFL*fHES(8GA!v5YmA7AiVce8e_;!6kC&7Z?Hyy8O0n%G}drq zY^2^A7ORi2YLl!XIxW$Sg>0fe(yD_8(T0#%Z4_w&Inczd&{N0@YP37MFWzF+MkX06M(8q>71~9GMQF*2ge2%AwMG*R7f)W-5CO{_W(pxQ1Gtd{5P-01VNw=dm{|+^ z6%j+0-eT37Lc+r$ViLp5kx^l=IKzeEl&qvF4E7NA%LH2ey@o@10m4vTyAQN~fSq7A zx?gWNFHF`H8*d3AI~%7r4CUPWFH{<1gk*m_30u(tfF`iWB#nqQTC}hv2E8F#m?SuDFTQn3UEkkc8@TWC!-F{GC^ww z>q*$~q;*EKK82V{VgW}(B4CfL)4q56 z4)D)xH0hF~^)O1fFcUYy3iJruY7hufKutIFVd8R^gr`Ecp*I_TDL24)U$r5ORbRg-pCjNXR?8@hRjlg!)^B z(D!dOu%iM74)q`)qGOHW+C($Zqs|&;iLn3^gGC89>$Oo4U_&EF=f-R>g=zQ41JxU% z^ai~(IaX`22o=$0BPn|0z*CK8 zK%DqkW2^;?Z85-a0Z6ni9$1JOKmq#-j|FR7G;j-Zd_)ZF6-)}K?p{V%Lg*B4TBUeba0p4h(`{lkhnUa;!S@mlEwb3uRAAna%X|R34lqnNUbFX_%$pF{0bXxjWdRmGt^CFZcG*MWq&*% zpD-JDPJjsSWiSA$4WFQ~!(L z(g@%$q;&`!M=`(;0H;FcJiPEeUTy)bGXu%#O;$^MxH}UvXTe-kd`b#g8@(3xP*30x znc%M+5eqCjy*4&-n6xnX2oC%!5s^Uj?t@SuO@S=#uW(bx z{WX6b2|^FDjXG;w?7RqzWiB8Wa4|QJBTGftngtFZz*C@qy(Q$Y1K?iO@DUL*ch+1% z9wK1j&>$1McLEb&Zk8+5#cF{jf&aTxfx3yPAYib-S%s<1oju2WfRYkWB~Tuak9)I+ z(-1(skh!xT*2bHo!{JN-dNJ<8yjM5m zG60rH7zk-~uZGNixK`kLe=CruA#>*j!96b-j;Z)?t?(j4`6Spia^GJE{4Ojx680Zt zNWe8%t069;H$XAk92OS^LR}2VREDV856=$Q!%mO|6<}C_6UCa{zd}W<5upDiblg`Y z4Cvl7f*bc0-6U;-JxByu&zNWdaxxqBk$}(fNs-__0UlzBNj3priZ@%}*dQl4?7A@u zxFO-}z(C>X2fTOs4u7+;J0*%HiJsMQxqoBiu59bC{I)* zIwpEv)GK;ZbY1kl=qJ%1q5%)ugY$R_l;6D`VIDej?~k_t(Uq#ab(*CcOB-jjSFxlRYtLG(g8nl{qO zbOHT5{ZCLqIVOM^&rD@zGV_^TOav3dn3%)Nr_5K(_smbsZ;XR+Nxh{3(y`L%(je&q z=^E)esaBdKO_%0LE2WLn1JX|EJJNqkKa+kfy&=6R{Z;m$EI>A1Hd!`RHd8iFwn+Af zOe@pN;$&u7o$Qe8lVqKiD_fkJ-=Jui1W386V`Pb1S)E zZZ{Xs={O@7&!utMTpf3Udy%`wead~q-Q@bYKfGjKDz6z{L0&7o9`}0EYlm03m(I)J zmEe`?mG4#O)#laVb=0fN>w?#dUN3vS=Jl4>2VS3feeLyw*Uw(Rc{#l9deh#V_egJz z_ayH*-iy4Kd2jIE?ESR2*4ylzxhxHlZ~0u+4bSNe2Avwqk&^$DHRv=KS#CD3;S~8SQm|;x zN%uXOg<%H!6sOWpT07MECb~&~iaal%Kr~kA@W=0ly z{t+$Uxdi~XHN7!e%}J9R(_7UXGlAu{@LgPTdU`T9mC4D=%h61g=2Yj|)i)V?b+ui? zE#uW(1@DS-MfI`{o?I@T&abi;)~M_?7x@=n*uipt?Z;r>c-GlBp66Pcnp(J_b~W~k zJU4;W8IE;z9Xr-_5FpZ3`8gH2s@$By{Co|!66RIRN3*C1^>ST?V>+@U!LTF2up`?- zL$|?lw4^nqr~{nKnUu7&6b%lRrZlCsr~{Z@h76@~^htykcl!R`V4$yrCB3Hbq$wn746_@NOa-3Klzp2l^gn2VQjbAuo0?#JQLL z$Mz}bSE*b<%<3&$R%={A(pBfD{9}jO88R43TRRf@j!umu(~;H5a&uR%M853YmDj$} zIQyjET)Xy-no~>!4446Ue9XYDW$(ym^9NXsBiI!j&bBmH*VjYd5uCtsQXS7>`8HO> zDbN}`0?ouLy46Rz8=vn%p8Uqm@ezB}D0m6pght^=)w6thX?kgz2G3qG5zoOZl-P#$ z;62Eu9_V9|U>i5{jy^LBsJUYYou6NrldH_F$f?R#6Z}L^@PMpQjwrgSs={8Q zoOChE&E(fDVqJZ+_^S(9K%?|z4Qv@&$Gd6owP0l%>_y%&IxVx)7#jOLcGPC4#d!g42=Yrv!#JYwQRKph}ax;`_tIz`20);H(1 zsJH++i<8d1wvyoE7px2R-tQK>V~5{WU|KHT4=~~?>;J-zTfD!37u?D8Q>s%Z8#$yy z%h5wD_x>xdywB+ughWP$WMyPzRwT*3=TpiXGn-0FZKbMbDvnhisqR1g!-dcPCCh&K zU-?&5z+T@$$>=nPF5$IkC4LdF#0#)`=@RwFOYj1u#w%4&w-#zI;XGu*dusADPKoOm z8YZ0Itm0}4+W;2`1!=edNfwuq23(9Y^AiBwidZ$*g5O$1LZ$6+E(!Uc|#A>nDKry|{>zcC#+K%kF13+aeB` z9VD9p6UpVd$^V7B9CH{zE9`mIIchS3J(9JvNG|5m;2dy7E#^4~49g)Y8pA2@Lg!dK zg2BOf!)Nnef3=~Zrna)izq+0-OJ%Z4GBT8|Rd_LG9C|4SxZ~=3jfW$p9$pYw$y_dg z$>JhlV>uJMiW^X%#R@E9a470Q>roqx9zaWQErSDbk~yp(uQ0DT&%cNvuP5iE^LQ+u z26PNWna=x2;dpDwYtF2PX<;eXb5R_ zZZpZ*jjdH0&h{xRQ82^3_v)+fai0dznTkb#fpNA>TZj!$wMBp(y(a5G+OcF=O-IX7 zI1yn7^P5|gEmh6+^=fi-zRxzcYPfTi=c-TFqDL>HS)ZW?kxW)_xu>W{<;ZnRKUuRK|0& z{yIfL1XJ`OLv>qeQ+d6Ac^h59pu}O!d{)1 zv*gVuu9H;FWrMuddxQ0v#UA3Pz#$I+SM%g3Mhc$GgAw6?7&+-zJQ9zbG>QEFIth(L zBY*uBja2)zlewX3ESktVZS|5(mkM&oHz$Xv$b>E&ZkH^c3ZkKeyP{@`J>81Zl|K725KKL~og7cTUw&+r2C zUk9>oB)d(Z#5JNP*mUmDq4TywX6_8%+DKj@yYsN}P;F;x zs~Sy06X}*#uDQ7i4t1y4@e^&gBNN(#@|4_eym;lN^{dj7Q_?EUGMmj-qU3N8NR(vr zL5@U0AW!DyaDfW~n7L>qoU7ycb%~=uC}_($bO;~RAg|+gl_}Tm%SPM9pFM`C+p(U`f$Ogj39`p#D49F9Oe2B)Y(1=eW zw)bneg>cL|gV(T-@p*5{tE=Jcu_#{Qxp*GXIvt3kkYHpQ3rMZzl>31_u>s6-4t1k$ z+%4rq9}T342VUdi$!t^dQ!_JRmu7%?geCz#$k7y78#|!3og3_v;<;Rny}YW5!%{qk zYr=}g#4>emYj$g9vy8LVs?h8`L_|TiBLNz~6T}mIn`7Q#x%%eXmYM^ywlbt>Y*KQW ztPgGNM5|#@Lho##(bo(L9oRr~qe#cANDc%f=kjIw`MHHTDlBJG(mA{ekB4g&=UR+@ z#y>k2b08anAWukZCeRZa(ch0ofCOX(Es0wN+K`%qt+#QuZ7_-y0m}#2?n`dsD*wD% zU9TxGD=jNm!ZzETgs?z(%&2dH6S29assTs?*$2o*DW}7G$(=zkCn=n0K=g91j%PTP zO^O&KdH%vD8V)3XPz7L>;2B8w07~qv;%G|;IoyGV`0yOvTG|Z!pBsQ#a448*<@V{7 zdf2gEhBIedl9SbV5}wF0Z(rH8R)gfF3J%|GPxzE<#INuQA;=Fuj>54gr^1)E;a_nA zo)4mW8(@oc8NVA2@UCNk;D%})%w{#z2H@ok=K_g?v+@cKVge`%egi3pAfR$7s)V8% zDeAC@I!=iS?|Kv_iSmi9WFEB;;){P5Rf%dKM4(>OC~6j+5}g+P=`qz~g~xw9Zi~l? z6U67mcO<+dT5?YEC%uhsrC(z|gAE zO*vJ0Soy8esY(oZgqQLER6n4etX{4*s1K;GsNYi~jhAMuW{;*_b1QI4;QGKH$2>CT zA7i<(=f?Sr+dQskyn1}e_?r{PPpF*GHsRt#zlr~zR50n=$@LGNnX+igA5%|F+cqs@ z+S}6~n7(}aZ!^p@%4hsObLz||W*(ijYF6oN$QX$5KDr7zAHmywn^DlpJ_O|_m=Lh-A{Et-MyoGSNERokiok) zBnhB3NFqWKByj{Ii5OXtL=iv-I)VcRzH|jku>?yL&Y*4VU{JsS#rOmaeBcup%p(vg z?BW3W4M&OsA3!q@+*i8Vuj{V(uR|WXD@)op>iqEmJe@|bq0uaUO$x21Z|quaWJ_xUXAmZ_~hhx4bGFsw0wse^@d)0B zL-DjAP%gua%Yc&7*ptG~HMb>n%yYV^Ir+quNu8Y~X zOsAO}fxX6IZ{=QTe4}1~-O+ORpvERWcIMrGol^hUixhq6Nu^Kwy$j!Uz@hXT4-9Ss z-^eat$rCh}7lHN*%g%HL&}$Su8|+c)fPpL~YD3OWLx-U)QRDO)^r8pth-2Z11unc6 zgng%-ae6tu=(e_wW5-~S1W_f(E39}MY+<0HH}t}`?3|LK9Q9xyw$l+A#;7pmon0@m z&K*)1ESq+ndV%!`g!5xSUcduLyEub)22bZfY4K@?Qx%R1r~Nu#$Db%*0|u7If<;f- zZs~|Wl!(S*4>TT2kOs?S>p%Q{+3%`Sh&B5C`;XrEP=ho`23o%ajYA%X+By!lcghCs z(t*>G`3tf5iS25v9E+7>u>TlY=(eddSF1{x5@z+(?=Ec9VE;d`68_zm&3^yMUl5~Q z0Git}{%n4T8P1e5L>?Gep2ptkLk#cJzMcm|(|{by6<_nIywA5V(E)G8Gcom+3bm`G z563%p(Fbx;4q8>~c*j#Xi_WWWENE06tM5GgA^R;KAldIYrnu%>=<-IpTt0YLpJO5Z z7ka_5=ykNkF$!&QjdCo4<9+{Y{}-4YM?Pfn-Sr?2iLE?(P=OM*pd0w2DX66fl@N?-1iD^%I(}!F>Y{#DE3uA#DGd2hEe5<#MzbG*8eJ9rAVS*a7>X z{S`8p!61R*K0CV=3?EN|rl+Y>-AblM$u#nWsCFL|0B zfQG|)pZ4~I6JVA_-Cz?4mQ3W`hJitlTLhF*gLObK6@qDS+lA0x(4E2J0agpr&cu^; zCO{MD_+OBcSu~yntMX9y*I=$xBgAa|S3PuJ@wbLP?TrDFLn7oI!1w?W6b|fFfXJWR zs>T5*;3zvdesBW5jGjNr;s6}*4v+5OI|y>`@(7+gbxs`u84}+uPY@vw00iu76xufo z;xcky3)%Z&;>+Yhm+!$8%J?!scS9CB;mhtZ2z){+m9XdqJo!a-xeFw$i9EJ~O~`HB z##U^V3ifpbIY!5;!OjkR*D9R>68VYgd@_*MUtkE$$-fkUxcc07c}E{~7;XvDpX)Cb|1|XFuvZq>JsB#)PveQe{;jxBiN^8{5K0jUrRqVzDg~18#Ciz@>FQUv zymy! z&*Od810Fl&u{>a&NYRqnoKmjF>yBohOh1`&!vECeGZ#-?l2ulhSKE~}#We+0>ac&U zetlbytST=DEOI$HMPT2?V*?FMarLpa{zkN(ZYfS}NLFDp%px@Hdbg?*+HWKXULd8 zkEK16c|6zUdZ=x9l%!V#N--vs)1Y?7`7@ zUn0ko6}wEv0^s#bf$8Y;nt{g#G6c;O9Rxkp~37xp$cQT7Cj!TNVhT`^& zI&4Hw_&KKS_Q{rzgsVT3nbUxjS!=s=ByFFeTQM)>Kqhz5aopk1G=ntHm(bZMG8dQ$BhNn1}_Fh1}7Nti)0c zsT@ogRyZ#PtP12$h;{@IwrJG15JZTZim@zu2-s#H3a(^DF9b*f!~-`SXB4TWX_;v% zT*RcM)i;-FDx{sz1Pp>3(E_#;_tAw?r_B|uIG=Ss?X=o8Z{QexDBE<7`o%{7?Ua9oUL)qyK{_Ai_VIOP#S7N&Z?ckpe>SiZNU9u zm_q=i4bJZ5(sVGj!PB!f7mo=XL{82L5inMgk&7V{T*SK~8Nwgw=%`(Z+g00lwVjUA zU=<3WUD{k?Dq6tekKu^y$hJ1`S7AGt=)v}92iHh2woB0rmiQX{&w_)RM|6e?WpRxG1qwgX1Z!msyPF7Ub7d7P6Vlc}3fyKQX z{8za}`FR?A4PT@4^9plwl!99goGkcu9*=ILU}-~rO?{;X|K@0ah;2_8fQ@>SAE*Hu zm0Ehb1*Q3A1^#G9oZ@s=Z~7@U&T;h6C(|Pi z>r_B2x`_Sz(lt28)kCN2v$jPmT?xPQJ9rqtDh3Y{nDII?+Y{^5u5Q$qRByH=X89*( zW+qsbz#re{>&mNY!JH4q<+i%|_71QcjvmY20Be`s_Y9ba=Ca)^9*q@#$RFGQTd(6C zD%WBR767mVjOD@V9ovsqp^2K>2HSzmI?N+AtVd2c@Vk*_I(IXT8ZbX?y>VB zUjx`hNA3vvLF4-_R%7+suyd>U8$5c5_dOFpf9J3&TGE@)C^juSC%r(E5|OF3M9T2A z8F=ALyha5M-v?g!X1a!$w-VTSu>AxDq`vRwfu|HHXh4~0-SQeQgF!}1ZYz~VPn9c zflBaRv=`n3Qn*Usc#Ek45eF0^LSR7lb6Mh?HnDpSg`cyk1F(JR%Ob?7Vgyf{qpy_(zgvuS>Vj=cLo{pa z>7>`QufDBBFQFGv3;F@B7jX-I>9Oo}NgLE_GwF{*7W7V4osfp`C!~n`D{ zw)N2Ge`)&ziIhHfGEX#uH_&MpKf(LB?vesIuAl_mzgzL^#-FF3QCH;Vl;)~*24l45 z5hQEJ5XpdL?T;vL1Qt`RP}9%>a6BA^|X!|NjdB_-jxI_CZ_l=Idxa zYiv&H$kZH3Ka|;-Ec<2Ut6=@}QDUDhSUP#7+LCO}G^NX|nW;%eh5%56KxP0ZU4iv*KA7w1xTwa7;q_g#*D8$PI$hF$~8E;@fbZi2er?M%mste&UVe zXw>l^U;pv=3AlcEd7Zho235`~JX|gRb zKMD8VG5SSkg(gI)?#yI@*VMn7sL4H8YOkr6)!UoP8&pmwgM1I4LNhLF(2)Uk4S`SY@Fxs`Oc(;0h69>rvKnWwBS-<;xgEr(x6DibxmxA2GpmIW%yoQloTB&TirQB-&)3iy;JKCM^{C2fZQ!-8vmGcos@_>` zs?06jUahZ9ZjxoybQv>rMOIl>wlW*yIdawc z1=gI%9Q>fsugF}o-=uuC4DGI?OOHNR`nu}nH;VJ$(-gdSwdhq6NdZ#d`u?6~~Z{9B`t z1-wD7iVv{1TrJ$)^S%f-D(W5jPFReasvb;xyJU+{ge@XLF!sW1Y>t#pxHf&n1 zT#>nH|1Pz8XL!_BlgzYrRr(xN=QBka^;w~<(os*A)DqVV3{f`x~wu*<2rlCTY(;`{I>jL zIg(cYQuReK+EM8DP0?Fb7i+$1ey6Rcv#0a&>5I>wJl%P&@mbk{muvs|59Qaf*EhbW z_U+#I{v1%Pj(mLjABWnTWxgjboH*Xqepc3gw(i1Z<%PWN^t0;pv+-Sq_cH?QCUG% zdPQ{U<|=F`!^+a9%Ut<>^NXIy4^bDT=A~pM$7FvlUt%w-s(;S!0?Is#=3GHno8CWo>lpI)FKe$jT79zST+OkX zwj*_?YR}i6x1XsyQCHPo(E_mQ%IeFS(o1y3!G*H?$*YP&RM{3=S)>NP*O)ZkUffX9 zT;l&u;qy61(`3n|nI*aE+#T^)mAc-5XO|S1md4@P{+a8x;&v0(YMUovWmkUrJ&Pu zXoQi+mlzyVO8Y8*2502splvA@57<9pE;b(RGHHC@z@yN7Q&))11UB+fcs{K&H5xCf zKDlFG%!H&Hbw@N1lr{f|?xO7oSi+$#0O~rDel$eo146*S?V*`hq6(0H%NP%`pACJIXr6*_&%wUIKAOx$>g;p&(WnhH6fYKMq71sza*elGHFyzT zNPIVF5n6Pb9n8$&3wSgMoXv3B$C6Mh1fewGk~#e>zp;A#;b65xG}uIkv|TbiuX_H{ zk&Epb2jy&{55H9X#uX)4CZOX@#Zq2#rw<$&plbvIOi;aXCP=0bJUn3c-RxUQ+%1X* z{>fL~SNpafs_Cq6Q#Z8rzSI7;tgaj)tW-6%1zF{q_Q!hHHYCdG6KgDHrSE2tnfv2@ z*#3!n`zLrG>Rg06WEV2S+hbHQ5ecCgnnkz+d`6wy7t4G@cPx&bJ`uY72A&*2kiR() z6bXoV6U+i~@qib)t=M{V>dOo`ML-S4(`fXOqhDdqDM`!8!N1|({Bm;AN^(==Jist4j@u&|VHkfH@Du$@Qy2AQ$ zyS=B!4Apu-Qm z??=AR!Q1>cw5nx=g{6hW@|2gSS+|amKUv#qsXH{+_oKfB=iXcIlJfGBa)=elxEVFOi~iUHd&I=pcASXucdT%& zI1%%L?ZgRx=S$9)Xz&P5Vg--jbHH8UD3D7bnD#I%oeT0z8Q3~q@{90U0|W>Iq7TOh z1NXBNgAP&M96-(t7<7ax5CV`lsF`;0Kr{)mF%V-31dg>2)dn!v5Y0Px-e3)^bLR_u zAk-tD0EPi=Wb4oq5)tMOdh~ZfmOf-|vv(;;YY^!I0+^8?SJRo`dC@ukP#kZu9gS@X z7R zCS-&8Ac`H_`5nyExf3wSe-KjId?+zTryShb!;;qltDAkOl@Z$Z084;cCoF^bIV@Ee zi3{;N-Umb2864mq;zq|m6=t(Nu}cM>#x8r?A+v@+MLw**Gn*WdKniw(tq8euTdsi8Zq0W~rrMOat z%m0Qa9T0xxB&|C-8&94BV}cy@fj6lSv`8TpH^P5~fbH1MJPwr1O5YI>fq5L>0N%zO zpw)L380LDgt&xsGhe10dgc}3xt5^u(a<_ofE8Q_ik&>4J5mvKj)0vr&g(IvQf*&EM z=Wz@dRD$rSN=YG=v%iJN&b$_g?5u8v$WA1*LC~f?kA!H=1=V$Z2@4m*i z!)jf11|vI|n8CTKI0gr=6lqxSh(fRxsD;zUZFwYAz1w8iX;p%+pFb`A>8H=%KcT*I z^vK~Cl@~X6uZ!LX%cM?9PfXsuNtT-rdYCFNudJd#gZ+NZs4Z-@H~OP-Um>6O(8DSS zoDRl3UI$DI2g5tT@K!iGt*{MN6a;gygZes?bp@Y!A_yRcap%RV1Aj6_&7Kx;2d?wJhEtaB~olpbt#z|334}xAjCm}zo^*y)xKLutVI8W?{JDyFB1Q@ zZ_8I|ht9Q2;aCbEKK)ESZ-CDnes(Q&ErZV-ejfVF;b+G(wNC)OE>Uz9__G-Nz3=RO zZ6z2L7<36;qB{jz2UcO}R4@MkgsPa&d5c9es2Nn#RuU84VO2XdgMo>XE1Z^x!2y&xJLkH-3zbN3m%kH8KljihAJNb-ug>0nsnuBd*6X?d6;)zd+r*T zW2CS(mmnq)+H`6@{E%?I6J&tp0rb`DATh%L%b^w|O)E&6u#ND-5T68qh?oB|I~X|p z2@cFJ@H7ifZHSfthPe--wSjaqP6Yd#K)hyrfmUFjYbnTCJU^_5+x3N53hR# z%hh$(x|pT}S$1`GUZbk5zWG3NVQWdVrl`BPyIbklk4}H?SP7qr0PoF%gUtaaGMsqM zLWgx1?>y+dy%z!%qyh8|Q3L#d1ncPA3r`1b?*eB7@SU5^Ai{UTK*kTiV-(5hX({SM zd~#Y-s|GzOZEb1-=Sncs(wLU4DMm9C=_P4d;9uOpB&F3gYEqmc8a&F?73#_=d%0bO zOpM)LR8XaQxY8$jL6_Ykc&_$lHY{ri9Qr?lgOz-=rM)PkfMXZbcU8L&C61U zPD*?Y2U(X+x>f4h?fglZc;v8 z4XQz@C<#qQf2!cj1MkmH#g|cl&Gf^j-P?oJ;GFSuJ$4<3t(D<3({U9}#P2J0<+>`p zx+3xLwwx_^=b~}Sgz9{Iih9qH1F>&>{Td2=L3RG-`qbw&u{VB6y{SUe(A4wqAe9D; z`f9Wr?Y)Yw${Ma#zj>8d_#v(fJp@s(pg{&fWG{s1xT8FPC^iG04cu0s8#oI-dO3!C z)ukmxrS$QQT{BkW8dtF1<*URuP!?W^j$vPQNohq19dkwZ{d=g!5q!$w3*la{n*$Ow zUgQWyI(rdKs&+03P}IdMxon^wJ+EegJG^7B0Xxyc%CLKZ^bQ;6Uhr6Dl5U z*PMIqT+i`;$Qlk-w;v`8L*z602~b(lJVNvDvqSXW2=x9Z55$h2lomT!MMg4@`|!bbNtJ)t8(lGj!JyO57)!Bt(Pt>F0vKDH>o6MXX+Gi=;uJYQV7SX zDF7jBiywIBDywp93TsRJOKtE~7}!oUH*Z3GK79S*zYT3e^>CeVRgw<&V*iqIh%Zr9 zSC>^(g0^$Bwx+V7sNNq3IoG3kXx`16S5eTqtNx(10=0Et1*sM6Fn;`rt0#cl1;ImD zSRpS5K1Zw^3dHeOM zu@muwpA$d5brnd044QhC_)A~aod2Qw`&c>N|F)9h5%!0F8W~ zOX7qE><;<;HLE}y1wH9Hs3Sy80@-H}q@3Y{UXUS<^Hw5*49O3md?gc|=`UFU{A{4D zfsjB9Qhx~vM5zLGEd^u)kVD*p1(97&Lo5)Q4r>Qeb258EQC(D1Sf$265MffCpAA7} zu0Bx7gPCP)Q$bU99Yk<~t)Ve9xh6@Kl$@ImT2Y@%PG@Hoq@^K<+=iYnHXFSjIS=0spgd563i}N>f zk6XpVsBFQsxjg;O?JtUpi3k7a-Q)VbjFxT zvu)6pLrfF{lxH+gg0LQH5P-V>h`o9|_GVmVuA$1Ut2S;}6C%w{$x2C4(R#2LTireA zGXTz?AH*3;N=>Ee2jA~L^BMn|dECX&Z;-VqG#0AMi!9bMen9!STMt!W*k*AJ@r}uQ zOwxJ#0$W;D`|_L0>bXB)X}$J3c{4?dR8nb)ib(I>Bhm|}!`AHMjyMjLHP^%~-Mo6` zw)brZ^7oZWu@o)zM-Yj0asEV>kgepk&VHgHWG&VNHI`!fX8XTrvGZR*G;ak; z_W2{SfrA;dl|CgNoxWurPdk&P60(Nu^~V4|r@17&e~&0W^3bDNU~(%E9)-op%uY-c z!!*o*9Hxl@^o{X&85^7#&^;#N47#r>34Hv6m?MO%%Dp&A&K~$gK==z0Z!KOreIzYJ zA#wr=C8jcPn25upDggj}Cvm6@vF=Xfc`&lY418P3?p#c^TJ*y6+{M}Iawy-Ig>1DK zY~u>H*|&zM-k0?pe*4j*+qWO>+>w@4$0gOJ?bxYe?;qVB-jj3QZPzMy(gsqpp^5YA zFX&!-O}Fjd=*mbQYb6XH(N}FJ(GedN384c>e;Q10bUcFbZU6}(KwzBws*Q6FYaiCZ zZ#>h|a>fHt=4mJiy?OObZ6j8`8bz?L28{2 zw?jE)-rUJk=AOM;r}^|8;JYqI*Z+LN$?fbzkl5X$ltsyf3BcYCtWMdHv^{aV?~eVu z_U_y-&9MQ@s@g$iq|>$<&YF(d2q6oj0kB)y(C~t={B60uI#4%?j0yP(YC21tkd&N| z!6z;?Xbnq3Q^JzN5~<{SpB&GQAwU;D7aGMQZ2-R`&61Xr&NZyxwPDBF#4vqW>NfgX zxDR65@rf!rQ<9LESY+hLz;MUbg3zK+-;i~|8$#AgK|X~5LkN-i*M)PyeIgfQ&ov|Y zKxE(5B-QHcQhlqzLP;5J54mbj=OuLx1%qt?^bw&`B{My_)@>-2gp*gR(Pz9{PZ%WcbGeJfMYUJa}R{xq( z!4Wm+0@+>hv3$}5nLGtwdB2d)!dJ|$Z2BieX4oF0#rORpS2BDwoUT1t*y&<5l|L z6PbO#Ve63PCayBPXnBxIzSa7(#u8(Wjs~D}bToL~v?1%ZN$GZW z!(kqL9+nsmT)E>$aPm%m1+I3V)#N2Ly7HrVueeoKd$91>F;#VDO?nmAaHRC?IaN1U zZ&vTC^W|P??H8 zt(!nK+>8$!$*cVzZrvGPA673t_b$aqj8zAT<+D#>a3p8$?kzvX?;}qU@g5?BC5kU9 zNte%;U|{64t-UaPaW-@T5p?cToA-<*J~B<&ohWw)w!cW5@;|KTS&P zdM@^C&=Jm7WvQuF;Sk3XkA)rN%thJ7MXHv_mUYKCt3-bAB$=I!*|QU!uBKhZbP#=E z{Sx{zpByqec&nOX;AWqEGK|~B`?q~EWY@agEBCD0xAy$>Ep+Iw{iNP-%OAfs{d|!=I z%ex;^FJ#^vx*H}$k2uZ0HJ)?}>4_CsabMZA&Jc#Ys@R)F(Rw9Lnly(JKiTo73>MNq zq;8P#^nSs+0)*yGh>sxm?VNs(q>+3~)5-AR<@jg7zvM1>+fC`5PU709ONw3o%D0y+ z7|mswByTJ^_0cCMPF%l!bkVeIUby+#Unxi=_cmXCea8A#Yhts;gSNn2s#9Pz3USvXoF>* z1qz5+X8?tr|2n`1gQ*WEI3#r%uqSZ+d-PuzdxCevO7{WvelUFa4`d{OX2>D4?1)DchD@fD zkx%dkAp|kmQ5vKI{Ml#3kIgO2u;~m?lEMpM-UP%pX}gRT#qSnQ+qz-D6$q_np!we% z#v?kG2bBWvH=AG#w*FfNQ__W`u+YjV21KEFU3k~oQ%RRJQ(xlui|RfS2y{pT?e^Yl zoa-{#q3lO}fkjxdhI{XB1CWzLfSViu(}yU&meJ<>;tZL)HC{G=GR2dFGCGgM(hcOp zc<#XBrr@#!>B(h9OJ=BM1i{H1Fk=7*NWK%0{1(am0WAXt1hurZ6dgNxgexm*+I8T# zlzdnWQp*O$sKYg~>3mgubySt5{$3Fhd@G5fmb|miIhNGRb505zc}JO(V|1k3puUlv zVK8KvQ|##wWHRMgrSb{-)fbf+_Ed`@!;qN;Vuv*?H#5f~&5~GivT_Y}>8uM%b55o; z-2&{m$(U)(uo!Ha)=Zn(Y?0OnDswC*yTN9#rXh)#k(r%lO}85C#+)1}!T?>BW?Q-) z$N&gO7?C!&r8$gJd2c<)gch?+dfA|~r&?1?TuPcDJ&%jV_J>m7EhjX#&CG}$0P zV@ffmr)Q^Sg970&18-w9*`%(;t~pG_3l3q!?yMtxnd!T?G&{m;R=oLg7VQ$ITGp7= z0HX<~kKqLViyF`ZX25vy#L&qLUWauretq((&qI0l`2SD>mMinB4LhRCn7V~eVN$Fu zP8}EPK`3b5+K*vxxV7R}@zhr)XmR%Is!M9}cy4h%WV1ykvRAQnh@pe{fv& z4*p=(dxuqWYvqlw>o-&+{ZrCN-X*Vc=MP?M_+-0u_wDcZ{HT^2{IRNumXT-n?|1B1 z=UB5$IlSCH!4a1o75#4VyDL-+@C;qngg&E|n?r_%!H$Fxa>!;Y#Q zJ9