Repository: matryer/xbar
Branch: main
Commit: d62423905899
Files: 708
Total size: 4.6 MB
Directory structure:
gitextract_oblxmil8/
├── .github/
│ ├── FUNDING.yml
│ └── workflows/
│ └── deploy-xbarappcom.yaml
├── .gitignore
├── .vscode/
│ └── settings.json
├── LICENSE.txt
├── README.md
├── app/
│ ├── .gitignore
│ ├── README.md
│ ├── app.go
│ ├── build.sh
│ ├── categories_service.go
│ ├── categories_service_test.go
│ ├── command_service.go
│ ├── frontend/
│ │ ├── .gitignore
│ │ ├── package.json
│ │ ├── postcss.config.js
│ │ ├── public/
│ │ │ └── index.html
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── App.svelte
│ │ │ ├── Homepage.svelte
│ │ │ ├── InstalledPluginView.svelte
│ │ │ ├── PersonView.svelte
│ │ │ ├── PluginView.svelte
│ │ │ ├── PluginsList.svelte
│ │ │ ├── backend/
│ │ │ │ ├── index.js
│ │ │ │ └── package.json
│ │ │ ├── elements/
│ │ │ │ ├── A.svelte
│ │ │ │ ├── Breadcrumbs.svelte
│ │ │ │ ├── Button.svelte
│ │ │ │ ├── Duration.svelte
│ │ │ │ ├── Error.svelte
│ │ │ │ ├── KeyboardShortcuts.svelte
│ │ │ │ ├── PluginCollection.svelte
│ │ │ │ ├── PluginDetails.svelte
│ │ │ │ ├── PluginSourceBrowser.svelte
│ │ │ │ ├── Spinner.svelte
│ │ │ │ ├── Switch.svelte
│ │ │ │ ├── VariableInput.svelte
│ │ │ │ └── Variables.svelte
│ │ │ ├── main.js
│ │ │ ├── pagedata.svelte
│ │ │ ├── rpc.svelte
│ │ │ ├── signals.svelte
│ │ │ ├── styles.css
│ │ │ └── waiters.svelte
│ │ └── tailwind.config.js
│ ├── go.mod
│ ├── go.sum
│ ├── incoming_urls.go
│ ├── incoming_urls_test.go
│ ├── main.go
│ ├── menu_parser.go
│ ├── menu_parser_test.go
│ ├── package.json
│ ├── package.sh
│ ├── person_service.go
│ ├── plugins_service.go
│ ├── settings.go
│ ├── settings_test.go
│ ├── test.sh
│ └── wails.json
├── archive/
│ └── bitbar/
│ ├── .gitignore
│ ├── .gitmodules
│ ├── .travis.yml
│ ├── App/
│ │ ├── BitBar/
│ │ │ ├── App.xib
│ │ │ ├── AppDelegate.m
│ │ │ ├── Base.lproj/
│ │ │ │ └── MainMenu.xib
│ │ │ ├── BitBar-Info.plist
│ │ │ ├── CHANGELOG.md
│ │ │ ├── ExecutablePlugin.h
│ │ │ ├── ExecutablePlugin.m
│ │ │ ├── HTMLPlugin.h
│ │ │ ├── HTMLPlugin.m
│ │ │ ├── Images.xcassets/
│ │ │ │ └── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ ├── NSColor+Hex.h
│ │ │ ├── NSColor+Hex.m
│ │ │ ├── NSString+ANSI.h
│ │ │ ├── NSString+ANSI.m
│ │ │ ├── NSUserDefaults+Settings.h
│ │ │ ├── NSUserDefaults+Settings.m
│ │ │ ├── Plugin.h
│ │ │ ├── Plugin.m
│ │ │ ├── PluginManager.h
│ │ │ ├── PluginManager.m
│ │ │ └── incoming-url-tests.html
│ │ ├── BitBar.xcodeproj/
│ │ │ ├── project.pbxproj
│ │ │ ├── project.xcworkspace/
│ │ │ │ ├── contents.xcworkspacedata
│ │ │ │ └── xcshareddata/
│ │ │ │ ├── BitBar.xccheckout
│ │ │ │ ├── BitBar.xcscmblueprint
│ │ │ │ └── IDEWorkspaceChecks.plist
│ │ │ └── xcshareddata/
│ │ │ └── xcschemes/
│ │ │ ├── BitBar.xcscheme
│ │ │ └── BitBarDistro.xcscheme
│ │ ├── BitBarTests/
│ │ │ ├── BitBarTests-Info.plist
│ │ │ ├── PluginManager+Test.h
│ │ │ ├── PluginManager+Test.m
│ │ │ ├── PluginManagerTest.m
│ │ │ ├── PluginTest.m
│ │ │ └── TestPlugins/
│ │ │ ├── one.10s.sh
│ │ │ ├── three.7d.sh
│ │ │ └── two.5m.sh
│ │ └── Vendor/
│ │ ├── AHProxySettings/
│ │ │ ├── .gitignore
│ │ │ ├── AHProxyExampe/
│ │ │ │ ├── AppDelegate.h
│ │ │ │ ├── AppDelegate.m
│ │ │ │ ├── Base.lproj/
│ │ │ │ │ └── MainMenu.xib
│ │ │ │ ├── Images.xcassets/
│ │ │ │ │ └── AppIcon.appiconset/
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── Info.plist
│ │ │ │ └── main.m
│ │ │ ├── AHProxySettings/
│ │ │ │ ├── AHProxy.h
│ │ │ │ ├── AHProxy.m
│ │ │ │ ├── AHProxySettings.h
│ │ │ │ ├── AHProxySettings.m
│ │ │ │ ├── NSTask+useSystemProxies.h
│ │ │ │ └── NSTask+useSystemProxies.m
│ │ │ ├── AHProxySettings.podspec
│ │ │ ├── AHProxySettings.xcodeproj/
│ │ │ │ ├── project.pbxproj
│ │ │ │ ├── project.xcworkspace/
│ │ │ │ │ └── contents.xcworkspacedata
│ │ │ │ └── xcshareddata/
│ │ │ │ └── xcschemes/
│ │ │ │ └── AHProxySettings.xcscheme
│ │ │ ├── AHProxySettingsTests/
│ │ │ │ ├── AHProxySettingsTest.m
│ │ │ │ └── Info.plist
│ │ │ ├── LICENSE
│ │ │ └── README.md
│ │ ├── DateTools/
│ │ │ ├── .gitignore
│ │ │ ├── .travis.yml
│ │ │ ├── CREDITS.md
│ │ │ ├── DateTools/
│ │ │ │ ├── DTConstants.h
│ │ │ │ ├── DTConstants.m
│ │ │ │ ├── DTError.h
│ │ │ │ ├── DTError.m
│ │ │ │ ├── DTTimePeriod.h
│ │ │ │ ├── DTTimePeriod.m
│ │ │ │ ├── DTTimePeriodChain.h
│ │ │ │ ├── DTTimePeriodChain.m
│ │ │ │ ├── DTTimePeriodCollection.h
│ │ │ │ ├── DTTimePeriodCollection.m
│ │ │ │ ├── DTTimePeriodGroup.h
│ │ │ │ ├── DTTimePeriodGroup.m
│ │ │ │ ├── DateTools.bundle/
│ │ │ │ │ ├── ar.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── bg.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── ca.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── cs.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── cy.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── da.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── de.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── en.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── es.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── eu.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── fi.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── fr.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── gre.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── gu.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── he.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── hi.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── hr.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── hu.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── id.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── is.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── it.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── ja.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── ko.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── lv.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── ms.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── nb.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── nl.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── pl.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── pt-PT.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── pt.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── ro.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── ru.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── sl.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── sv.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── th.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── tr.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── uk.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── vi.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ ├── zh-Hans.lproj/
│ │ │ │ │ │ └── DateTools.strings
│ │ │ │ │ └── zh-Hant.lproj/
│ │ │ │ │ └── DateTools.strings
│ │ │ │ ├── DateTools.h
│ │ │ │ ├── NSDate+DateTools.h
│ │ │ │ └── NSDate+DateTools.m
│ │ │ ├── DateTools.podspec
│ │ │ ├── Examples/
│ │ │ │ └── DateToolsExample/
│ │ │ │ ├── DateTools/
│ │ │ │ │ └── Info.plist
│ │ │ │ ├── DateToolsExample/
│ │ │ │ │ ├── AppDelegate.h
│ │ │ │ │ ├── AppDelegate.m
│ │ │ │ │ ├── Colours.h
│ │ │ │ │ ├── Colours.m
│ │ │ │ │ ├── DateToolsExample-Info.plist
│ │ │ │ │ ├── DateToolsExample-Prefix.pch
│ │ │ │ │ ├── DateToolsViewController.h
│ │ │ │ │ ├── DateToolsViewController.m
│ │ │ │ │ ├── DateToolsViewController.xib
│ │ │ │ │ ├── ExampleNavigationController.h
│ │ │ │ │ ├── ExampleNavigationController.m
│ │ │ │ │ ├── Images.xcassets/
│ │ │ │ │ │ ├── AppIcon.appiconset/
│ │ │ │ │ │ │ └── Contents.json
│ │ │ │ │ │ └── LaunchImage.launchimage/
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ ├── TimePeriodsViewController.h
│ │ │ │ │ ├── TimePeriodsViewController.m
│ │ │ │ │ ├── TimePeriodsViewController.xib
│ │ │ │ │ ├── en.lproj/
│ │ │ │ │ │ └── InfoPlist.strings
│ │ │ │ │ └── main.m
│ │ │ │ ├── DateToolsExample.xcodeproj/
│ │ │ │ │ ├── project.pbxproj
│ │ │ │ │ ├── project.xcworkspace/
│ │ │ │ │ │ └── contents.xcworkspacedata
│ │ │ │ │ └── xcshareddata/
│ │ │ │ │ └── xcschemes/
│ │ │ │ │ └── DateTools.xcscheme
│ │ │ │ └── DateToolsExampleTests/
│ │ │ │ ├── DateToolsExampleTests-Info.plist
│ │ │ │ └── en.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ └── Tests/
│ │ │ └── DateToolsTests/
│ │ │ ├── DateToolsTests/
│ │ │ │ ├── AppDelegate.h
│ │ │ │ ├── AppDelegate.m
│ │ │ │ ├── Base.lproj/
│ │ │ │ │ └── Main.storyboard
│ │ │ │ ├── DateToolsTests-Info.plist
│ │ │ │ ├── DateToolsTests-Prefix.pch
│ │ │ │ ├── Images.xcassets/
│ │ │ │ │ ├── AppIcon.appiconset/
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ └── LaunchImage.launchimage/
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── ViewController.h
│ │ │ │ ├── ViewController.m
│ │ │ │ ├── en.lproj/
│ │ │ │ │ └── InfoPlist.strings
│ │ │ │ ├── es.lproj/
│ │ │ │ │ ├── InfoPlist.strings
│ │ │ │ │ └── Main.strings
│ │ │ │ ├── ja.lproj/
│ │ │ │ │ ├── InfoPlist.strings
│ │ │ │ │ └── Main.strings
│ │ │ │ └── main.m
│ │ │ ├── DateToolsTests.xcodeproj/
│ │ │ │ ├── project.pbxproj
│ │ │ │ ├── project.xcworkspace/
│ │ │ │ │ └── contents.xcworkspacedata
│ │ │ │ └── xcshareddata/
│ │ │ │ └── xcschemes/
│ │ │ │ ├── DateToolsTests.xcscheme
│ │ │ │ └── DateToolsTestsTests.xcscheme
│ │ │ └── DateToolsTestsTests/
│ │ │ ├── DTTimeAgoTests.m
│ │ │ ├── DTTimePeriodChainTests.m
│ │ │ ├── DTTimePeriodCollectionTests.m
│ │ │ ├── DTTimePeriodGroupTests.m
│ │ │ ├── DTTimePeriodTests.m
│ │ │ ├── DateToolsTests.m
│ │ │ ├── DateToolsTestsTests-Info.plist
│ │ │ ├── en.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── es.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ └── ja.lproj/
│ │ │ └── InfoPlist.strings
│ │ ├── LaunchAtLoginController/
│ │ │ ├── LaunchAtLoginController.h
│ │ │ ├── LaunchAtLoginController.m
│ │ │ └── README.md
│ │ ├── NSStringEmojize/
│ │ │ ├── .gitignore
│ │ │ ├── Example/
│ │ │ │ ├── NSStringEmojize/
│ │ │ │ │ ├── DIYAppDelegate.h
│ │ │ │ │ ├── DIYAppDelegate.m
│ │ │ │ │ ├── DIYViewController.h
│ │ │ │ │ ├── DIYViewController.m
│ │ │ │ │ ├── NSStringEmojize-Info.plist
│ │ │ │ │ ├── NSStringEmojize-Prefix.pch
│ │ │ │ │ ├── en.lproj/
│ │ │ │ │ │ └── InfoPlist.strings
│ │ │ │ │ └── main.m
│ │ │ │ ├── NSStringEmojize.xcodeproj/
│ │ │ │ │ ├── project.pbxproj
│ │ │ │ │ └── project.xcworkspace/
│ │ │ │ │ └── contents.xcworkspacedata
│ │ │ │ └── NSStringEmojizeTests/
│ │ │ │ ├── NSStringEmojizeTests-Info.plist
│ │ │ │ ├── NSStringEmojizeTests.h
│ │ │ │ ├── NSStringEmojizeTests.m
│ │ │ │ └── en.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── LICENSE.md
│ │ │ ├── NSStringEmojize/
│ │ │ │ ├── NSString+Emojize.h
│ │ │ │ ├── NSString+Emojize.m
│ │ │ │ └── emojis.h
│ │ │ ├── NSStringEmojize.podspec
│ │ │ └── README.md
│ │ ├── STPrivilegedTask/
│ │ │ ├── .gitignore
│ │ │ ├── LICENSE.txt
│ │ │ ├── PrivilegedTaskExample/
│ │ │ │ ├── PrivilegedTaskExample/
│ │ │ │ │ ├── AppDelegate.h
│ │ │ │ │ ├── AppDelegate.m
│ │ │ │ │ ├── Base.lproj/
│ │ │ │ │ │ └── MainMenu.xib
│ │ │ │ │ ├── Info.plist
│ │ │ │ │ ├── lock-icon.icns
│ │ │ │ │ └── main.m
│ │ │ │ └── PrivilegedTaskExample.xcodeproj/
│ │ │ │ └── project.pbxproj
│ │ │ ├── README.md
│ │ │ ├── STPrivilegedTask.h
│ │ │ ├── STPrivilegedTask.m
│ │ │ └── STPrivilegedTask.podspec
│ │ └── Sparkle/
│ │ ├── .clang-format
│ │ ├── .gitignore
│ │ ├── .travis.yml
│ │ ├── CHANGELOG
│ │ ├── Configurations/
│ │ │ ├── ConfigBinaryDelta.xcconfig
│ │ │ ├── ConfigBinaryDeltaDebug.xcconfig
│ │ │ ├── ConfigBinaryDeltaRelease.xcconfig
│ │ │ ├── ConfigCommon.xcconfig
│ │ │ ├── ConfigCommonCoverage.xcconfig
│ │ │ ├── ConfigCommonDebug.xcconfig
│ │ │ ├── ConfigCommonRelease.xcconfig
│ │ │ ├── ConfigFileop.xcconfig
│ │ │ ├── ConfigFramework.xcconfig
│ │ │ ├── ConfigFrameworkDebug.xcconfig
│ │ │ ├── ConfigFrameworkRelease.xcconfig
│ │ │ ├── ConfigRelaunch.xcconfig
│ │ │ ├── ConfigRelaunchDebug.xcconfig
│ │ │ ├── ConfigRelaunchRelease.xcconfig
│ │ │ ├── ConfigTestApp.xcconfig
│ │ │ ├── ConfigTestAppDebug.xcconfig
│ │ │ ├── ConfigTestAppRelease.xcconfig
│ │ │ ├── ConfigUITest.xcconfig
│ │ │ ├── ConfigUITestCoverage.xcconfig
│ │ │ ├── ConfigUITestDebug.xcconfig
│ │ │ ├── ConfigUITestRelease.xcconfig
│ │ │ ├── ConfigUnitTest.xcconfig
│ │ │ ├── ConfigUnitTestCoverage.xcconfig
│ │ │ ├── ConfigUnitTestDebug.xcconfig
│ │ │ ├── ConfigUnitTestRelease.xcconfig
│ │ │ ├── make-release-package.sh
│ │ │ └── set-git-version-info.sh
│ │ ├── Documentation/
│ │ │ ├── .gitignore
│ │ │ ├── Doxyfile
│ │ │ └── build-docs.sh
│ │ ├── LICENSE
│ │ ├── Makefile
│ │ ├── README.markdown
│ │ ├── Resources/
│ │ │ ├── Images.xcassets/
│ │ │ │ └── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ ├── SUModelTranslation.plist
│ │ │ ├── SampleAppcast.xml
│ │ │ └── Sparkle-Icon.sketch
│ │ ├── Sparkle/
│ │ │ ├── Autoupdate/
│ │ │ │ ├── Autoupdate-Info.plist
│ │ │ │ └── Autoupdate.m
│ │ │ ├── CheckLocalizations.swift
│ │ │ ├── SUAppcast.h
│ │ │ ├── SUAppcast.m
│ │ │ ├── SUAppcastItem.h
│ │ │ ├── SUAppcastItem.m
│ │ │ ├── SUAutomaticUpdateAlert.h
│ │ │ ├── SUAutomaticUpdateAlert.m
│ │ │ ├── SUAutomaticUpdateDriver.h
│ │ │ ├── SUAutomaticUpdateDriver.m
│ │ │ ├── SUBasicUpdateDriver.h
│ │ │ ├── SUBasicUpdateDriver.m
│ │ │ ├── SUBinaryDeltaApply.h
│ │ │ ├── SUBinaryDeltaApply.m
│ │ │ ├── SUBinaryDeltaCommon.h
│ │ │ ├── SUBinaryDeltaCommon.m
│ │ │ ├── SUBinaryDeltaCreate.h
│ │ │ ├── SUBinaryDeltaCreate.m
│ │ │ ├── SUBinaryDeltaTool.m
│ │ │ ├── SUBinaryDeltaUnarchiver.h
│ │ │ ├── SUBinaryDeltaUnarchiver.m
│ │ │ ├── SUCodeSigningVerifier.h
│ │ │ ├── SUCodeSigningVerifier.m
│ │ │ ├── SUConstants.h
│ │ │ ├── SUConstants.m
│ │ │ ├── SUDSAVerifier.h
│ │ │ ├── SUDSAVerifier.m
│ │ │ ├── SUDiskImageUnarchiver.h
│ │ │ ├── SUDiskImageUnarchiver.m
│ │ │ ├── SUErrors.h
│ │ │ ├── SUExport.h
│ │ │ ├── SUFileManager.h
│ │ │ ├── SUFileManager.m
│ │ │ ├── SUGuidedPackageInstaller.h
│ │ │ ├── SUGuidedPackageInstaller.m
│ │ │ ├── SUHost.h
│ │ │ ├── SUHost.m
│ │ │ ├── SUInstaller.h
│ │ │ ├── SUInstaller.m
│ │ │ ├── SULog.h
│ │ │ ├── SULog.m
│ │ │ ├── SUOperatingSystem.h
│ │ │ ├── SUOperatingSystem.m
│ │ │ ├── SUPackageInstaller.h
│ │ │ ├── SUPackageInstaller.m
│ │ │ ├── SUPipedUnarchiver.h
│ │ │ ├── SUPipedUnarchiver.m
│ │ │ ├── SUPlainInstaller.h
│ │ │ ├── SUPlainInstaller.m
│ │ │ ├── SUProbingUpdateDriver.h
│ │ │ ├── SUProbingUpdateDriver.m
│ │ │ ├── SUScheduledUpdateDriver.h
│ │ │ ├── SUScheduledUpdateDriver.m
│ │ │ ├── SUStandardVersionComparator.h
│ │ │ ├── SUStandardVersionComparator.m
│ │ │ ├── SUStatus.xib
│ │ │ ├── SUStatusController.h
│ │ │ ├── SUStatusController.m
│ │ │ ├── SUSystemProfiler.h
│ │ │ ├── SUSystemProfiler.m
│ │ │ ├── SUUIBasedUpdateDriver.h
│ │ │ ├── SUUIBasedUpdateDriver.m
│ │ │ ├── SUUnarchiver.h
│ │ │ ├── SUUnarchiver.m
│ │ │ ├── SUUnarchiver_Private.h
│ │ │ ├── SUUpdateAlert.h
│ │ │ ├── SUUpdateAlert.m
│ │ │ ├── SUUpdateDriver.h
│ │ │ ├── SUUpdateDriver.m
│ │ │ ├── SUUpdatePermissionPrompt.h
│ │ │ ├── SUUpdatePermissionPrompt.m
│ │ │ ├── SUUpdater.h
│ │ │ ├── SUUpdater.m
│ │ │ ├── SUUpdater_Private.h
│ │ │ ├── SUUserInitiatedUpdateDriver.h
│ │ │ ├── SUUserInitiatedUpdateDriver.m
│ │ │ ├── SUVersionComparisonProtocol.h
│ │ │ ├── SUVersionDisplayProtocol.h
│ │ │ ├── SUWindowController.h
│ │ │ ├── SUWindowController.m
│ │ │ ├── Sparkle-Info.plist
│ │ │ ├── Sparkle.h
│ │ │ ├── Sparkle.pch
│ │ │ ├── ar.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── ca.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.strings
│ │ │ │ ├── SUUpdateAlert.strings
│ │ │ │ └── Sparkle.strings
│ │ │ ├── cs.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── da.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── de.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── el.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── en.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── es.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── fi.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.strings
│ │ │ │ ├── SUUpdateAlert.strings
│ │ │ │ └── Sparkle.strings
│ │ │ ├── fr.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── he.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.strings
│ │ │ │ ├── SUUpdateAlert.strings
│ │ │ │ └── Sparkle.strings
│ │ │ ├── is.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── it.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── ja.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── ko.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── nb.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── nl.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── no.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.strings
│ │ │ │ ├── SUUpdateAlert.strings
│ │ │ │ └── Sparkle.strings
│ │ │ ├── pl.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── pt_BR.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── pt_PT.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── ro.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── ru.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── sk.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── sl.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── sv.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── th.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── tr.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── uk.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ ├── zh_CN.lproj/
│ │ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ │ ├── SUUpdateAlert.xib
│ │ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ │ └── Sparkle.strings
│ │ │ └── zh_TW.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.xib
│ │ │ ├── SUUpdateAlert.xib
│ │ │ ├── SUUpdatePermissionPrompt.xib
│ │ │ └── Sparkle.strings
│ │ ├── Sparkle.podspec
│ │ ├── Sparkle.xcodeproj/
│ │ │ ├── project.pbxproj
│ │ │ ├── project.xcworkspace/
│ │ │ │ └── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ └── xcschemes/
│ │ │ ├── Distribution.xcscheme
│ │ │ ├── Sparkle.xcscheme
│ │ │ └── UITests.xcscheme
│ │ ├── TestApplication/
│ │ │ ├── English.lproj/
│ │ │ │ ├── InfoPlist.strings
│ │ │ │ └── MainMenu.xib
│ │ │ ├── SUTestApplicationDelegate.h
│ │ │ ├── SUTestApplicationDelegate.m
│ │ │ ├── SUTestWebServer.h
│ │ │ ├── SUTestWebServer.m
│ │ │ ├── SUUpdateSettingsWindowController.h
│ │ │ ├── SUUpdateSettingsWindowController.m
│ │ │ ├── SUUpdateSettingsWindowController.xib
│ │ │ ├── TestApplication-Info.plist
│ │ │ ├── ar.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── ca.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── cs.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── cy.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── da.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── de.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── el.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── es.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── fi.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── fr-CA.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── fr.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── he.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── hu.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── id.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── is.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── it.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── ja.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── ko.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── main.m
│ │ │ ├── nb.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── nl.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── pl.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── pt-BR.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── pt-PT.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── pt.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── ro.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── ru.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── sk.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── sl.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── sparkletestcast.xml
│ │ │ ├── sv.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── test_app_only_dsa_priv_dont_ever_do_this_for_real.pem
│ │ │ ├── test_app_only_dsa_pub.pem
│ │ │ ├── th.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── tr.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── uk.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ ├── zh-Hans.lproj/
│ │ │ │ └── InfoPlist.strings
│ │ │ └── zh-Hant.lproj/
│ │ │ └── InfoPlist.strings
│ │ ├── Tests/
│ │ │ ├── Resources/
│ │ │ │ ├── SparkleTestCodeSignApp.dmg
│ │ │ │ ├── SparkleTestCodeSignApp.enc.dmg
│ │ │ │ ├── SparkleTestCodeSignApp.tar.bz2
│ │ │ │ ├── SparkleTestCodeSignApp.tar.xz
│ │ │ │ ├── signed-test-file.txt
│ │ │ │ ├── test-pubkey.pem
│ │ │ │ ├── test.sparkle_guided.pkg
│ │ │ │ ├── testappcast.xml
│ │ │ │ └── testnamespaces.xml
│ │ │ ├── SUAppcastTest.swift
│ │ │ ├── SUBinaryDeltaTest.m
│ │ │ ├── SUCodeSigningVerifierTest.m
│ │ │ ├── SUDSAVerifierTest.m
│ │ │ ├── SUFileManagerTest.swift
│ │ │ ├── SUInstallerTest.m
│ │ │ ├── SUUnarchiverTest.swift
│ │ │ ├── SUUpdaterTest.m
│ │ │ ├── SUVersionComparisonTest.m
│ │ │ ├── Sparkle Unit Tests-Bridging-Header.h
│ │ │ └── SparkleTests-Info.plist
│ │ ├── UITests/
│ │ │ ├── SUTestApplicationTest.swift
│ │ │ └── UITests-Info.plist
│ │ ├── Vendor/
│ │ │ ├── CocoatechCore/
│ │ │ │ ├── NTSynchronousTask.h
│ │ │ │ └── NTSynchronousTask.m
│ │ │ └── bsdiff/
│ │ │ ├── bscommon.c
│ │ │ ├── bscommon.h
│ │ │ ├── bsdiff.c
│ │ │ ├── bspatch.c
│ │ │ ├── bspatch.h
│ │ │ ├── sais.c
│ │ │ └── sais.h
│ │ ├── bin/
│ │ │ ├── generate_keys
│ │ │ └── sign_update
│ │ └── fileop/
│ │ ├── SUFileOperationConstants.h
│ │ ├── SUFileOperationConstants.m
│ │ └── fileop.m
│ ├── Docs/
│ │ ├── DistributingBitBar.md
│ │ └── URLScheme.md
│ ├── Makefile
│ ├── README.md
│ └── Scripts/
│ └── bitbar-bundler
├── pkg/
│ ├── metadata/
│ │ ├── categories_metadata.go
│ │ ├── categories_metadata_test.go
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── plugin_metadata.go
│ │ └── plugin_metadata_test.go
│ ├── plugins/
│ │ ├── README.md
│ │ ├── action.go
│ │ ├── action_test.go
│ │ ├── colors.go
│ │ ├── emoji.go
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── install.go
│ │ ├── install_test.go
│ │ ├── installed_plugins.go
│ │ ├── installed_plugins_test.go
│ │ ├── item_params.go
│ │ ├── item_params_test.go
│ │ ├── parse.go
│ │ ├── parse_test.go
│ │ ├── plugin.go
│ │ ├── plugin_darwin.go
│ │ ├── plugin_linux.go
│ │ ├── plugin_test.go
│ │ ├── plugin_windows.go
│ │ ├── refresh_interval.go
│ │ ├── refresh_interval_test.go
│ │ ├── testdata/
│ │ │ ├── broken-plugins/
│ │ │ │ ├── broken.1m.sh
│ │ │ │ └── wont-quit.1m.sh
│ │ │ ├── plugins/
│ │ │ │ ├── 001-multiple.1s.sh
│ │ │ │ ├── 001-multiple.1s.sh.vars.json
│ │ │ │ ├── 002-multiple.1s.sh
│ │ │ │ ├── dirs-should-be-ignored/
│ │ │ │ │ └── .gitkeep
│ │ │ │ ├── expanded.1m.sh
│ │ │ │ ├── expanded.1m.sh.off
│ │ │ │ ├── expanded.1s.sh
│ │ │ │ ├── params.3s.sh
│ │ │ │ ├── simple.1m.sh
│ │ │ │ ├── simple.1m.sh.disabled
│ │ │ │ └── simple.1s.sh
│ │ │ ├── stub-api/
│ │ │ │ └── currency-tracker.1h.py.json
│ │ │ ├── token-too-long/
│ │ │ │ ├── jma.1h.sh
│ │ │ │ └── jma.1h.sh.output
│ │ │ └── vars-test/
│ │ │ ├── plugin.sh
│ │ │ └── plugin.sh.vars.json
│ │ ├── variables.go
│ │ └── variables_test.go
│ └── update/
│ ├── README.md
│ ├── go.mod
│ ├── go.sum
│ ├── update.go
│ ├── update_test.go
│ └── updatetest/
│ └── main.go
├── talk-overview.md
├── tools/
│ ├── sitegen/
│ │ ├── README.md
│ │ ├── docs.go
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── images.go
│ │ ├── main.go
│ │ ├── repo.go
│ │ ├── repo_test.go
│ │ └── run.sh
│ └── xbarmdcheck/
│ ├── README.md
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ └── testdata/
│ └── sample-plugin.sh
└── xbarapp.com/
├── .gcloudignore
├── README.md
├── app.yaml
├── articles/
│ └── 2021/
│ └── 03/
│ ├── 13/
│ │ └── Upgrade-legacy-BitBar-plugins.md
│ └── 14/
│ └── Variables-in-xbar.md
├── build.sh
├── deploy.sh
├── download.go
├── gen.sh
├── go.mod
├── go.sum
├── main.go
├── main_test.go
├── package.json
├── postcss.config.js
├── public/
│ └── css/
│ └── xbar.css
├── run.sh
├── styles.css
├── tailwind.config.js
└── templates/
├── _layout.html
├── article.html
├── articles-index.html
├── category.html
├── contributor.html
├── contributors.html
├── index.html
└── plugin.html
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/FUNDING.yml
================================================
github: matryer
================================================
FILE: .github/workflows/deploy-xbarappcom.yaml
================================================
name: Build and Deploy
on:
push:
branches:
- main
schedule:
- cron: "0 0 * * 0" # every week
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
fetch-depth: 0 # Fetch all history for all tags and branches
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: "1.22"
- name: Run sitegen
working-directory: tools/sitegen
env:
XBAR_GITHUB_ACCESS_TOKEN: ${{ secrets.XBAR_GITHUB_ACCESS_TOKEN }}
run: ./run.sh -skipdata
- name: Auth with Google Cloud
uses: google-github-actions/auth@v2
with:
credentials_json: ${{ secrets.GCP_CREDENTIALS }}
- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@v2
with:
version: ">= 363.0.0"
- name: Deploy to Google App Engine
working-directory: xbarapp.com
env:
GCP_CREDENTIALS: ${{ secrets.GCP_CREDENTIALS }}
run: |
VERSION=$(date +%Y%m%d%H%M%S)
gcloud app deploy --project xbarapp --version $VERSION --quiet --verbosity=debug
================================================
FILE: .gitignore
================================================
.DS_Store
.idea
app/frontend/package.json.md5
xbarapp.com/public/docs/
tools/sitegen/sitegen
app/node_modules
app/build/bin
pkg/update/testarea
xbarapp.com/node_modules
xbarapp.com/public/docs
xbarapp.com/package-lock.json
app/build/darwin/info.plist
app/frontend/package-lock.json
app/build/.DS_Store
app/.DS_Store
xbarapp.com/public/.DS_Store
tools/sitegen/.version
app/.version
xbarapp.com/.version
xbarapp.com/xbarappcom
xbarapp.com/version.gen.go
tools/bloggen/.version
pkg/.DS_Store
================================================
FILE: .vscode/settings.json
================================================
{
"files.exclude": {
"archive": true
}
}
================================================
FILE: LICENSE.txt
================================================
The MIT License (MIT)
Copyright (c) 2014-2023 Mat Ryer + contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
[](https://xbarapp.com/)
# Welcome to xbar
xbar (the BitBar reboot) lets you put the output from any script/program in your macOS menu bar.
* **Complete rewrite from the ground up** - in Go by @matryer and @leaanthony - using [Wails.app (build cross-platform desktop apps using Go & HTML/CSS/JS)](https://wails.app)
* Completely open source
* [Download latest xbar release](https://github.com/matryer/xbar/releases/latest) - requires macOS Catalina or newer (>= 10.15)
* [Visit the app homepage at https://xbarapp.com](https://xbarapp.com)
* [Get started](#get-started) and [installing plugins](#installing-plugins)
Digging deeper:
* [Browse plugin repository](https://xbarapp.com/)
* [Guide to writing your own plugins](https://github.com/matryer/xbar-plugins/blob/main/CONTRIBUTING.md)
And finally...
* [Read the story about how xbar unexpectedly got going](https://medium.com/@matryer/what-happens-when-your-old-open-source-project-unexpectedly-gets-to-the-top-of-hacker-news-31114c6c6efb#.fznvtgskb)
* [Contributing](#contributing) and [special thanks](#thanks)
## Get started
### Install
* [Download the latest release of xbar](https://github.com/matryer/xbar/releases).
## Installing plugins
From an xbar menu, choose **Preferences > Plugins...** to use the xbar app to discover and manage plugins.
You can [browse all the plugins](https://xbarapp.com/) online, or [write your own](https://github.com/matryer/xbar-plugins/blob/main/CONTRIBUTING.md).
### The Plugin Directory
The plugin directory is folder on your Mac where the plugins live, located at `~/Library/Application Support/xbar/plugins`.
* If you're transitioning from Bitbar, move your plugins into this new folder to install them
## Contributing
If you'd like to contribute a plugin, head over to https://github.com/matryer/xbar-plugins to get started.
Please do not send pull requests to this repo. Open an issue and start a conversation first. PRs will likely not be accepted.
* Get started with our [Writing plugins guide](https://github.com/matryer/xbar-plugins/blob/main/CONTRIBUTING.md)
## Thanks
* Special thanks to [@leaanthony at https://wails.app](https://wails.app) and [@ianfoo](https://github.com/ianfoo), [@gingerbeardman](https://github.com/gingerbeardman), [@iosdeveloper](https://github.com/iosdeveloper), [@muhqu](https://github.com/muhqu), [@m-cat](https://github.com/m-cat), [@mpicard](https://github.com/mpicard), [@tylerb](https://github.com/tylerb) for their help
* Thanks to [Chris Ryer](http://www.chrisryer.co.uk/) for the app logo - and to [@mazondo](https://twitter.com/mazondo) for the original
* Thanks for all our [plugin contributors](https://xbarapp.com/) who have come up with some pretty genius things
================================================
FILE: app/.gitignore
================================================
app/frontend/package.json.md5
app/build
.idea
================================================
FILE: app/README.md
================================================
# xbar
Put anything into your macOS menu bar (sequel to BitBar)
## Development
To build xbar, you will need:
* Go v1.15+
* npm v6.14.9
* Wails v2 cli - `go install github.com/wailsapp/wails/v2/cmd/wails@v2.0.0-alpha.72`
### Running
If running for the first time first generate the `.version` file and install the npm dependencies by running:
```bash
cd app && git describe --tags > .version
```
and
```bash
cd app/frontend && npm install
```
To start the application run:
```bash
cd app/frontend && npm run dev
```
and
```bash
cd app && wails dev
```
### Building
In this directory run `./build.sh`. The binary will be generated in `./build/bin/`.
```bash
./build.sh && ./build/bin/xbar
```
### Updates
To use the latest version of the Wails library, ensure that go.mod is using the latest release tag.
The Wails CLI may be updated by running `wails update -pre`. When v2 is released, then `wails update` will keep you
on the stable channel.
### Packaging
Tag the branch:
```bash
git tag -a v0.1.0 -m "release tag."
git push origin v0.1.0
```
```bash
./package.sh
```
* For code signing, xbar uses https://github.com/matryer/gon (fork of https://github.com/mitchellh/gon)
================================================
FILE: app/app.go
================================================
package main
import (
"context"
"fmt"
"log"
"net/http"
"os"
"path/filepath"
"sync"
"time"
"github.com/pkg/errors"
"github.com/wailsapp/wails/v2/pkg/mac"
"github.com/gregjones/httpcache"
"github.com/gregjones/httpcache/diskcache"
"github.com/wailsapp/wails/v2/pkg/options/dialog"
"github.com/matryer/xbar/pkg/plugins"
"github.com/matryer/xbar/pkg/update"
wails "github.com/wailsapp/wails/v2"
"github.com/wailsapp/wails/v2/pkg/menu"
"github.com/wailsapp/wails/v2/pkg/menu/keys"
)
var (
pluginDirectory = filepath.Join(os.Getenv("HOME"), "Library", "Application Support", "xbar", "plugins")
cacheDirectory = filepath.Join(os.Getenv("HOME"), "Library", "Application Support", "xbar", "cache")
configFilename = filepath.Join(os.Getenv("HOME"), "Library", "Application Support", "xbar", "xbar.config.json")
// concurrentIncomingURLs is the number of concurrent incoming URLs to handle at
// the same time.
concurrentIncomingURLs int = 1
// apiRequestTimeout is the timeout for making API calls.
apiRequestTimeout = 30 * time.Second
)
type app struct {
runtime *wails.Runtime
settings *settings
// appMenu isn't visible - it's used for key shortcuts.
appMenu *menu.Menu
contextMenus []*menu.ContextMenu
defaultTrayMenu *menu.TrayMenu
plugins plugins.Plugins
pluginTrays map[string]*menu.TrayMenu
menuParser *MenuParser
startsAtLoginMenu *menu.MenuItem
autoupdateMenu *menu.MenuItem
appUpdatesMenu *menu.MenuItem
// Verbose gets whether verbose output will be printed
// or not.
Verbose bool
CategoriesService *CategoriesService
PluginsService *PluginsService
PersonService *PersonService
CommandService *CommandService
// incomingURLSemaphore is a buffered channel that keeps the
// number of incoming URLs being parsed to one at a time.
incomingURLSemaphore chan struct{}
// lock protects menu items when RefreshAll
// is called.
// Also protects stopPluginsFunc, pluginsStoppedSignal,
// menuIsOpen and isDarkMode.
lock sync.Mutex
stopPluginsFunc context.CancelFunc
// menuIsOpen keeps track of whether menus are open or not.
// If they're open, they will not be updated.
menuIsOpen bool
// pluginsStoppedSignal is closed when plugins have stopped running.
pluginsStoppedSignal chan struct{}
defaultTrayMenuActive bool
// isDarkMode indicates whether the system is running
// in dark mode or not.
isDarkMode bool
}
// newApp makes a new app.
func newApp() (*app, error) {
settings, err := loadSettings(configFilename)
if err != nil {
return nil, errors.Wrap(err, "loadSettings")
}
app := &app{
settings: settings,
Verbose: true,
menuParser: NewMenuParser(),
incomingURLSemaphore: make(chan struct{}, concurrentIncomingURLs),
}
app.appMenu = menu.NewMenuFromItems(
menu.AppMenu(),
menu.EditMenu(),
menu.WindowMenu(),
&menu.MenuItem{
Type: menu.SubmenuType,
Label: "Browser",
SubMenu: menu.NewMenuFromItems(
menu.Text("Refresh", keys.CmdOrCtrl("r"), app.onBrowserRefreshMenuClicked),
menu.Text("Clear cache and refresh", keys.Combo("r", keys.CmdOrCtrlKey, keys.ShiftKey), app.onBrowserHardRefreshMenuClicked),
),
},
)
app.contextMenus = []*menu.ContextMenu{
menu.NewContextMenu("refreshContextMenu", menu.NewMenuFromItems(
menu.Text("Refresh page data", nil, app.onBrowserHardRefreshMenuClicked),
menu.Text("Refresh plugins", nil, app.onPluginsRefreshAllMenuClicked),
menu.Text("Clear Cache", nil, app.onClearCacheMenuClicked),
)),
}
app.appUpdatesMenu = &menu.MenuItem{
Type: menu.TextType,
Label: "Check for Updates…",
Click: app.onCheckForUpdatesMenuClick,
}
app.autoupdateMenu = &menu.MenuItem{
Label: "Update Automatically",
Type: menu.CheckboxType,
Checked: app.settings.AutoUpdate,
Click: app.updateAutoupdate,
}
app.startsAtLoginMenu = &menu.MenuItem{
Label: "Open at Login",
Type: menu.CheckboxType,
Checked: false,
Click: app.updateStartOnLogin,
}
startsAtLogin, err := mac.StartsAtLogin()
if err != nil {
if app.Verbose {
log.Println("open at login:", err)
}
app.startsAtLoginMenu.Label = "Open at Login"
app.startsAtLoginMenu.Disabled = true
} else {
app.startsAtLoginMenu.Checked = startsAtLogin
}
// client-side caching to cacheDirectory
tp := httpcache.NewTransport(diskcache.New(cacheDirectory))
client := &http.Client{
Transport: tp,
Timeout: apiRequestTimeout,
}
app.CategoriesService = NewCategoriesService(client)
app.PersonService = NewPersonService(client)
app.CommandService = NewCommandService(app.RefreshAll)
app.PluginsService = NewPluginsService(client, "https://xbarapp.com/docs/plugins/")
app.PluginsService.OnRefresh = app.RefreshAll
app.defaultTrayMenu = &menu.TrayMenu{
Label: "xbar",
Menu: app.newXbarMenu(nil, false),
}
return app, nil
}
func (app *app) Start(runtime *wails.Runtime) {
app.setDarkMode(runtime.System.IsDarkMode())
runtime.Events.OnThemeChange(func(darkMode bool) {
// keep track of dark mode changing, and refresh all
// plugins if it does.
app.setDarkMode(darkMode)
app.RefreshAll()
})
app.runtime = runtime
app.PluginsService.runtime = runtime
app.CommandService.runtime = runtime
app.CommandService.clearCache = app.clearCache
// ensure the plugin directory is there
if err := os.MkdirAll(pluginDirectory, 0777); err != nil {
log.Println("failed to create plugin directory:", err)
}
app.RefreshAll()
go func() {
// wait before checking for updates
time.Sleep(10 * time.Second)
for {
app.checkForUpdates(true)
// check again in twelve hours
time.Sleep(12 * time.Hour)
}
}()
}
func (app *app) RefreshAll() {
app.lock.Lock()
defer app.lock.Unlock()
if app.stopPluginsFunc != nil {
// plugins are already running - let's stop them
// and wait for them to stop
app.stopPluginsFunc()
<-app.pluginsStoppedSignal
}
// remove plugins
if app.defaultTrayMenuActive {
// only default menu - remove it
app.runtime.Menu.DeleteTrayMenu(app.defaultTrayMenu)
app.defaultTrayMenuActive = false
}
for _, plugin := range app.plugins {
m, ok := app.pluginTrays[plugin.Command]
if !ok {
continue
}
app.runtime.Menu.DeleteTrayMenu(m)
}
var err error
app.plugins, err = plugins.Dir(pluginDirectory)
if err != nil {
app.onErr(err.Error())
return
}
app.pluginTrays = make(map[string]*menu.TrayMenu)
if len(app.plugins) == 0 {
// no plugins - use default
app.runtime.Menu.SetTrayMenu(app.defaultTrayMenu)
app.defaultTrayMenuActive = true
return
}
for _, plugin := range app.plugins {
// Setup plugin
plugin.AppleScriptTemplate = app.settings.Terminal.AppleScriptTemplate3
plugin.OnCycle = app.onCycle
plugin.OnRefresh = app.onRefresh
if app.Verbose {
//plugin.Stdout = os.Stdout
plugin.Stderr = os.Stderr
plugin.Debugf = plugins.DebugfPrefix(plugin.CleanFilename(), plugins.DebugfLog)
}
app.pluginTrays[plugin.Command] = &menu.TrayMenu{
Label: " ",
Menu: app.newXbarMenu(plugin, false),
OnOpen: app.onMenuWillOpen,
OnClose: app.onMenuDidClose,
}
app.runtime.Menu.SetTrayMenu(app.pluginTrays[plugin.Command])
}
app.pluginsStoppedSignal = make(chan struct{})
var ctx context.Context
ctx, app.stopPluginsFunc = context.WithCancel(context.Background())
go func() {
// use stopPluginsFunc to allow the context to
// be canceled - which will kill all running plugin subprocesses.
app.plugins.Run(ctx)
close(app.pluginsStoppedSignal)
}()
}
// CheckForUpdates proactively checks for updates.
func (app *app) CheckForUpdates() {
app.checkForUpdates(false)
}
func (app *app) onMenuWillOpen() {
app.lock.Lock()
defer app.lock.Unlock()
app.menuIsOpen = true
}
func (app *app) onMenuDidClose() {
app.lock.Lock()
defer app.lock.Unlock()
app.menuIsOpen = false
}
func (app *app) updateStartOnLogin(data *menu.CallbackData) {
err := mac.StartAtLogin(data.MenuItem.Checked)
if err != nil {
app.startsAtLoginMenu.Label = "Start at Login unavailable"
app.startsAtLoginMenu.Disabled = true
}
// We need to refresh all as the menuitem is used in multiple places.
// If we don't refresh, only the menuitem clicked will toggle in the UI.
app.refreshMenus()
}
func (app *app) updateAutoupdate(data *menu.CallbackData) {
if data.MenuItem.Checked && app.settings.AutoUpdate {
// nothing to do
return
}
if !data.MenuItem.Checked && !app.settings.AutoUpdate {
// nothing to do
return
}
app.settings.AutoUpdate = data.MenuItem.Checked
if err := app.settings.save(); err != nil {
log.Println("err: updateAutoupdate:", err)
return
}
if app.settings.AutoUpdate {
go app.checkForUpdates(true)
}
// We need to refresh all as the menuitem is used in multiple places.
// If we don't refresh, only the menuitem clicked will toggle in the UI.
app.refreshMenus()
}
// onErr adds a single menu showing the specified error
// string.
func (app *app) onErr(err string) {
if app.defaultTrayMenuActive {
app.runtime.Menu.DeleteTrayMenu(app.defaultTrayMenu)
app.defaultTrayMenuActive = false
}
errorMenu := &menu.Menu{}
errorMenu.Append(menu.Text(err, nil, nil))
errorMenu.Append(menu.Separator())
errorMenu.Merge(app.newXbarMenu(nil, false))
app.defaultTrayMenu = &menu.TrayMenu{
Label: "⚠️ xbar",
Menu: errorMenu,
}
app.runtime.Menu.SetTrayMenu(app.defaultTrayMenu)
app.defaultTrayMenuActive = true
}
// Shutdown shuts down the app.
func (app *app) Shutdown() {
if app.stopPluginsFunc != nil {
// it's possible this gets called _before_ the stop
// func is set. In which case, we'll just ignore it.
app.stopPluginsFunc()
}
}
func (app *app) newXbarMenu(plugin *plugins.Plugin, asSubmenu bool) *menu.Menu {
var items []*menu.MenuItem
if plugin != nil {
items = append(items, &menu.MenuItem{
Type: menu.TextType,
Label: "Refresh",
Accelerator: keys.CmdOrCtrl("r"),
Click: func(ctx *menu.CallbackData) {
app.onPluginsRefreshMenuClicked(ctx, plugin)
},
})
}
items = append(items, &menu.MenuItem{
Type: menu.TextType,
Label: "Refresh All",
Accelerator: keys.Combo("r", keys.CmdOrCtrlKey, keys.ShiftKey),
Click: app.onPluginsRefreshAllMenuClicked,
})
if plugin != nil {
items = append(items, menu.Text("Run in Terminal…", keys.CmdOrCtrl("t"), func(_ *menu.CallbackData) {
err := plugin.RunInTerminal(app.settings.Terminal.AppleScriptTemplate3)
if err != nil {
_, err2 := app.runtime.Dialog.Message(&dialog.MessageDialog{
Type: dialog.ErrorDialog,
Title: "Run in Terminal",
Message: err.Error(),
Buttons: []string{"OK"},
CancelButton: "OK",
})
if err2 != nil {
log.Println(err2)
return
}
return
}
}))
}
items = append(items, menu.Separator())
if plugin != nil {
items = append(items, &menu.MenuItem{
Type: menu.TextType,
Label: "Open Plugin…",
Accelerator: keys.CmdOrCtrl("e"),
Click: func(_ *menu.CallbackData) {
app.runtime.Window.Show()
rel, err := filepath.Rel(pluginDirectory, plugin.Command)
if err != nil {
log.Println(err)
return
}
app.runtime.Events.Emit("xbar.browser.openInstalledPlugin", map[string]string{
"path": rel,
})
},
})
}
items = append(items, &menu.MenuItem{
Type: menu.TextType,
Label: "Plugin Browser…",
Accelerator: keys.CmdOrCtrl("p"),
Click: app.onPluginsMenuClicked,
})
items = append(items, &menu.MenuItem{
Type: menu.TextType,
Label: "Open Plugin Folder…",
Click: app.onOpenPluginsFolderClicked,
})
items = append(items, menu.Separator())
items = append(items, &menu.MenuItem{
Type: menu.TextType,
Label: fmt.Sprintf("xbar (%s)", version),
Disabled: true,
})
items = append(items, app.appUpdatesMenu)
items = append(items, app.autoupdateMenu)
items = append(items, app.startsAtLoginMenu)
items = append(items, menu.Separator())
items = append(items, &menu.MenuItem{
Type: menu.TextType,
Label: "Quit xbar",
Accelerator: keys.CmdOrCtrl("q"),
Click: app.onQuitMenuClicked,
})
if asSubmenu {
m := menu.NewMenuFromItems(
menu.SubMenu("xbar", &menu.Menu{
Items: items,
}),
)
return m
}
m := &menu.Menu{Items: items}
return m
}
func (app *app) createDefaultMenus() {
app.defaultTrayMenu = &menu.TrayMenu{
Label: "xbar",
Menu: app.newXbarMenu(nil, false),
}
}
func (app *app) onPluginsMenuClicked(_ *menu.CallbackData) {
app.runtime.Window.Show()
}
func (app *app) onOpenPluginsFolderClicked(_ *menu.CallbackData) {
_ = app.CommandService.OpenPath(pluginDirectory)
}
func (app *app) onQuitMenuClicked(_ *menu.CallbackData) {
app.runtime.Quit()
}
func (app *app) onPluginsRefreshMenuClicked(_ *menu.CallbackData, p *plugins.Plugin) {
p.TriggerRefresh()
}
func (app *app) onPluginsRefreshAllMenuClicked(_ *menu.CallbackData) {
app.RefreshAll()
}
func (app *app) onBrowserRefreshMenuClicked(_ *menu.CallbackData) {
app.runtime.Events.Emit("xbar.browser.refresh")
}
func (app *app) onBrowserHardRefreshMenuClicked(_ *menu.CallbackData) {
app.clearCache(true)
app.runtime.Events.Emit("xbar.browser.refresh")
}
func (app *app) onCheckForUpdatesMenuClick(_ *menu.CallbackData) {
app.CheckForUpdates()
}
func (app *app) onClearCacheMenuClicked(_ *menu.CallbackData) {
app.clearCache(false)
}
func (app *app) clearCache(passive bool) {
// bit cheeky - but use the oslock in PluginsService to protect
// against this from being run concurrently.
app.PluginsService.osLock.Lock()
defer app.PluginsService.osLock.Unlock()
err := os.RemoveAll(cacheDirectory)
if err != nil {
if passive {
return
}
_, err2 := app.runtime.Dialog.Message(&dialog.MessageDialog{
Type: dialog.ErrorDialog,
Title: "Clear cache failed",
Message: err.Error(),
Buttons: []string{"OK"},
CancelButton: "OK",
})
if err2 != nil {
log.Println(err2)
return
}
return
}
if passive {
return
}
_, err2 := app.runtime.Dialog.Message(&dialog.MessageDialog{
Type: dialog.InfoDialog,
Title: "Cache cleared",
Message: "The local cache was successfully cleared.",
Buttons: []string{"OK"},
CancelButton: "OK",
})
if err2 != nil {
log.Println(err2)
return
}
}
func (app *app) handleIncomingURL(url string) {
// wait for a space
app.incomingURLSemaphore <- struct{}{}
defer func() {
// free up this space
<-app.incomingURLSemaphore
}()
log.Println("incoming URL: handleIncomingURL", url)
incomingURL, err := parseIncomingURL(url)
if err != nil {
_, err2 := app.runtime.Dialog.Message(&dialog.MessageDialog{
Type: dialog.ErrorDialog,
Title: "Invalid URL",
Message: err.Error(),
Buttons: []string{"OK"},
CancelButton: "OK",
})
if err2 != nil {
log.Println(err2)
return
}
return
}
switch incomingURL.Action {
case "openPlugin":
app.runtime.Window.Show()
app.runtime.Events.Emit("xbar.incomingURL.openPlugin", map[string]string{
"path": incomingURL.Params.Get("path"),
})
case "refreshPlugin":
for _, plugin := range app.plugins {
rel, err := filepath.Rel(pluginDirectory, plugin.Command)
if err != nil {
log.Println("incoming URL: rel for this failed", err)
continue
}
if rel == incomingURL.Params.Get("path") {
plugin.TriggerRefresh()
return
}
}
case "refreshAllPlugins":
app.RefreshAll()
default:
log.Printf("incoming URL: skipping, unknown action %q\n", incomingURL.Action)
}
}
// onRefresh is fired when a plugin needs to refresh.
func (app *app) onRefresh(ctx context.Context, p *plugins.Plugin, _ error) {
app.lock.Lock()
defer app.lock.Unlock()
if app.menuIsOpen {
// don't update while the menu is open
// as this can cause a crash
return
}
tray, ok := app.pluginTrays[p.Command]
if !ok {
log.Println("no item - probably refreshing", tray.Label)
return
}
app.updateLabel(tray, p)
pluginMenu := app.menuParser.ParseItems(ctx, p.Items.ExpandedItems)
if pluginMenu == nil {
pluginMenu = app.newXbarMenu(p, false)
} else {
pluginMenu.Append(menu.Separator())
pluginMenu.Merge(app.newXbarMenu(p, true))
}
tray.Menu = pluginMenu
app.runtime.Menu.SetTrayMenu(tray)
}
func (app *app) onCycle(_ context.Context, p *plugins.Plugin) {
app.lock.Lock()
defer app.lock.Unlock()
if app.menuIsOpen {
// don't update while the menu is open
// as this can cause a crash
return
}
tray, ok := app.pluginTrays[p.Command]
if !ok {
// no tray item - it's probably refreshing
// so we'll just skip silently.
return
}
if app.updateLabel(tray, p) {
app.runtime.Menu.UpdateTrayMenuLabel(tray)
}
}
// refreshMenus refreshes all tray menus to ensure they
// are in sync with the data, EG: checkbox sync
func (app *app) refreshMenus() {
app.onMenuWillOpen()
for _, tray := range app.pluginTrays {
app.runtime.Menu.SetTrayMenu(tray)
}
app.onMenuDidClose()
}
func (app *app) updateLabel(tray *menu.TrayMenu, p *plugins.Plugin) bool {
cycleItem := p.CurrentCycleItem()
if cycleItem == nil {
return false
}
tray.Label = cycleItem.DisplayText()
tray.Image = cycleItem.Params.Image
tray.FontName = cycleItem.Params.Font
tray.FontSize = cycleItem.Params.Size
tray.RGBA = cycleItem.Params.Color
tray.Disabled = cycleItem.Params.Disabled
if cycleItem.Params.TemplateImage != "" {
tray.Image = cycleItem.Params.TemplateImage
tray.MacTemplateImage = true
}
return true
}
// checkForUpdates looks to see if there's a newer version of xbar,
// downloads it and installs it.
// If passive is true, it won't complain if it fails.
func (app *app) checkForUpdates(passive bool) {
if app.Verbose {
log.Printf("checking for updates... (current: %s)", version)
log.Println("updates: passive", passive)
log.Println("updates: AutoUpdate", app.settings.AutoUpdate)
}
u := update.Updater{
CurrentVersion: version,
//LatestReleaseGitHubEndpoint: "https://api.github.com/repos/matryer/xbar/releases/latest",
LatestReleaseGitHubEndpoint: "https://api.github.com/repos/matryer/xbar/releases/latest",
Client: &http.Client{Timeout: 10 * time.Minute},
SelectAsset: func(release update.Release, asset update.Asset) bool {
// look for the zip file
return filepath.Ext(asset.Name) == ".zip"
},
DownloadBytesLimit: 10_741_824, // 10MB
}
latest, hasUpdate, err := u.HasUpdate()
if err != nil {
if app.Verbose {
log.Println("failed to check for updates:", err)
}
if !passive {
_, err := app.runtime.Dialog.Message(&dialog.MessageDialog{
Type: dialog.ErrorDialog,
Title: "Update check failed",
Message: err.Error(),
Buttons: []string{"OK"},
CancelButton: "OK",
})
if err != nil {
log.Println(err)
return
}
}
return
}
if !hasUpdate {
// they are using the latest version
if app.Verbose {
log.Println("update: you have the latest version")
}
if !passive {
_, err := app.runtime.Dialog.Message(&dialog.MessageDialog{
Type: dialog.InfoDialog,
Title: "You're up to date",
Message: fmt.Sprintf("%s is the latest version.", latest.TagName),
Buttons: []string{"OK"},
CancelButton: "OK",
})
if err != nil {
log.Println(err)
return
}
}
return
}
if !app.settings.AutoUpdate {
oneWeek := 168 * time.Hour
// if this check is passive, and the release is only a few days
// old - do a soft prompt.
if passive && latest.CreatedAt.After(time.Now().Add(0-oneWeek)) {
// Update menu text
app.appUpdatesMenu.Label = "Install " + latest.TagName + "…"
app.refreshMenus()
return
}
response, err := app.runtime.Dialog.Message(&dialog.MessageDialog{
Type: dialog.QuestionDialog,
Title: "Update xbar?",
Message: fmt.Sprintf("xbar %s is now available (you have %s).\n\nWould you like to update?", latest.TagName, u.CurrentVersion),
Buttons: []string{"Update", "Later"},
DefaultButton: "Update",
CancelButton: "Later",
})
if err != nil {
log.Println(err)
return
}
switch response {
case "Update":
// continue
case "Later":
return
}
} else {
if app.Verbose {
log.Println("autoupdating...")
}
}
_, err = u.Update()
if err != nil {
if app.Verbose {
log.Println("failed to update:", err)
}
if !passive {
_, err := app.runtime.Dialog.Message(&dialog.MessageDialog{
Type: dialog.InfoDialog,
Title: "Update successful",
Message: "Please restart xbar for the changes to take effect.",
Buttons: []string{"OK"},
CancelButton: "OK",
})
if err != nil {
log.Println(err)
return
}
}
return
}
err = u.Restart()
if err != nil {
if app.Verbose {
log.Println("failed to restart:", err)
}
if !passive {
_, err := app.runtime.Dialog.Message(&dialog.MessageDialog{
Type: dialog.InfoDialog,
Title: "Update successful",
Message: "Please restart xbar for the changes to take effect.",
Buttons: []string{"OK"},
CancelButton: "OK",
})
if err != nil {
log.Println(err)
return
}
}
return
}
}
// tickOS waits a beat after some os changes to give the system
// time to reflect those changes.
func tickOS() {
time.Sleep(500 * time.Millisecond)
}
// setDarkMode sets the current dark mode state.
// It updates app.isDarkMode and also sets the
// appropriate environment variables.
func (app *app) setDarkMode(darkmode bool) {
app.lock.Lock()
defer app.lock.Unlock()
app.isDarkMode = darkmode
var err error
if darkmode {
err = os.Setenv("BitBarDarkMode", "true") // backwards compatibility
if err != nil {
log.Println("os.Setenv", err)
}
err = os.Setenv("XBARDarkMode", "true")
if err != nil {
log.Println("os.Setenv", err)
}
} else {
err = os.Setenv("BitBarDarkMode", "false") // backwards compatibility
if err != nil {
log.Println("os.Setenv", err)
}
err = os.Setenv("XBARDarkMode", "false")
if err != nil {
log.Println("os.Setenv", err)
}
}
}
================================================
FILE: app/build.sh
================================================
#!/bin/bash
set -e
VERSION=`git describe --tags`
echo ""
echo " xbar ${VERSION}..."
echo ""
echo -n $VERSION > .version
wails build -o xbar
================================================
FILE: app/categories_service.go
================================================
package main
import (
"context"
"encoding/json"
"io/ioutil"
"net/http"
)
// Category represents a group of plugins.
type Category struct {
Path string `json:"path"`
Text string `json:"text"`
Children []Category `json:"children"`
CategoryPathSegments []PathItem `json:"categoryPathSegments"`
}
// PathItem is a path segment.
type PathItem struct {
Path string `json:"path"`
Text string `json:"text"`
IsLast bool `json:"isLast"`
}
// CategoriesService access category information.
type CategoriesService struct {
baseURL string
client *http.Client
}
// NewCategoriesService makes a new CategoriesService.
func NewCategoriesService(client *http.Client) *CategoriesService {
return &CategoriesService{
baseURL: "https://xbarapp.com/docs",
client: client,
}
}
// GetCategories gets the categories from the remote server.
func (c *CategoriesService) GetCategories() ([]Category, error) {
req, err := http.NewRequest("GET", c.baseURL+"/plugins/categories.json", nil)
if err != nil {
return nil, err
}
ctx, cancel := context.WithTimeout(req.Context(), apiRequestTimeout)
defer cancel()
req = req.WithContext(ctx)
res, err := c.client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
var payload struct {
Categories []Category `json:"categories"`
}
err = json.Unmarshal(body, &payload)
if err != nil {
return nil, err
}
return payload.Categories, nil
}
================================================
FILE: app/categories_service_test.go
================================================
package main
import (
"net/http"
"testing"
"time"
"github.com/matryer/is"
)
func TestCategoryRepositoryGetCategories(t *testing.T) {
is := is.New(t)
cr := NewCategoriesService(&http.Client{Timeout: 1 * time.Second})
cats, err := cr.GetCategories()
is.NoErr(err)
is.True(len(cats) > 0)
cr.baseURL = "broken"
cats, err = cr.GetCategories()
is.True(err != nil)
is.True(cats == nil)
}
================================================
FILE: app/command_service.go
================================================
package main
import (
"os"
"os/exec"
"path/filepath"
"syscall"
"github.com/pkg/errors"
wails "github.com/wailsapp/wails/v2"
)
// CommandService provides window service.
type CommandService struct {
runtime *wails.Runtime
OnRefresh func()
clearCache func(passive bool)
}
// NewCommandService makes a new CommandService.
func NewCommandService(OnRefresh func()) *CommandService {
return &CommandService{
OnRefresh: OnRefresh,
}
}
// ClearCache clears the cache.
func (c *CommandService) ClearCache() {
c.clearCache(false)
}
// RefreshAllPlugins refreshes all plugins.
func (c *CommandService) RefreshAllPlugins() {
c.OnRefresh()
}
// WindowHide hides the window.
func (c *CommandService) WindowHide() {
c.runtime.Window.Hide()
}
// WindowMinimise minimises the window.
func (c *CommandService) WindowMinimise() {
c.runtime.Window.Minimise()
}
// OpenPath opens a window.
func (c CommandService) OpenPath(path string) error {
err := c.runCommand("open", path)
if err != nil {
return errors.Wrapf(err, "unable to open path %q", path)
}
return nil
}
// OpenURL opens a window.
func (c CommandService) OpenURL(url string) error {
err := c.runCommand("open", url)
if err != nil {
return errors.Wrapf(err, "unable to open URL %s", url)
}
return nil
}
// OpenFile opens a file for editing.
func (c CommandService) OpenFile(path string) error {
err := c.runCommand("open", filepath.Join(pluginDirectory, path))
if err != nil {
return errors.Wrapf(err, "failed to open %q", path)
}
return nil
}
// runCommand runs the command, wiring up stdout and stderr, and
// inheriting the environment.
func (CommandService) runCommand(name string, args ...string) error {
cmd := exec.Command(name, args...)
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
cmd.Env = os.Environ()
return cmd.Run()
}
================================================
FILE: app/frontend/.gitignore
================================================
/node_modules/
/public/build/
.DS_Store
/public/bundle.js.map
/public/bundle.js
/public/bundle.css
================================================
FILE: app/frontend/package.json
================================================
{
"name": "xbar",
"version": "1.0.0",
"scripts": {
"build": "rollup -c",
"dev": "rollup -c -w",
"start": "sirv public",
"start:dev": "sirv public --single --host 0.0.0.0 --dev"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^11.0.0",
"@rollup/plugin-image": "^2.0.6",
"@rollup/plugin-node-resolve": "^7.0.0",
"@rollup/plugin-url": "^5.0.1",
"@wails/runtime": "^1.3.10",
"autoprefixer": "^10.4.14",
"focus-visible": "^5.2.0",
"highlight.js": ">=10.4.1",
"postcss": "^8.4.21",
"postcss-import": "^15.1.0",
"rollup": "^2.35.1",
"rollup-plugin-livereload": "^1.0.0",
"rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-string": "^3.0.0",
"rollup-plugin-svelte": "~6.1.1",
"rollup-plugin-terser": "^5.1.2",
"sirv-cli": "^0.4.4",
"svelte": "^3.32.2",
"svelte-highlight": "^0.6.2",
"svelte-preprocess": "^4.6.1",
"tailwindcss": "^3.3.1"
},
"dependencies": {
"svelte-hash-router": "^1.0.1"
}
}
================================================
FILE: app/frontend/postcss.config.js
================================================
module.exports = {
plugins: [
require('postcss-import'),
require('tailwindcss'),
require('autoprefixer'),
],
}
================================================
FILE: app/frontend/public/index.html
================================================
xbar
xbar requires JavaScript to run correctly
================================================
FILE: app/frontend/rollup.config.js
================================================
import svelte from 'rollup-plugin-svelte'
import resolve from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import livereload from 'rollup-plugin-livereload'
import { terser } from 'rollup-plugin-terser'
import postcss from 'rollup-plugin-postcss'
import autoPreprocess from 'svelte-preprocess'
import image from '@rollup/plugin-image'
import { string } from 'rollup-plugin-string'
import url from '@rollup/plugin-url'
const production = !process.env.ROLLUP_WATCH;
export default {
input: 'src/main.js',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/bundle.js'
},
onwarn: handleRollupWarning,
plugins: [
image(),
// Embed binary files
url({
include: ['**/*.woff', '**/*.woff2'],
limit: Infinity,
}),
// Embed text files
string({
include: ["**/*.jsx", "**/*.go", "**/*.txt"],
}),
svelte({
preprocess: autoPreprocess(),
// enable run-time checks when not in production
dev: !production,
// we'll extract any component CSS out into
// a separate file - better for performance
// css: css => {
// css.write('bundle.css');
// },
emitCss: true,
}),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration -
// consult the documentation for details:
// https://github.com/rollup/plugins/tree/master/packages/commonjs
resolve({
browser: true,
dedupe: ['svelte']
}),
commonjs(),
// PostCSS preprocessing
postcss({
extensions: ['.css', '.scss'],
extract: true,
minimize: false,
use: [
['sass', {
includePaths: [
'./src/theme',
'./node_modules'
]
}]
],
}),
// In dev mode, call `npm run start` once
// the bundle has been generated
!production && serve(),
// Watch the `public` directory and refresh the
// browser on changes when not in production
!production && livereload('public'),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser()
],
watch: {
clearScreen: false
}
};
function handleRollupWarning(warning) {
console.error('ERROR: ' + warning.toString());
}
function serve() {
let started = false;
return {
writeBundle() {
if (!started) {
started = true;
require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
stdio: ['ignore', 'inherit', 'inherit'],
shell: true
});
}
}
};
}
================================================
FILE: app/frontend/src/App.svelte
================================================
================================================
FILE: app/frontend/src/Homepage.svelte
================================================
Featured plugins
================================================
FILE: app/frontend/src/InstalledPluginView.svelte
================================================
{#if !err}
{#if installedPlugin}
{installedPlugin.title || installedPlugin.filename}
{/if}
{#if refreshInterval}
Refresh every:
{/if}
{#if installedPlugin && installedPlugin.imageURL}
{/if}
{#if installedPlugin}
Open issue…
Uninstall this plugin
{/if}
{#if installedPlugin && installedPlugin.vars && installedPlugin.enabled}
{/if}
{#if installedPlugin}
{/if}
{/if}
================================================
FILE: app/frontend/src/PersonView.svelte
================================================
Contributors
﹥
@{personDetails ? personDetails.person.githubUsername : ''}
{#if personDetails}
{#if personDetails.person.githubUsername != personDetails.person.name}
{personDetails.person.name}
{/if}
@{personDetails.person.githubUsername}
{#if personDetails.person.bio}
{personDetails.person.bio}
{/if}
View on GitHub
{/if}
================================================
FILE: app/frontend/src/PluginView.svelte
================================================
{plugin ? plugin.filename : ''}
{#if plugin}
install(plugin)}
>
Install
{#if plugin.imageURL}
{/if}
{/if}
================================================
FILE: app/frontend/src/PluginsList.svelte
================================================
{category ? category.text : ''}
================================================
FILE: app/frontend/src/backend/index.js
================================================
// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
const backend = {
"main": {
"CategoriesService": {
/**
* GetCategories
* @returns {Promise|Error>} - Go Type: []main.Category
*/
"GetCategories": () => {
return window.backend.main.CategoriesService.GetCategories();
},
}
"CommandService": {
/**
* ClearCache
* @returns {Promise}
*/
"ClearCache": () => {
return window.backend.main.CommandService.ClearCache();
},
/**
* OpenFile
* @param {string} arg1 - Go Type: string
* @returns {Promise} - Go Type: error
*/
"OpenFile": (arg1) => {
return window.backend.main.CommandService.OpenFile(arg1);
},
/**
* OpenPath
* @param {string} arg1 - Go Type: string
* @returns {Promise} - Go Type: error
*/
"OpenPath": (arg1) => {
return window.backend.main.CommandService.OpenPath(arg1);
},
/**
* OpenURL
* @param {string} arg1 - Go Type: string
* @returns {Promise} - Go Type: error
*/
"OpenURL": (arg1) => {
return window.backend.main.CommandService.OpenURL(arg1);
},
/**
* RefreshAllPlugins
* @returns {Promise}
*/
"RefreshAllPlugins": () => {
return window.backend.main.CommandService.RefreshAllPlugins();
},
/**
* WindowHide
* @returns {Promise}
*/
"WindowHide": () => {
return window.backend.main.CommandService.WindowHide();
},
/**
* WindowMinimise
* @returns {Promise}
*/
"WindowMinimise": () => {
return window.backend.main.CommandService.WindowMinimise();
},
}
"PersonService": {
/**
* GetPersonDetails
* @param {string} arg1 - Go Type: string
* @returns {Promise} - Go Type: *main.PersonDetails
*/
"GetPersonDetails": (arg1) => {
return window.backend.main.PersonService.GetPersonDetails(arg1);
},
}
"PluginsService": {
/**
* GetFeaturedPlugins
* @returns {Promise|Error>} - Go Type: []metadata.Plugin
*/
"GetFeaturedPlugins": () => {
return window.backend.main.PluginsService.GetFeaturedPlugins();
},
/**
* GetInstalledPluginMetadata
* @param {string} arg1 - Go Type: string
* @returns {Promise} - Go Type: *main.InstalledPluginMetadata
*/
"GetInstalledPluginMetadata": (arg1) => {
return window.backend.main.PluginsService.GetInstalledPluginMetadata(arg1);
},
/**
* GetInstalledPlugins
* @returns {Promise|Error>} - Go Type: []plugins.InstalledPlugin
*/
"GetInstalledPlugins": () => {
return window.backend.main.PluginsService.GetInstalledPlugins();
},
/**
* GetPlugin
* @param {string} arg1 - Go Type: string
* @returns {Promise} - Go Type: *metadata.Plugin
*/
"GetPlugin": (arg1) => {
return window.backend.main.PluginsService.GetPlugin(arg1);
},
/**
* GetPlugins
* @param {string} arg1 - Go Type: string
* @returns {Promise|Error>} - Go Type: []metadata.Plugin
*/
"GetPlugins": (arg1) => {
return window.backend.main.PluginsService.GetPlugins(arg1);
},
/**
* InstallPlugin
* @param {any} arg1 - Go Type: metadata.Plugin
* @returns {Promise} - Go Type: string
*/
"InstallPlugin": (arg1) => {
return window.backend.main.PluginsService.InstallPlugin(arg1);
},
/**
* LoadVariableValues
* @param {string} arg1 - Go Type: string
* @returns {Promise} - Go Type: map[string]interface {}
*/
"LoadVariableValues": (arg1) => {
return window.backend.main.PluginsService.LoadVariableValues(arg1);
},
/**
* SaveVariableValues
* @param {string} arg1 - Go Type: string
* @param {any} arg2 - Go Type: map[string]interface {}
* @returns {Promise} - Go Type: error
*/
"SaveVariableValues": (arg1, arg2) => {
return window.backend.main.PluginsService.SaveVariableValues(arg1, arg2);
},
/**
* SetEnabled
* @param {string} arg1 - Go Type: string
* @param {boolean} arg2 - Go Type: bool
* @returns {Promise} - Go Type: string
*/
"SetEnabled": (arg1, arg2) => {
return window.backend.main.PluginsService.SetEnabled(arg1, arg2);
},
/**
* SetRefreshInterval
* @param {string} arg1 - Go Type: string
* @param {any} arg2 - Go Type: plugins.RefreshInterval
* @returns {Promise} - Go Type: *main.SetRefreshIntervalResult
*/
"SetRefreshInterval": (arg1, arg2) => {
return window.backend.main.PluginsService.SetRefreshInterval(arg1, arg2);
},
/**
* UninstallPlugin
* @param {any} arg1 - Go Type: main.UninstallPluginRequest
* @returns {Promise} - Go Type: bool
*/
"UninstallPlugin": (arg1) => {
return window.backend.main.PluginsService.UninstallPlugin(arg1);
},
}
}
};
export default backend;
================================================
FILE: app/frontend/src/backend/package.json
================================================
{
"name": "backend",
"version": "1.0.0",
"description": "Package to wrap backend method calls",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
================================================
FILE: app/frontend/src/elements/A.svelte
================================================
================================================
FILE: app/frontend/src/elements/Breadcrumbs.svelte
================================================
================================================
FILE: app/frontend/src/elements/Button.svelte
================================================
================================================
FILE: app/frontend/src/elements/Duration.svelte
================================================
{#if value.unit == 'milliseconds'}
ms
{:else}
seconds
minutes
hours
days
{/if}
================================================
FILE: app/frontend/src/elements/Error.svelte
================================================
{#if err}
{#if isNotFoundError(err)}
404 Not found
{#if refreshing}Refreshing…{:else}Refresh{/if}
← Use the navigation to
find your way back.
{:else}
{/if}
{/if}
================================================
FILE: app/frontend/src/elements/KeyboardShortcuts.svelte
================================================
================================================
FILE: app/frontend/src/elements/PluginCollection.svelte
================================================
{#if plugins}
{#each plugins as plugin}
{#if plugin.imageURL}
{/if}
{plugin.desc}
{#if plugin.authors && plugin.authors.length}
{/if}
{/each}
{/if}
================================================
FILE: app/frontend/src/elements/PluginDetails.svelte
================================================
{#if plugin}
{#if $$slots.action}
{plugin.title || plugin.filename}
{:else}
{plugin.title || plugin.filename}
{/if}
by
{#if plugin.authors}
{#each plugin.authors as author}
{author.name || author.githubUsername}
{#if author.githubUsername}
gotoPerson(author.githubUsername)}>
@{author.githubUsername}
{/if}
{/each}
{:else}
Anon.
{/if}
{#if $$slots.footer}
{/if}
{/if}
================================================
FILE: app/frontend/src/elements/PluginSourceBrowser.svelte
================================================
{#if files && files.length > 0}
{#each files as file}
Source code
{#if showEditButton}
editFile(file) }
>Open in external editor
{/if}
{file.content}
{/each}
{/if}
================================================
FILE: app/frontend/src/elements/Spinner.svelte
================================================
================================================
FILE: app/frontend/src/elements/Switch.svelte
================================================
================================================
FILE: app/frontend/src/elements/VariableInput.svelte
================================================
{#if variable}
{#if variable.type === 'string'}
{:else if variable.type === 'boolean'}
{#if values[variable.name]}
TRUE
{:else}
FALSE
{/if}
{:else if variable.type === 'number'}
{:else if variable.type === 'select'}
{#each variable.options as option}
{option}
{/each}
{/if}
{/if}
================================================
FILE: app/frontend/src/elements/Variables.svelte
================================================
{#if variables && variables.length && values}
{#each variables as variable}
{variable.label}
{variable.desc}
{/each}
💡 You must refresh the plugin for changes to take effect.
{/if}
================================================
FILE: app/frontend/src/main.js
================================================
import App from './App.svelte'
import { ready } from '@wails/runtime'
import { routes } from 'svelte-hash-router'
import Homepage from './Homepage.svelte'
import PluginsList from './PluginsList.svelte'
import PluginView from './PluginView.svelte'
import PeopleView from './PersonView.svelte'
import InstalledPluginView from './InstalledPluginView.svelte'
let app;
routes.set({
'/': Homepage,
'/plugins/*': PluginsList,
'/installed-plugins/*': InstalledPluginView,
'/plugin-details/*': PluginView,
'/people/:username': PeopleView,
})
ready(() => {
app = new App({
target: document.body,
});
});
export default app;
================================================
FILE: app/frontend/src/pagedata.svelte
================================================
================================================
FILE: app/frontend/src/rpc.svelte
================================================
================================================
FILE: app/frontend/src/signals.svelte
================================================
================================================
FILE: app/frontend/src/styles.css
================================================
@tailwind base;
@tailwind components;
@tailwind utilities;
* {
cursor: default !important;
}
html {
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";
-webkit-font-smoothing: subpixel-antialiased;
font-size: 13px;
}
@media (prefers-color-scheme: dark) {
html {
background-color: rgb(24,24,28,0.5);
}
}
html, body {
height: 100%;
width: 100%;
position: fixed;
overflow: hidden;
overscroll-behavior-y: none;
}
/* from https://css-tricks.com/snippets/css/prevent-long-urls-from-breaking-out-of-container/ */
.nice-wrapping {
/* These are technically the same, but use both */
overflow-wrap: break-word;
word-wrap: break-word;
-ms-word-break: break-all;
/* This is the dangerous one in WebKit, as it breaks things wherever */
word-break: break-all;
/* Instead use this non-standard one: */
word-break: break-word;
/* Adds a hyphen where the word breaks, if supported (No Blink) */
-ms-hyphens: auto;
-moz-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;
}
::-webkit-scrollbar-track
{
background: transparent;
border-radius: 2px;
padding: 2px;
padding-right: 10px;
}
::-webkit-scrollbar
{
width: 12px;
width: 6px;
background: transparent;
margin-right: 50px;
}
::-webkit-scrollbar-thumb
{
border-radius: 2px;
width: 6px;
background: rgba(160,160,160,0.5);
}
/* Credit: https://stackoverflow.com/a/4407335 */
.noselect {
cursor: default;
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently supported by Chrome, Edge, Opera and Firefox */
}
.allow-select {
-webkit-touch-callout: initial; /* iOS Safari */
-webkit-user-select: initial; /* Safari */
-khtml-user-select: initial; /* Konqueror HTML */
-moz-user-select: initial; /* Old versions of Firefox */
-ms-user-select: initial; /* Internet Explorer/Edge */
user-select: initial; /* Non-prefixed version, currently supported by Chrome, Edge, Opera and Firefox */
}
================================================
FILE: app/frontend/src/waiters.svelte
================================================
================================================
FILE: app/frontend/tailwind.config.js
================================================
const colors = require('tailwindcss/colors')
module.exports = {
purge: [
'./src/**/*.html',
'./src/**/*.js',
'./src/**/*.svelte',
],
theme: {
colors: {
transparent: 'transparent',
gray: colors.neutral,
blue: colors.blue,
black: colors.black,
white: colors.white,
yellow: colors.yellow,
},
},
plugins: [],
}
================================================
FILE: app/go.mod
================================================
module github.com/matryer/xbar/app
go 1.16
require (
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/uuid v1.2.0 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79
github.com/klauspost/compress v1.13.1 // indirect
github.com/leaanthony/go-ansi-parser v1.3.0
github.com/matryer/is v1.4.0
github.com/matryer/xbar/pkg/metadata v0.0.0-20210701102621-61a690f92a94
github.com/matryer/xbar/pkg/plugins v0.0.0-20210701102621-61a690f92a94
github.com/matryer/xbar/pkg/update v0.0.0-20210701102621-61a690f92a94
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
github.com/pkg/errors v0.9.1
github.com/wailsapp/wails/v2 v2.0.0-alpha.74
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
nhooyr.io/websocket v1.8.7 // indirect
)
replace github.com/matryer/xbar/pkg/plugins => ../pkg/plugins
replace github.com/matryer/xbar/pkg/metadata => ../pkg/metadata
replace github.com/matryer/xbar/pkg/update => ../pkg/update
//replace github.com/wailsapp/wails/v2 => ../../wails/v2
================================================
FILE: app/go.sum
================================================
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/frankban/quicktest v1.13.0 h1:yNZif1OkDfNoDfb9zZa9aXIpejNR4F23Wely0c+Qdqk=
github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
github.com/go-git/go-billy/v5 v5.1.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw=
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.13.1 h1:wXr2uRxZTJXHLly6qhJabee5JqIhTRoLBhDOA74hDEQ=
github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leaanthony/clir v1.0.4 h1:Dov2y9zWJmZr7CjaCe86lKa4b5CSxskGAt2yBkoDyiU=
github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
github.com/leaanthony/debme v1.1.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM=
github.com/leaanthony/go-ansi-parser v1.2.0/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU=
github.com/leaanthony/go-ansi-parser v1.3.0 h1:8CRGdyxf2/cCiBZmYqpFkeTGcsFswDcVeB2SZKYUnbo=
github.com/leaanthony/go-ansi-parser v1.3.0/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU=
github.com/leaanthony/go-common-file-dialog v1.0.3 h1:O0uGjKnWtdEADGrkg+TyAAbZylykMwwx/MNEXn9fp+Y=
github.com/leaanthony/go-common-file-dialog v1.0.3/go.mod h1:TGhEc9eSJgRsupZ+iH1ZgAOnEo9zp05cRH2j08RPrF0=
github.com/leaanthony/gosod v1.0.1/go.mod h1:W8RyeSFBXu7RpIxPGEJfW4moSyGGEjlJMLV25wEbAdU=
github.com/leaanthony/idgen v1.0.0 h1:IZreR+JGEzFV4yeVuBZA25gM0keUoFy+RDUldncQ+Jw=
github.com/leaanthony/idgen v1.0.0/go.mod h1:4nBZnt8ml/f/ic/EVQuLxuj817RccT2fyrUaZFxrcVA=
github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY=
github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
github.com/leaanthony/webview2runtime v1.1.0 h1:N0pv55ift8XtqozIp4PNOtRCJ/Qdd/qzx80lUpalS4c=
github.com/leaanthony/webview2runtime v1.1.0/go.mod h1:hH9GnWCve3DYzNaPOcPbhHQ7fodXR1QJNsnwixid4Tk=
github.com/leaanthony/winicon v0.0.0-20200606125418-4419cea822a0/go.mod h1:en5xhijl92aphrJdmRPlh4NI1L6wq3gEm0LpXAPghjU=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e h1:9MlwzLdW7QSDrhDjFlsEYmxpFyIoXmYRon3dt0io31k=
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mholt/archiver v3.1.1+incompatible h1:1dCVxuqs0dJseYEhi5pl7MYPH9zDa1wBi7mF09cbNkU=
github.com/mholt/archiver v3.1.1+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ=
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pierrec/lz4 v2.6.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=
github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tdewolff/minify v2.3.6+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT56Uf6o3Mcz9CEsg8USYs=
github.com/tdewolff/parse v2.3.4+incompatible/go.mod h1:8oBwCsVmUkgHO8M5iCzSIDtpzXOT0WXX9cWhz+bIzJQ=
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk=
github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/sjson v1.1.7/go.mod h1:w/yG+ezBeTdUxiKs5NcPicO9diP38nk96QBAbIIGeFs=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/wailsapp/wails/v2 v2.0.0-alpha.74 h1:h7K/gM2uR8HJQwb+VZYSTsbMqPz1O2Dx6jn9FFBA20o=
github.com/wailsapp/wails/v2 v2.0.0-alpha.74/go.mod h1:BFBtJpsnU9bMYfqhotj5wYn5EIGBXXJl5x+2ZT9UrKw=
github.com/wzshiming/ctc v1.2.3/go.mod h1:2tVAtIY7SUyraSk0JxvwmONNPFL4ARavPuEsg5+KA28=
github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae/go.mod h1:VTAq37rkGeV+WOybvZwjXiJOicICdpLCN8ifpISjK20=
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
github.com/xyproto/xpm v1.2.1/go.mod h1:cMnesLsD0PBXLgjDfTDEaKr8XyTFsnP1QycSqRw7BiY=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/ztrue/tracerr v0.3.0 h1:lDi6EgEYhPYPnKcjsYzmWw4EkFEoA/gfe+I9Y5f+h6Y=
github.com/ztrue/tracerr v0.3.0/go.mod h1:qEalzze4VN9O8tnhBXScfCrmoJo10o8TN5ciKjm6Mww=
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
================================================
FILE: app/incoming_urls.go
================================================
package main
import (
"net/url"
"strings"
"github.com/pkg/errors"
)
type incomingURL struct {
// Action is the action to take.
Action string
// Params are the parameters for the action.
Params url.Values
}
// parseIncomingURL parses an incoming xbar:// URL.
func parseIncomingURL(urlStr string) (incomingURL, error) {
var inURL incomingURL
u, err := url.Parse(urlStr)
if err != nil {
return inURL, err
}
if u.Scheme != "xbar" && u.Host != "app.xbarapp.com" {
return inURL, errors.New("not an xbar:// url")
}
inURL.Action = strings.Trim(u.Path, "/")
inURL.Params = u.Query()
switch inURL.Action {
case "openPlugin":
case "refreshPlugin":
case "refreshAllPlugins":
default: // not ok
return inURL, errors.Errorf("unsupported action %q", inURL.Action)
}
return inURL, nil
}
================================================
FILE: app/incoming_urls_test.go
================================================
package main
import (
"testing"
"github.com/matryer/is"
)
func TestParseIncomingURL(t *testing.T) {
is := is.New(t)
result, err := parseIncomingURL(`xbar://app.xbarapp.com/openPlugin?path=IoT/homebridge.10s.py`)
is.NoErr(err)
is.Equal(result.Action, "openPlugin")
is.Equal(result.Params.Get("path"), "IoT/homebridge.10s.py")
result, err = parseIncomingURL(`xbar://app.xbarapp.com/refreshPlugin?path=cycle_text_and_detail`)
is.NoErr(err)
is.Equal(result.Action, "refreshPlugin")
is.Equal(result.Params.Get("path"), "cycle_text_and_detail")
result, err = parseIncomingURL(`xbar://app.xbarapp.com/refreshAllPlugins`)
is.NoErr(err)
is.Equal(result.Action, "refreshAllPlugins")
result, err = parseIncomingURL(`xbar://app.xbarapp.com/nope?path=cycle_text_and_detail`)
is.True(err != nil)
}
================================================
FILE: app/main.go
================================================
package main
import (
_ "embed"
"fmt"
"os"
"github.com/pkg/errors"
"github.com/wailsapp/wails/v2"
"github.com/wailsapp/wails/v2/pkg/logger"
"github.com/wailsapp/wails/v2/pkg/options"
"github.com/wailsapp/wails/v2/pkg/options/mac"
)
//go:embed .version
var version string
func main() {
println("xbar", version)
if err := run(); err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
os.Exit(1)
}
println("xbar exited")
}
func run() error {
app, err := newApp()
if err != nil {
return errors.Wrap(err, "newApp")
}
wailsLogLevel := logger.ERROR
app.Verbose = true
if app.Verbose {
wailsLogLevel = logger.DEBUG
}
err = wails.Run(&options.App{
Title: "xbar",
Width: 1080,
Height: 700,
MinWidth: 800,
MinHeight: 600,
StartHidden: true,
HideWindowOnClose: true,
Mac: &mac.Options{
WebviewIsTransparent: true,
WindowBackgroundIsTranslucent: true,
TitleBar: mac.TitleBarHiddenInset(),
Menu: app.appMenu,
ActivationPolicy: mac.NSApplicationActivationPolicyAccessory,
URLHandlers: map[string]func(string){
// xbar://...
"xbar": app.handleIncomingURL,
},
},
ContextMenus: app.contextMenus,
LogLevel: wailsLogLevel,
Startup: app.Start,
Shutdown: app.Shutdown,
Bind: []interface{}{
app.PersonService,
app.CategoriesService,
app.PluginsService,
app.CommandService,
},
})
if err != nil {
return err
}
return nil
}
================================================
FILE: app/menu_parser.go
================================================
package main
import (
"context"
"fmt"
"strconv"
"github.com/leaanthony/go-ansi-parser"
"github.com/matryer/xbar/pkg/plugins"
"github.com/wailsapp/wails/v2/pkg/menu"
"github.com/wailsapp/wails/v2/pkg/menu/keys"
)
// MenuParser translates xbar items into Wails menu items.
type MenuParser struct{}
// NewMenuParser makes a new MenuParser.
func NewMenuParser() *MenuParser {
return &MenuParser{}
}
// ParseItems parses the items, returning the new menu.
func (m MenuParser) ParseItems(ctx context.Context, items []*plugins.Item) *menu.Menu {
if len(items) == 0 {
return nil
}
theMenu := menu.NewMenu()
for _, item := range items {
if item.Params.Separator {
theMenu.Append(menu.Separator())
continue
}
menuItem := m.ParseMenuItem(ctx, item)
theMenu.Append(menuItem)
if item.Alternate != nil {
menuItem = m.ParseMenuItem(ctx, item.Alternate)
theMenu.Append(menuItem)
}
}
return theMenu
}
// ParseMenuItem parses a single item, returning the new menu.
func (m MenuParser) ParseMenuItem(ctx context.Context, item *plugins.Item) *menu.MenuItem {
var err error
displayText := item.DisplayText()
itemAction := item.Action()
menuItem := menu.Text(displayText, nil, func(_ *menu.CallbackData) {
if itemAction == nil {
return
}
itemAction(ctx)
})
if item.Text != displayText {
tooltip := item.Text
if item.Params.ANSI {
tooltip, err = strconv.Unquote(`"` + tooltip + `"`)
if err != nil {
tooltip = item.Text
}
}
if ansi.HasEscapeCodes(tooltip) {
menuItem.Tooltip, err = ansi.Cleanse(tooltip)
if err != nil {
menuItem.Tooltip = err.Error()
}
} else {
menuItem.Tooltip = tooltip
}
}
if item.Params.Key != "" {
acc, err := keys.Parse(item.Params.Key)
if err != nil {
// show the error in the menu
menuItem.Label = fmt.Sprintf("error: %s", err)
}
menuItem.Accelerator = acc
}
menuItem.Image = item.Params.Image
menuItem.FontName = item.Params.Font
menuItem.FontSize = item.Params.Size
menuItem.RGBA = item.Params.Color
// Check for template image
if item.Params.TemplateImage != "" {
menuItem.Image = item.Params.TemplateImage
// get template images working on all macOS versions
menuItem.MacTemplateImage = true
}
menuItem.MacAlternate = item.Params.Alternate
if item.Params.Dropdown == false {
menuItem.Hidden = true
}
if len(item.Items) > 0 { // subitems
menuItem.SubMenu = m.ParseItems(ctx, item.Items)
}
if itemAction == nil && menuItem.SubMenu == nil {
// no action and no submenu, disable it.
menuItem.Disabled = true
}
if item.Params.Disabled {
// explicitly disabled
menuItem.Disabled = true
}
return menuItem
}
================================================
FILE: app/menu_parser_test.go
================================================
package main
import (
"context"
"encoding/json"
"testing"
"time"
"github.com/matryer/is"
"github.com/matryer/xbar/pkg/plugins"
"github.com/wailsapp/wails/v2/pkg/menu"
)
func TestMenuParser(t *testing.T) {
is := is.New(t)
ctx := context.Background()
ctx, cancel := context.WithTimeout(ctx, 1*time.Second)
defer cancel()
plugin := &plugins.Plugin{}
items := []*plugins.Item{
{
Plugin: plugin,
Text: "one",
Items: []*plugins.Item{
{Text: "sub1"},
{Text: "sub2"},
{Text: "sub3"},
},
},
{
Plugin: plugin,
Text: "two",
Params: plugins.ItemParams{
Font: "Courier New",
Size: 26,
Key: "CmdOrCtrl+Shift+K",
},
},
{
Plugin: plugin,
Text: "three",
},
{
Plugin: plugin,
Text: "four",
Params: plugins.ItemParams{
Href: "https://xbarapp.com",
},
},
{
Plugin: plugin,
Text: "five",
Params: plugins.ItemParams{
Shell: "echo",
ShellParams: []string{"hi"},
},
},
{
Plugin: plugin,
Text: "six",
Params: plugins.ItemParams{
Refresh: true,
},
},
{
Plugin: plugin,
Text: "seven but this will be truncated",
Params: plugins.ItemParams{
Refresh: true,
Length: 5,
},
},
{
Plugin: plugin,
Text: "Template Image",
Params: plugins.ItemParams{
TemplateImage: "base64stuff",
},
},
{
Plugin: plugin,
Text: "Non Alternate",
Alternate: &plugins.Item{
Text: "Alternate",
Params: plugins.ItemParams{
Alternate: true,
},
},
},
{
Text: "\033[0;38;2;255;0;0mA\033[0;38;2;255;127;0mN\033[0;38;2;255;255;0mS\033[0;38;2;0;255;0mI\u001B[0m",
Params: plugins.ItemParams{
Refresh: true,
},
},
}
menuitems := NewMenuParser().ParseItems(ctx, items)
is.Equal(len(menuitems.Items), 11) // len(menuitems.Items)
is.Equal(menuitems.Items[0].Label, "one")
is.Equal(menuitems.Items[0].Disabled, false)
is.True(menuitems.Items[0].SubMenu != nil)
is.Equal(len(menuitems.Items[0].SubMenu.Items), 3)
is.Equal(menuitems.Items[1].Label, "two")
is.Equal(menuitems.Items[1].Disabled, true)
is.Equal(menuitems.Items[1].FontName, "Courier New")
is.Equal(menuitems.Items[1].FontSize, 26)
is.True(menuitems.Items[1].Accelerator != nil)
is.Equal(menuitems.Items[1].Accelerator.Key, "k")
is.Equal(len(menuitems.Items[1].Accelerator.Modifiers), 2) // len(modifiers)
is.Equal(menuitems.Items[2].Label, "three")
is.Equal(menuitems.Items[2].Disabled, true)
is.Equal(menuitems.Items[3].Label, "four")
is.Equal(menuitems.Items[3].Disabled, false)
is.Equal(menuitems.Items[4].Label, "five")
is.Equal(menuitems.Items[4].Disabled, false)
is.Equal(menuitems.Items[5].Label, "six")
is.Equal(menuitems.Items[5].Disabled, false)
is.Equal(menuitems.Items[6].Label, "seve…")
is.Equal(menuitems.Items[6].Tooltip, "seven but this will be truncated")
is.Equal(menuitems.Items[7].Label, "Template Image")
is.Equal(menuitems.Items[7].Image, "base64stuff")
//is.Equal(menuitems.Items[7].MacTemplateImage, true)
is.Equal(menuitems.Items[8].Label, "Non Alternate")
is.Equal(menuitems.Items[9].Label, "Alternate")
is.Equal(menuitems.Items[9].MacAlternate, true)
is.Equal(menuitems.Items[10].Tooltip, "ANSI")
}
func JSON(menu *menu.Menu, is *is.I) string {
data, err := json.Marshal(menu)
is.NoErr(err)
return string(data)
}
================================================
FILE: app/package.json
================================================
{}
================================================
FILE: app/package.sh
================================================
#!/bin/bash
set -e
VERSION=`git describe --tags`
# usage:
# git tag -a v0.1.0 -m "release tag."
# git push origin v0.1.0
# ./build.sh
# functions
requeststatus() { # $1: requestUUID
requestUUID=${1?:"need a request UUID"}
req_status=$(xcrun altool --notarization-info "$requestUUID" \
--username "${AC_USERNAME}" \
--password "${AC_PASSWORD}" 2>&1 \
| awk -F ': ' '/Status:/ { print $2; }' )
echo "$req_status"
}
notarizefile() { # $1: path to file to notarize, $2: identifier
filepath=${1:?"need a filepath"}
identifier=${2:?"need an identifier"}
# upload file
echo "## uploading $filepath for notarization"
requestUUID=$(xcrun altool --notarize-app \
--primary-bundle-id "$identifier" \
--username "${AC_USERNAME}" \
--password "${AC_PASSWORD}" \
--asc-provider "${AC_PROVIDER}" \
--file "$filepath" 2>&1 \
| awk '/RequestUUID/ { print $NF; }')
echo "Notarization RequestUUID: $requestUUID"
if [[ $requestUUID == "" ]]; then
echo "could not upload for notarization"
exit 1
fi
# wait for status to be not "in progress" any more
request_status="in progress"
while [[ "$request_status" == "in progress" ]]; do
echo -n "waiting... "
sleep 10
request_status=$(requeststatus "$requestUUID")
echo "$request_status"
done
# print status information
xcrun altool --notarization-info "$requestUUID" \
--username "${AC_USERNAME}" \
--password "${AC_PASSWORD}"
echo
if [[ $request_status != "success" ]]; then
echo "## could not notarize $filepath"
exit 1
fi
}
echo ""
echo " xbar ${VERSION}..."
echo ""
echo -n $VERSION > .version
# run all tests
./test.sh
rm -rf ./build/bin
sed "s/0.0.0/${VERSION}/" ./build/darwin/Info.plist.src > ./build/darwin/Info.plist
#CGO_LDFLAGS=-mmacosx-version-min=10.13 wails build -package -production -platform darwin/amd64 -o xbar
#CGO_LDFLAGS=-mmacosx-version-min=10.13 wails build -package -production -platform darwin/arm64 -o xbar
CGO_LDFLAGS=-mmacosx-version-min=10.13 wails build -package -production -platform darwin/universal -o xbar
cd ./build/bin/
echo "Signing the binary..."
codesign -s "${XBAR_SIGNING_IDENTITY}" -o runtime -v "./xbar.app/Contents/MacOS/xbar"
echo "Creating DMG..."
create-dmg ./xbar.app --overwrite --identity="${XBAR_SIGNING_IDENTITY}" --dmg-title "Install xbar"
mv xbar*.dmg "xbar.${VERSION}.dmg"
#echo "TARing..."
#tar -czvf xbar.${VERSION}.tar.gz ./xbar.app
echo "Zipping..."
zip -r xbar.zip ./xbar.app
mv xbar.zip "xbar.${VERSION}.zip"
#xcrun notarytool submit "xbar.${VERSION}.zip" --keychain-profile "${AC_PASSWORD}" --wait
echo "Notorizing..."
notarizefile "xbar.${VERSION}.zip" "com.xbarapp.app"
notarizefile "xbar.${VERSION}.dmg" "com.xbarapp.app"
xcrun stapler staple "xbar.${VERSION}.dmg"
rm -rf ./build/bin/xbar.app
open .
================================================
FILE: app/person_service.go
================================================
package main
import (
"context"
"encoding/json"
"io/ioutil"
"net/http"
"github.com/matryer/xbar/pkg/metadata"
)
// PersonService provides people related functionality.
type PersonService struct {
baseURL string
Client *http.Client
}
// NewPersonService makes a new PersonService.
func NewPersonService(client *http.Client) *PersonService {
return &PersonService{
Client: client,
baseURL: "https://xbarapp.com/docs",
}
}
// PersonDetails are details relating to a human.
type PersonDetails struct {
Person *metadata.Person `json:"person"`
Plugins []metadata.Plugin `json:"plugins"`
}
// GetPersonDetails gets details about a human by their GitHub username.
func (p *PersonService) GetPersonDetails(githubUsername string) (*PersonDetails, error) {
req, err := http.NewRequest("GET", p.baseURL+"/contributors/"+githubUsername+".json", nil)
if err != nil {
return nil, err
}
ctx, cancel := context.WithTimeout(req.Context(), apiRequestTimeout)
defer cancel()
req = req.WithContext(ctx)
res, err := p.Client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
var payload *PersonDetails
err = json.Unmarshal(body, &payload)
if err != nil {
return nil, err
}
return payload, nil
}
================================================
FILE: app/plugins_service.go
================================================
package main
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"os"
"path/filepath"
"sync"
"time"
"github.com/matryer/xbar/pkg/metadata"
"github.com/matryer/xbar/pkg/plugins"
"github.com/pkg/errors"
wails "github.com/wailsapp/wails/v2"
"github.com/wailsapp/wails/v2/pkg/options/dialog"
)
// PluginsService access remote plugin information.
type PluginsService struct {
runtime *wails.Runtime
baseURL string
client *http.Client
// osLock is used whenever there are operating system changes,
// like renaming files. This prevents overlap and potentially strange
// state.
// todo: move this to a better place?
osLock sync.Mutex
// OnRefresh is called whenever the menus should
// be updated.
OnRefresh func()
}
// NewPluginsService makes a new PluginsService.
func NewPluginsService(client *http.Client, baseURL string) *PluginsService {
return &PluginsService{
baseURL: baseURL,
client: client,
}
}
// GetPlugins gets the plugins for the specified category.
func (p *PluginsService) GetPlugins(categoryPath string) ([]metadata.Plugin, error) {
req, err := http.NewRequest("GET", p.baseURL+categoryPath+"/plugins.json", nil)
if err != nil {
return nil, err
}
ctx, cancel := context.WithTimeout(req.Context(), apiRequestTimeout)
defer cancel()
req = req.WithContext(ctx)
res, err := p.client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
var payload struct {
Plugins []metadata.Plugin
}
err = json.Unmarshal(body, &payload)
if err != nil {
return nil, err
}
return payload.Plugins, nil
}
// GetPlugin gets the plugin metadata for a plugin.
func (p *PluginsService) GetPlugin(pluginPath string) (*metadata.Plugin, error) {
req, err := http.NewRequest("GET", p.baseURL+pluginPath+".json", nil)
if err != nil {
return nil, err
}
ctx, cancel := context.WithTimeout(req.Context(), apiRequestTimeout)
defer cancel()
req = req.WithContext(ctx)
res, err := p.client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
var payload struct {
Plugin *metadata.Plugin
}
err = json.Unmarshal(body, &payload)
if err != nil {
return nil, err
}
return payload.Plugin, nil
}
// GetFeaturedPlugins gets the featured plugins.
func (p *PluginsService) GetFeaturedPlugins() ([]metadata.Plugin, error) {
req, err := http.NewRequest("GET", p.baseURL+"featured-plugins.json", nil)
if err != nil {
return nil, err
}
ctx, cancel := context.WithTimeout(req.Context(), apiRequestTimeout)
defer cancel()
req = req.WithContext(ctx)
res, err := p.client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
var payload struct {
Plugins []metadata.Plugin
}
err = json.Unmarshal(body, &payload)
if err != nil {
return nil, err
}
return payload.Plugins, nil
}
// GetInstalledPlugins gets the installed plugins.
func (p *PluginsService) GetInstalledPlugins() ([]plugins.InstalledPlugin, error) {
p.osLock.Lock()
defer p.osLock.Unlock()
return plugins.GetInstalledPlugins(pluginDirectory)
}
// InstallPlugin installs the plugin described by the provided metadata.
func (p *PluginsService) InstallPlugin(plugin metadata.Plugin) (string, error) {
defer p.OnRefresh()
p.osLock.Lock()
defer p.osLock.Unlock()
if p.runtime != nil {
response, err := p.runtime.Dialog.Message(&dialog.MessageDialog{
Type: "Question",
Title: "Install plugin",
Message: fmt.Sprintf("Are you sure you want to install %s?", plugin.Title),
Buttons: []string{"Install", "Cancel"},
DefaultButton: "Install",
CancelButton: "Cancel",
})
if err != nil {
return "", err
}
switch response {
case "Install":
// continue
case "Cancel":
return "", nil
}
}
installer := &plugins.Installer{
Client: &http.Client{
Timeout: 1 * time.Minute,
},
PluginDir: pluginDirectory,
}
pluginPath := "https://xbarapp.com/docs/plugins/" + plugin.Path + ".json"
pluginPathURL, err := url.Parse(pluginPath)
if err != nil {
return "", errors.Wrapf(err, "parse URL: %s", pluginPath)
}
installedPluginPath, err := installer.Install(pluginPathURL)
if err != nil {
return "", errors.Wrap(err, "Install")
}
tickOS() // wait a beat
return installedPluginPath, nil
}
// UninstallPluginRequest is the object to send when uninstalling an
// installed plugin.
type UninstallPluginRequest struct {
Path string
Title string
}
// UninstallPlugin removes a plugin.
func (p *PluginsService) UninstallPlugin(installedPluginInfo UninstallPluginRequest) (bool, error) {
defer p.OnRefresh()
p.osLock.Lock()
defer p.osLock.Unlock()
if p.runtime != nil {
response, err := p.runtime.Dialog.Message(&dialog.MessageDialog{
Type: "Question",
Title: "Uninstall plugin",
Message: fmt.Sprintf("Are you sure you want to remove %s?\n\nThis cannot be undone.", installedPluginInfo.Title),
Buttons: []string{"Uninstall", "Cancel"},
DefaultButton: "Uninstall",
CancelButton: "Cancel",
})
if err != nil {
return false, err
}
switch response {
case "Uninstall":
// continue
case "Cancel":
return false, nil
}
}
installer := &plugins.Installer{
PluginDir: pluginDirectory,
}
err := installer.Uninstall(installedPluginInfo.Path)
if err != nil {
return false, errors.Wrap(err, "uninstall")
}
tickOS() // wait a beat
return true, nil
}
// InstalledPluginMetadata is the metadata extracted from an installed
// plugin.
type InstalledPluginMetadata struct {
Plugin metadata.Plugin `json:"plugin"`
Enabled bool `json:"enabled"`
RefreshInterval plugins.RefreshInterval `json:"refreshInterval"`
Error string `json:"error,omitempty"`
}
// GetInstalledPluginMetadata loads the plugin metadata from a plugin file.
func (p *PluginsService) GetInstalledPluginMetadata(installedPluginPath string) (*InstalledPluginMetadata, error) {
p.osLock.Lock()
defer p.osLock.Unlock()
filename := filepath.Base(installedPluginPath)
b, err := os.ReadFile(filepath.Join(pluginDirectory, installedPluginPath))
if err != nil {
return nil, err
}
md, err := metadata.Parse(metadata.DebugfNoop, filename, string(b))
if err != nil {
return nil, err
}
md.Path = installedPluginPath
response := &InstalledPluginMetadata{
Plugin: md,
Enabled: plugins.IsPluginEnabled(installedPluginPath),
}
response.RefreshInterval, err = plugins.ParseFilenameInterval(filename)
if err != nil {
response.Error = err.Error()
}
return response, nil
}
// LoadVariableValues loads the values for an installed plugin.
func (p *PluginsService) LoadVariableValues(installedPluginPath string) (map[string]interface{}, error) {
p.osLock.Lock()
defer p.osLock.Unlock()
defer tickOS() // wait a beat
return plugins.LoadVariableValues(pluginDirectory, installedPluginPath)
}
// SaveVariableValues saves the values for an installed plugin.
func (p *PluginsService) SaveVariableValues(installedPluginPath string, values map[string]interface{}) error {
p.osLock.Lock()
defer p.osLock.Unlock()
defer tickOS() // wait a beat
return plugins.SaveVariableValues(pluginDirectory, installedPluginPath, values)
}
// SetEnabled sets a plugin to enabled or disabled state, depending on the value of
// the enabled parameter.
func (p *PluginsService) SetEnabled(installedPluginPath string, enabled bool) (string, error) {
defer p.OnRefresh()
p.osLock.Lock()
defer p.osLock.Unlock()
newPath, err := plugins.SetEnabled(pluginDirectory, installedPluginPath, enabled)
if err != nil {
return "", err
}
tickOS() // wait a beat
return newPath, err
}
// SetRefreshIntervalResult is the refresh interval result returned from SetRefreshInterval.
type SetRefreshIntervalResult struct {
InstalledPluginPath string `json:"installedPluginPath"`
RefreshInterval plugins.RefreshInterval `json:"refreshInterval"`
}
// SetRefreshInterval updates the refresh interval for a plugin.
func (p *PluginsService) SetRefreshInterval(installedPluginPath string, refreshInterval plugins.RefreshInterval) (*SetRefreshIntervalResult, error) {
defer p.OnRefresh()
p.osLock.Lock()
defer p.osLock.Unlock()
newPath, newInterval, err := plugins.SetRefreshInterval(pluginDirectory, installedPluginPath, refreshInterval)
if err != nil {
return nil, err
}
result := &SetRefreshIntervalResult{
InstalledPluginPath: newPath,
RefreshInterval: newInterval,
}
tickOS() // wait a beat
return result, nil
}
================================================
FILE: app/settings.go
================================================
package main
import (
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
"sync"
"github.com/pkg/errors"
)
type settings struct {
sync.Mutex
path string `json:"-"`
// AutoUpdate indicates that xbar should automatically
// update itself.
AutoUpdate bool `json:"autoupdate"`
Terminal struct {
AppleScriptTemplate3 string `json:"appleScriptTemplate3"`
} `json:"terminal"`
}
func (s *settings) setDefaults() {
if s.Terminal.AppleScriptTemplate3 == "" {
s.Terminal.AppleScriptTemplate3 = `
set quotedScriptName to quoted form of "{{ .Command }}"
{{ if .Params }}
set commandLine to {{ .Vars }} & " " & quotedScriptName & " " & {{ .Params }}
{{ else }}
set commandLine to {{ .Vars }} & " " & quotedScriptName
{{ end }}
if application "Terminal" is running then
tell application "Terminal"
do script commandLine
activate
end tell
else
tell application "Terminal"
do script commandLine in window 1
activate
end tell
end if
`
}
}
func loadSettings(path string) (*settings, error) {
s := &settings{
path: path,
}
b, err := ioutil.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
// file not found - it's ok, just use defaults
s.setDefaults()
return s, nil
}
return nil, errors.Wrap(err, "ReadFile")
}
err = json.Unmarshal(b, s)
if err != nil {
return nil, errors.Wrap(err, "Unmarshal")
}
s.setDefaults()
return s, nil
}
func (s *settings) save() error {
s.Lock()
defer s.Unlock()
s.setDefaults()
b, err := json.MarshalIndent(s, "", "\t")
if err != nil {
return errors.Wrap(err, "MarshalIndent")
}
err = os.MkdirAll(filepath.Dir(s.path), 0777)
if err != nil {
return errors.Wrap(err, "MkdirAll")
}
err = ioutil.WriteFile(s.path, b, 0777)
if err != nil {
return errors.Wrap(err, "WriteFile")
}
return nil
}
================================================
FILE: app/settings_test.go
================================================
package main
import (
"os"
"path/filepath"
"testing"
"github.com/matryer/is"
)
func TestSettings(t *testing.T) {
is := is.New(t)
t.Cleanup(func() {
os.RemoveAll(filepath.Join("testdata", "settings.json"))
})
s, err := loadSettings(filepath.Join("testdata", "settings.json"))
is.NoErr(err)
s.AutoUpdate = true
err = s.save()
is.NoErr(err)
s, err = loadSettings(filepath.Join("testdata", "settings.json"))
is.NoErr(err)
is.Equal(s.AutoUpdate, true)
}
================================================
FILE: app/test.sh
================================================
#!/bin/bash
set -e
VERSION=`git describe --tags`
echo -n $VERSION > .version
go test
cd ../pkg/metadata
go test
cd ../../app
cd ../pkg/plugins
go test
cd ../../app
cd ../pkg/update
go test
cd ../../app
# cd ../tools/sitegen
# echo -n $VERSION > .version
# go test -short
# cd ../../app
================================================
FILE: app/wails.json
================================================
{
"name": "xbar",
"outputfilename": "xbar",
"html": "frontend/public/index.html",
"js": "frontend/public/bundle.js",
"css": "frontend/public/bundle.css",
"frontend:build": "npm run build",
"frontend:install": "npm install"
}
================================================
FILE: archive/bitbar/.gitignore
================================================
# xcode noise
build/*
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
profile
*.moved-aside
# osx noise
.DS_Store
profile
build
================================================
FILE: archive/bitbar/.gitmodules
================================================
[submodule "App/Vendor/STPrivilegedTask"]
path = App/Vendor/STPrivilegedTask
url = https://github.com/sveinbjornt/STPrivilegedTask.git
[submodule "App/Vendor/DateTools"]
path = App/Vendor/DateTools
url = https://github.com/MatthewYork/DateTools.git
[submodule "App/Vendor/LaunchAtLoginController"]
path = App/Vendor/LaunchAtLoginController
url = https://github.com/ksuther/LaunchAtLoginController--with-ARC-.git
[submodule "App/Vendor/AHProxySettings"]
path = App/Vendor/AHProxySettings
url = https://github.com/eahrold/AHProxySettings.git
[submodule "App/Vendor/NSStringEmojize"]
path = App/Vendor/NSStringEmojize
url = https://github.com/diy/NSStringEmojize.git
[submodule "App/Vendor/Sparkle"]
path = App/Vendor/Sparkle
url = https://github.com/sparkle-project/Sparkle.git
================================================
FILE: archive/bitbar/.travis.yml
================================================
language: objective-c
osx_image: xcode11.2
xcode_project: App/BitBar.xcodeproj
xcode_scheme: BitBar
xcode_sdk: macosx10.11
#before_install:
#- brew update
#- brew outdated xctool || brew upgrade xctool
script:
- CERT_P12=Certificate.p12
- echo "$CERT_BASE64" | base64 --decode > $CERT_P12
- KEYCHAIN=build.keychain
- security create-keychain -p travis $KEYCHAIN
- security default-keychain -s $KEYCHAIN
- security unlock-keychain -p travis $KEYCHAIN
- security set-keychain-settings -t 3600 -u $KEYCHAIN
- security import $CERT_P12 -k $KEYCHAIN -P "$CERT_PW" -T /usr/bin/codesign
- 'IDENTITY="Developer ID Application: Code and That Ltd (B3T8QSC4HG)"'
- if [ -n "$TRAVIS_TAG" ]; then xctool -project $TRAVIS_XCODE_PROJECT
-scheme $TRAVIS_XCODE_SCHEME -sdk $TRAVIS_XCODE_SDK -configuration Release OBJROOT=$PWD/build
SYMROOT=$PWD/build ONLY_ACTIVE_ARCH=NO CODE_SIGN_IDENTITY="$IDENTITY" build analyze; else xctool -project $TRAVIS_XCODE_PROJECT
-scheme $TRAVIS_XCODE_SCHEME -sdk $TRAVIS_XCODE_SDK -configuration Release OBJROOT=$PWD/build
SYMROOT=$PWD/build ONLY_ACTIVE_ARCH=NO build analyze -failOnWarnings; fi
- security delete-keychain $KEYCHAIN
before_deploy:
- OUTPUTDIR="$PWD/build/Release"
- cd $OUTPUTDIR
- ditto -c -k --sequesterRsrc --keepParent "BitBar.app" "BitBar-$TRAVIS_TAG.zip"
- ditto -c -k --sequesterRsrc --keepParent "BitBarDistro.app" "BitBarDistro-$TRAVIS_TAG.zip"
deploy:
provider: releases
api_key:
secure: VB7wqPRAmwRxX1ugTss4lWdcCjMO4+9yYuvkSKIhRz5PcKFTdgIE5Ol29wssYSlEnk1D5ZqeCJBe3t2qowrxOKHWKJRxH5r4fbgYAYnbk9/nWsMLgWDn1mo4nYa0sD4GyMUDY9JqqmtBY3nZ2pYcJ0L1LmxUU+EHViwcBQz6G4Y=
file:
- $OUTPUTDIR/BitBar-$TRAVIS_TAG.zip
- $OUTPUTDIR/BitBarDistro-$TRAVIS_TAG.zip
skip_cleanup: true
on:
repo: matryer/bitbar
tags: true
after_deploy:
# Rebuild the Sparkle feed
- curl -s -X POST -H "Authorization:token $GH_TOKEN" -H Accept:application/vnd.github.mister-fantastic-preview https://api.github.com/repos/matryer/bitbar/pages/builds
# Update the Sparkle feed cache
- brew install jq
- PRERELEASE=$(curl -s -H "Authorization:token $GH_TOKEN" "https://api.github.com/repos/matryer/bitbar/releases/tags/$TRAVIS_TAG" | jq .prerelease)
- echo "$PRERELEASE"
- if [ "$PRERELEASE" = true ]; then FEED=(beta distro-beta); else FEED=(bitbar distro); fi
- while :; do STATUS=$(curl -s -H "Authorization:token $GH_TOKEN" https://api.github.com/repos/matryer/bitbar/pages | jq .status); if [ "$STATUS" != '"queued"' ] && [ "$STATUS" != '"building"' ]; then echo "$STATUS"; break; fi; sleep 1; done
- curl -s -H "X-RELOAD-KEY:$SPARKLE_UPDATE_KEY" -D - -o /dev/null "https://bitbarapp.com/feeds/${FEED[0]}/reload"
- curl -s -H "X-RELOAD-KEY:$SPARKLE_UPDATE_KEY" -D - -o /dev/null "https://bitbarapp.com/feeds/${FEED[1]}/reload"
notifications:
slack:
secure: TpJVJf/NWxDvHxPjaQJnVg4vlW6JeLQ7eWadzFo7sUNSdB7Tui703AvYjG8tZTlk2lJ/4bV4jKgz8+rSElkeGsfPLTgDU33IDmG3V9o6MrAeV/ZQL37793bj+zJFxNuOkoIBaBQt1aNDTuIDUB97MNv02Vklb1M7Yd44NRVXdHk=
================================================
FILE: archive/bitbar/App/BitBar/App.xib
================================================
================================================
FILE: archive/bitbar/App/BitBar/AppDelegate.m
================================================
//
// AppDelegate.m
// BitBar
//
// Created by Mat Ryer on 11/12/13.
// Copyright (c) 2013 Bit Bar. All rights reserved.
//
#import "NSUserDefaults+Settings.h"
#import "LaunchAtLoginController.h"
#import "PluginManager.h"
#import "Plugin.h"
#import
#import
@interface AppDelegate : NSObject
@property (assign) IBOutlet NSWindow *window;
@property PluginManager *pluginManager;
// plugin download
@property NSURLDownload *download;
@property NSString *destinationPath;
@property NSString *suggestedDestinationPath;
@end
@implementation AppDelegate
- (NSArray*) otherCopies { return [NSRunningApplication runningApplicationsWithBundleIdentifier:NSBundle.mainBundle.bundleIdentifier]; }
- (void)applicationWillFinishLaunching:(NSNotification *)n {
NSString *feedURLString;
#ifdef DISTRO
feedURLString = @"https://bitbarapp.com/feeds/distro";
#else
feedURLString = @"https://bitbarapp.com/feeds/bitbar";
#endif
SUUpdater *updater = [SUUpdater sharedUpdater];
updater.delegate = self;
updater.automaticallyChecksForUpdates = YES;
updater.feedURL = [NSURL URLWithString:feedURLString];
updater.sendsSystemProfile = YES;
// register custom url scheme handler
[[NSAppleEventManager sharedAppleEventManager] setEventHandler:self
andSelector:@selector(handleGetURLEvent:withReplyEvent:)
forEventClass:kInternetEventClass
andEventID:kAEGetURL];
if (self.otherCopies.count <= 1) return;
NSModalResponse runm = [[NSAlert alertWithMessageText:[NSString stringWithFormat:@"Another copy of %@ is already running.", NSBundle.mainBundle.infoDictionary[(NSString *)kCFBundleNameKey]]
defaultButton:@"Quit" alternateButton:@"Kill others" otherButton:nil informativeTextWithFormat:@"Quit, or kill the other copy(ies)?"] runModal];
runm == 1 ? [NSApp terminate:nil] : ({
for ( NSRunningApplication *app in self.otherCopies)
if (app.processIdentifier != NSProcessInfo.processInfo.processIdentifier)
[app terminate];
});
}
- (void) applicationDidFinishLaunching:(NSNotification*)n {
// enable usage of Safari's WebInspector to debug HTML Plugins
[NSUserDefaults.standardUserDefaults setBool:YES forKey:@"WebKitDeveloperExtras"];
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self
selector: @selector(receiveWakeNote:)
name: NSWorkspaceDidWakeNotification object: NULL];
if (DEFS.isFirstTimeAppRun) {
LaunchAtLoginController *launcher = LaunchAtLoginController.new;
if (!launcher.launchAtLogin) [launcher setLaunchAtLogin:YES];
DEFS.isFirstTimeAppRun = NO;
}
NSString* pluginsDirectory = DEFS.pluginsDirectory;
// Test if we are running unit tests!
NSString* testBundlePath = [NSProcessInfo processInfo].environment[@"XCInjectBundle"];
if (testBundlePath && [testBundlePath hasSuffix:@".xctest"]) {
pluginsDirectory = [[[NSBundle bundleWithPath:testBundlePath] resourcePath] stringByAppendingPathComponent:@"TestPlugins"];
}
// make a plugin manager
[_pluginManager = [PluginManager.alloc initWithPluginPath:pluginsDirectory]
setupAllPlugins];
}
- (void) receiveWakeNote: (NSNotification*) note
{
[[self pluginManager] reset];
}
- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent {
// check if plugins directory is set
if (!DEFS.pluginsDirectory)
return;
// extract the url from the event and handle it
NSString *URLString = [event paramDescriptorForKeyword:keyDirectObject].stringValue;
URLString = [URLString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *prefix = @"bitbar://refreshPlugin?name=";
if ([URLString hasPrefix:prefix]) {
URLString = [URLString substringFromIndex:prefix.length];
NSArray *plugins = [self.pluginManager.plugins filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"name LIKE %@", URLString]];
[plugins makeObjectsPerformSelector:@selector(performRefreshNow) withObject:nil];
return;
}
// don't open plugins if user configuration is disabled
if (DEFS.userConfigDisabled)
return;
prefix = @"bitbar://openPlugin?";
// skip urls that don't begin with our prefix
if (![URLString hasPrefix:prefix])
return;
URLString = [URLString substringFromIndex:prefix.length];
prefix = @"title=";
NSString *title = nil;
if ([URLString hasPrefix:prefix]) {
URLString = [URLString substringFromIndex:prefix.length];
NSArray *components = [URLString componentsSeparatedByString:@"&"];
if (components.count < 2)
return;
title = components.firstObject;
URLString = [[components subarrayWithRange:NSMakeRange(1, components.count - 1)] componentsJoinedByString:@"&"];
}
prefix = @"src=";
if (![URLString hasPrefix:prefix])
return;
URLString = [URLString substringFromIndex:prefix.length];
BOOL trusted = NO;
// if the plugin is at our repository, only display the filename
if ([URLString hasPrefix:@"https://github.com/matryer/xbar-plugins/raw/master/"]) {
trusted = YES;
}
NSAlert *alert = [[NSAlert alloc] init];
[alert addButtonWithTitle:@"Install"];
[alert addButtonWithTitle:@"Cancel"];
alert.messageText = [NSString stringWithFormat:@"Download and install the plugin %@?", trusted ? (title.length > 0 ? title : URLString.lastPathComponent) : [NSString stringWithFormat:@"at %@", URLString]];
if (trusted) {
alert.informativeText = @"Only install plugins from trusted sources.";
} else {
alert.informativeText = @"CAUTION: This plugin is not from the official BitBar repository. We recommend that you only install plugins from trusted sources.";
}
if ([alert runModal] != NSAlertFirstButtonReturn) {
// cancel clicked
return;
}
[self.download cancel];
self.destinationPath = nil;
self.suggestedDestinationPath = nil;
// NSURLSession is not available below 10.9 :(
self.download = [[NSURLDownload alloc] initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:URLString]] delegate:self];
}
#pragma mark - NSURLDownload delegate
- (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename {
self.suggestedDestinationPath = [DEFS.pluginsDirectory stringByAppendingPathComponent:filename];
[download setDestination:self.suggestedDestinationPath allowOverwrite:NO];
}
- (void)download:(NSURLDownload *)download didCreateDestination:(NSString *)path {
self.destinationPath = path;
}
- (void)downloadDidFinish:(NSURLDownload *)download {
if (self.destinationPath) {
if (self.suggestedDestinationPath && ![self.suggestedDestinationPath isEqualToString:self.destinationPath]) {
// overwrite file at suggested destination path
[[NSFileManager defaultManager] removeItemAtPath:self.suggestedDestinationPath error:nil];
if ([[NSFileManager defaultManager] moveItemAtPath:self.destinationPath toPath:self.suggestedDestinationPath error:nil])
self.destinationPath = self.suggestedDestinationPath;
}
// ensure plugin is executable
// `chmod +x plugin.sh`
struct stat st;
stat(self.destinationPath.UTF8String, &st);
chmod(self.destinationPath.UTF8String, (st.st_mode & ALLPERMS) | S_IXUSR | S_IXGRP | S_IXOTH);
}
// refresh
[self.pluginManager reset];
self.download = nil;
self.destinationPath = nil;
self.suggestedDestinationPath = nil;
}
- (void)download:(NSURLDownload *)download didFailWithError:(NSError *)error {
NSAlert *alert = [[NSAlert alloc] init];
[alert addButtonWithTitle:@"OK"];
alert.messageText = @"Download failed";
alert.informativeText = error.localizedDescription;
[alert runModal];
self.download = nil;
self.destinationPath = nil;
self.suggestedDestinationPath = nil;
}
#pragma mark - SUUpdater delegate
// hack to disable the update prompt if user configuration is disabled
- (SUAppcastItem *)bestValidUpdateInAppcast:(SUAppcast *)appcast forUpdater:(SUUpdater *)updater {
id driver;
if (DEFS.userConfigDisabled || ((driver = [updater valueForKey:@"driver"]) && !driver)) return nil;
SEL sel = NSSelectorFromString(@"bestItemFromAppcastItems:getDeltaItem:withHostVersion:comparator:");
NSArray *items = appcast.items;
void *deltaUpdateItem = nil;
id version = [[driver valueForKey:@"host"] valueForKey:@"version"];
id comparator = [driver valueForKey:@"versionComparator"];
void *item = nil;
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[[driver class] methodSignatureForSelector:sel]];
inv.selector = sel;
inv.target = [driver class];
if (items) [inv setArgument:&items atIndex:2];
[inv setArgument:&deltaUpdateItem atIndex:3];
if (version) [inv setArgument:&version atIndex:4];
if (comparator) [inv setArgument:&comparator atIndex:5];
[inv invoke];
if (deltaUpdateItem) {
item = deltaUpdateItem;
} else {
[inv getReturnValue:&item];
}
return (__bridge SUAppcastItem *)item;
}
@end
int main(int argc, const char * argv[]) { return NSApplicationMain(argc, argv); }
================================================
FILE: archive/bitbar/App/BitBar/Base.lproj/MainMenu.xib
================================================
================================================
FILE: archive/bitbar/App/BitBar/BitBar-Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleExecutable
${EXECUTABLE_NAME}
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
${PRODUCT_NAME}
CFBundlePackageType
APPL
CFBundleShortVersionString
$(MARKETING_VERSION)
CFBundleSignature
????
CFBundleURLTypes
CFBundleTypeRole
Viewer
CFBundleURLSchemes
bitbar
CFBundleVersion
$(CURRENT_PROJECT_VERSION)
LSApplicationCategoryType
public.app-category.productivity
LSMinimumSystemVersion
${MACOSX_DEPLOYMENT_TARGET}
LSUIElement
NSHumanReadableCopyright
Copyright ©2013-2016 Mat Ryer. All rights reserved.
NSMainNibFile
App
NSPrincipalClass
NSApplication
================================================
FILE: archive/bitbar/App/BitBar/CHANGELOG.md
================================================
# BitBar Changes
## v1.9.2
* Added Sparkle updater
## v1.9.1
* Bug fixes and performance enhancements
## v1.9
* Restored distributable BitBar
* BitBar now requires OS X 10.7 to fix a crash on refresh and wake from sleep
* Added support for single click action from the status bar (`href`, `bash` and `refresh`)
* Added support for separators in sub menus
* Added update check (Preferences menu will show you when there's a newer version available)
* Various other bug fixes
## v1.8
* Added `emojize` parameter
* Added sub menus
* Added ANSI color code support and `ansi=false` option to turn it off
* Significant bug fixes and performance enhancements
## v1.7
* Added `image` and `templateImage` parameters (Base64 encoded images)
* Memory leak fixes and bug fixes
## v1.6
* Added [distributable BitBar](https://github.com/matryer/bitbar/blob/master/Docs/DistributingBitBar.md) to allow you to bundle a BitBar app with plugins, and distribute a tamper free version.
* Added ability to refresh plugins remotely via the [URL scheme](https://github.com/matryer/bitbar/blob/master/Docs/URLScheme.md) - #149 and #216
* Integration with Slack - please join us: [](https://getbitbar.herokuapp.com/)
* Added ability to [hide Preferences menu](https://github.com/matryer/bitbar/blob/master/Docs/DistributingBitBar.md#settings).
* Small UI improvements based on feedback from lovely users just like you
* Updated dependencies to fix crash and memory leak
* See a [complete list of all changes in this release](https://github.com/matryer/bitbar/compare/v1.5.1...master)
## v1.5
Features:
* Added `trim=false` option to give plugin authors control of whitespace - #182
* Added `alternate=true` option to allow option key menu items - #218
* Tasks now run in background (preventing menu bar items from locking) - #181
* Plugins will reset on wake from sleep - #184
* Added URL scheme for opening and downloading plugins - #224
Other:
* Work to address duplicate items - #21
* Updated "Browse plugins..." link to getbitbar.com
* Improved docs
* "Open at login" was getting reset every time - now it's remembered - #169
* Warnings and static analyzer errors are resolved
## v1.4
Features:
* Made `$BitBarDarkMode` environment variable available to plugins - #155
* Ability to hide items from the dropdown - #102
* Selecting a Plugin folder (rather than having to navigate inside it) is enough - better UI - #120
* `Reset` renamed to `Refresh` to make it clearer - #82
* `refresh` parameter indicates that an item should issue the refresh of a plugin - #48
* Added support for `length` parameter - #131
Other:
* Started tracking changes
* Fixed vertical alignment - #153
* Numbers are now monospace - #148
* Removed unnecessary separators from BitBar menu - #143
* General bug fixes and improvements
* Support spaces in paths
* Fonts will be checked, and a default will be used if they're not available
* Plugins now live in their own repo - #78
================================================
FILE: archive/bitbar/App/BitBar/ExecutablePlugin.h
================================================
//
// ExecutablePlugin.h
// BitBar
//
// Created by Mathias Leppich on 22/01/14.
// Copyright (c) 2014 Bit Bar. All rights reserved.
//
#import "Plugin.h"
@interface ExecutablePlugin : Plugin
@property (nonatomic, strong) NSTimer *lineCycleTimer;
@property (nonatomic, strong) NSTimer *refreshTimer;
- (BOOL) refreshContentByExecutingCommand;
@end
================================================
FILE: archive/bitbar/App/BitBar/ExecutablePlugin.m
================================================
//
// ExecutablePlugin.m
// BitBar
//
// Created by Mathias Leppich on 22/01/14.
// Copyright (c) 2014 Bit Bar. All rights reserved.
//
#import "ExecutablePlugin.h"
#import "PluginManager.h"
#import "NSTask+useSystemProxies.h"
#import "NSUserDefaults+Settings.h"
@implementation ExecutablePlugin
- (BOOL) refreshContentByExecutingCommand {
if (![[NSFileManager defaultManager] fileExistsAtPath:self.path]) {
return NO;
}
NSTask *task = NSTask.new;
[task setEnvironment:self.manager.environment];
[task setLaunchPath:self.path];
[task useSystemProxies];
NSPipe *stdoutPipe = [NSPipe pipe];
[task setStandardOutput:stdoutPipe];
NSPipe *stderrPipe = [NSPipe pipe];
[task setStandardError:stderrPipe];
@try {
[task launch];
} @catch (NSException *e) {
NSLog(@"Error when running %@: %@", self.name, e);
self.lastCommandWasError = YES;
self.content = @"";
self.errorContent = e.reason;
return NO;
}
NSData *stdoutData = [[stdoutPipe fileHandleForReading] readDataToEndOfFile];
NSData *stderrData = [[stderrPipe fileHandleForReading] readDataToEndOfFile];
[task waitUntilExit];
self.content = [NSString.alloc initWithData:stdoutData encoding:NSUTF8StringEncoding];
self.errorContent = [NSString.alloc initWithData:stderrData encoding:NSUTF8StringEncoding];
// failure
if ([task terminationStatus] != 0) {
self.lastCommandWasError = YES;
return NO;
}
// success
self.lastCommandWasError = NO;
return YES;
}
- (void)performRefreshNow {
self.content = @"Updating ...";
self.errorContent = @"";
[self rebuildMenuForStatusItem:self.statusItem];
self.currentLine = -1;
[self cycleLines];
[self.manager pluginDidUdpdateItself:self];
[self refresh];
}
-(BOOL)refresh {
__weak ExecutablePlugin *weakSelf = self;
[self.lineCycleTimer invalidate];
self.lineCycleTimer = nil;
[self.refreshTimer invalidate];
self.refreshTimer = nil;
// execute command
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
[weakSelf refreshContentByExecutingCommand];
dispatch_sync(dispatch_get_main_queue(), ^{
if (weakSelf) {
__strong ExecutablePlugin* strongSelf = weakSelf;
strongSelf.lastUpdated = NSDate.new;
[strongSelf rebuildMenuForStatusItem:strongSelf.statusItem];
// reset the current line
strongSelf.currentLine = -1;
// update the status item
[strongSelf cycleLines];
// sort out multi-line cycler
if (strongSelf.isMultiline) {
// start the timer to keep cycling lines
strongSelf.lineCycleTimer = [NSTimer scheduledTimerWithTimeInterval:strongSelf.cycleLinesIntervalSeconds target:strongSelf selector:@selector(cycleLines) userInfo:nil repeats:YES];
}
// tell the manager this plugin has updated
[strongSelf.manager pluginDidUdpdateItself:strongSelf];
// strongSelf next refresh
strongSelf.refreshTimer = [NSTimer scheduledTimerWithTimeInterval:[strongSelf.refreshIntervalSeconds doubleValue] target:strongSelf selector:@selector(refresh) userInfo:nil repeats:NO];
}
});
});
return YES;
}
- (void) close {
[self.lineCycleTimer invalidate];
self.lineCycleTimer = nil;
[self.refreshTimer invalidate];
self.refreshTimer = nil;
}
- (void) copyOutput {
NSString *valueToCopy = [self.allContentLines objectAtIndex:self.currentLine];
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
[pasteboard clearContents];
[pasteboard writeObjects:[NSArray arrayWithObject:valueToCopy]];
}
- (void) copyAllOutput {
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
[pasteboard clearContents];
[pasteboard writeObjects:[NSArray arrayWithObject:self.allContent]];
}
- (void) runPluginExternally {
NSString* script = @"tell application \"Terminal\" \n\
do script \"%@\" \n\
activate \n\
end tell";
NSString *s = [NSString stringWithFormat:
script, [self.path stringByReplacingOccurrencesOfString:@" " withString:@"\\\\ "]];
NSAppleScript *as = [NSAppleScript.alloc initWithSource:s];
[as executeAndReturnError:nil];
}
- (void) addAdditionalMenuItems:(NSMenu *)menu {
if (!DEFS.userConfigDisabled) {
NSMenuItem *runItem = [NSMenuItem.alloc initWithTitle:@"Run in Terminal…" action:@selector(runPluginExternally) keyEquivalent:@"o"];
[runItem setTarget:self];
[menu addItem:runItem];
}
}
@end
================================================
FILE: archive/bitbar/App/BitBar/HTMLPlugin.h
================================================
//
// HTMLPlugin.h
// BitBar
//
// Created by Mathias Leppich on 22/01/14.
// Copyright (c) 2014 Bit Bar. All rights reserved.
//
#import "Plugin.h"
@class WebView;
@interface HTMLPlugin : Plugin
@property (nonatomic, strong) NSTimer *autoReloadTimer;
@property (nonatomic, strong) WebView *webView;
@property (nonatomic, readonly) NSString * reloadInterval;
@property (nonatomic, strong) NSMenu * menu;
// callable from JavaScript
- (void) resizeToFit;
- (void) resetMenu;
- (void) addMenuItem:(NSObject*)titleOrParamsDict;
- (void) addMenuItems:(NSObject*)titleOrParamsDict;
- (void) addMenuSeperatorItem;
- (void) showMenu;
- (void) showWebInspector;
@end
================================================
FILE: archive/bitbar/App/BitBar/HTMLPlugin.m
================================================
//
// HTMLPlugin.m
// BitBar
//
// Created by Mathias Leppich on 22/01/14.
// Copyright (c) 2014 Bit Bar. All rights reserved.
//
#import "HTMLPlugin.h"
#import "PluginManager.h"
#import
@interface WebInspector : NSObject { WebView *_webView; }
- (id)initWithWebView:(WebView *)webView;
- (void)detach: (id)sender;
- (void)show: (id)sender;
- (void)showConsole:(id)sender;
@end
@implementation HTMLPlugin
-(BOOL)refresh {
if (![[NSFileManager defaultManager] fileExistsAtPath:self.path]) {
return NO;
}
NSLog(@" HTML File: %@", self.path);
self.content = @"HTML File";
self.currentLine = -1;
[self cycleLines];
[self.manager pluginDidUdpdateItself:self];
[self reinitAutoReloadTimer];
return YES;
}
-(void)reinitAutoReloadTimer {
[self.autoReloadTimer invalidate];
self.autoReloadTimer = [NSTimer scheduledTimerWithTimeInterval:[self.refreshIntervalSeconds doubleValue]
target:self
selector:@selector(reloadWebView)
userInfo:nil
repeats:YES];
}
-(void)reloadWebView {
NSLog(@"soft reload");
[self.webView reload:nil];
}
-(void)rebuildMenuForStatusItem:(NSStatusItem *)statusItem {
WebView * webview = [WebView.alloc initWithFrame:NSMakeRect(0, 0, 15, 15)];
self.webView = webview;
webview.frameLoadDelegate = (id)self;
webview.resourceLoadDelegate = (id)self;
webview.UIDelegate = (id)self;
webview.drawsBackground = NO;
webview.mainFrame.frameView.allowsScrolling = NO;
webview.shouldUpdateWhileOffscreen = YES;
webview.autoresizingMask = NSViewWidthSizable;
NSURL * url = [NSURL fileURLWithPath:self.path];
NSURLRequest * req = [NSURLRequest.alloc initWithURL:url];
[webview.mainFrame loadRequest:req];
statusItem.view = webview;
[self resetMenu];
}
- (void)resizeWebViewToFitContents {
WebView * webView = (WebView *)self.statusItem.view;
WebFrame * webFrame = [webView mainFrame];
//get the rect for the rendered frame
NSRect webFrameRect = [[[webFrame frameView] documentView] frame];
//get the rect of the current webview
NSRect webViewRect = [webView frame];
//calculate the new frame
NSRect newWebViewRect = NSMakeRect(webViewRect.origin.x,
webViewRect.origin.y,
webFrameRect.size.width,
webViewRect.size.height);
//set the frame
[webView setFrame:newWebViewRect];
NSLog(@"The dimensions of the page are: %@",NSStringFromRect(webFrameRect));
}
# pragma mark Delegate methods
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)webFrame
{
[self resizeWebViewToFitContents];
}
- (void)webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)windowObject forFrame:(WebFrame *)frame
{
// WebInspector * inspector = [WebInspector.alloc initWithWebView:sender];
// [inspector detach:sender];
// [inspector showConsole:sender];
NSLog(@"didClearWindowObject: windowObject: %@", windowObject);
WebScriptObject * script = [sender windowScriptObject];
NSLog(@"didClearWindowObject: script: %@", script);
[script setValue:self forKey:@"BitBar"];
[script evaluateWebScript:@"Object.isArray = function(a){ return a instanceof Array; }"];
}
- (void)webView:(WebView *)webView addMessageToConsole:(NSDictionary *)dictionary
{
NSLog(@"Error from webkit: %@", dictionary);
}
-(NSArray *)webView:(WebView *)sender contextMenuItemsForElement:(NSDictionary *)element defaultMenuItems:(NSArray *)defaultMenuItems {
// disable right-click menu in webview
return nil;
}
-(BOOL)webView:(WebView *)sender shouldChangeSelectedDOMRange:(DOMRange *)currentRange toDOMRange:(DOMRange *)proposedRange affinity:(NSSelectionAffinity)selectionAffinity stillSelecting:(BOOL)flag {
// disable text selection
return NO;
}
+ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector {
SEL allowed[] = {
@selector(log:),
@selector(setReloadInterval:),
@selector(resizeToFit),
@selector(showWebInspector),
@selector(resetMenu),
@selector(addMenuItem:),
@selector(addMenuItems:),
@selector(addMenuSeperatorItem),
@selector(showMenu)
};
for (int i=0; i<(sizeof allowed)/(sizeof allowed[0]); i++) {
if (allowed[i] == selector) {
NSLog(@"allow Selector: %@", NSStringFromSelector(selector));
return NO;
}
}
//NSLog(@"isSelectorExcludedFromWebScript: %@", NSStringFromSelector(selector));
return YES;
}
+(NSString *)webScriptNameForSelector:(SEL)selector {
return [NSStringFromSelector(selector) stringByReplacingOccurrencesOfString:@":" withString:@""];
}
+(BOOL)isKeyExcludedFromWebScript:(const char *)name {
NSArray * allowed = @[
@"reloadInterval"
];
if ([allowed containsObject:[NSString stringWithUTF8String:name]]) {
NSLog(@"isKeyExcludedFromWebScript: %@", [NSString stringWithUTF8String:name]);
return NO;
}
return YES;
}
#pragma mark - WebScriptObject Utils
- (NSArray*) arrayOfKeysFromWebScriptObject:(WebScriptObject *)obj {
WebScriptObject* bridge = [obj evaluateWebScript:@"Object"];
WebScriptObject* keysObj = [bridge callWebScriptMethod:@"keys" withArguments:@[obj]];
return [self arrayFromWebScriptObject:keysObj];
}
- (NSDictionary*) dictionaryFromWebScriptObject:(WebScriptObject *)obj {
NSArray * keys = [self arrayOfKeysFromWebScriptObject:obj];
NSMutableDictionary * dict = [NSMutableDictionary.alloc initWithCapacity:keys.count];
for (NSString * key in keys) {
NSObject * value = [obj valueForKey:key];
if ([[value class] isSubclassOfClass:[NSString class]] || [[value class] isSubclassOfClass:[NSNumber class]]) {
[dict setObject:value forKey:key];
}
}
return dict;
}
- (BOOL) isWebScriptObjectInstanceOfArray:(WebScriptObject *)obj {
WebScriptObject* bridge = [obj evaluateWebScript:@"Object"];
NSNumber * result = [bridge callWebScriptMethod:@"isArray" withArguments:@[obj]];
return [result boolValue];
}
- (NSArray*) arrayFromWebScriptObject:(WebScriptObject *)obj {
NSMutableArray * values = NSMutableArray.new;
id elem = nil;
int i = 0;
WebUndefined *undefined = [WebUndefined undefined];
while ((elem = [obj webScriptValueAtIndex:i++]) != undefined) {
[values addObject:elem];
}
return values;
}
#pragma mark - Called from JavaScript
-(void)log:(NSString*) str {
NSLog(@"JAVASCRIPT LOG: %@", str);
}
-(NSNumber *)reloadInterval {
NSLog(@"reloadInterval:");
return self.refreshIntervalSeconds;
}
-(void)setReloadInterval:(NSNumber* )arg{
if (![arg isKindOfClass:[NSNumber class]]) {
return;
}
NSLog(@"setReloadInterval: %@", arg);
self.refreshIntervalSeconds = arg;
[self reinitAutoReloadTimer];
}
- (void) resizeToFit {
[self resizeWebViewToFitContents];
}
- (void) resetMenu {
NSLog(@"resetMenu");
_menu = NSMenu.new;
}
- (void) addMenuItem:(NSObject*)titleOrParamsDict {
[self addMenuItems:titleOrParamsDict];
}
- (void) addMenuItems:(NSObject*)titleOrParamsDict {
NSDictionary * params = nil;
if ([[titleOrParamsDict class] isSubclassOfClass:[NSString class]]) {
NSString * title = (NSString *)titleOrParamsDict;
if ([title hasPrefix:@"---"]) {
[self addMenuSeperatorItem];
return;
}
params = @{@"title": title};
}
else if ([[titleOrParamsDict class] isSubclassOfClass:[NSArray class]]) {
NSArray * values = (NSArray *)titleOrParamsDict;
for (NSObject * value in values) {
[self addMenuItem:value];
}
return;
}
else if ([[titleOrParamsDict class] isSubclassOfClass:[NSDictionary class]]) {
params = (NSDictionary *)titleOrParamsDict;
}
else if ([[titleOrParamsDict class] isSubclassOfClass:[WebScriptObject class]]) {
WebScriptObject * obj = (WebScriptObject*) titleOrParamsDict;
if ([self isWebScriptObjectInstanceOfArray:obj]) {
[self addMenuItems:[self arrayFromWebScriptObject:obj]];
return;
} else {
params = [self dictionaryFromWebScriptObject:obj];
}
}
else {
NSLog(@"addMenuItem: ERROR: unhandled class: %@", [titleOrParamsDict class]);
}
if (params != nil) {
NSLog(@"addMenuItem: %@", params);
NSMenuItem * item = [self buildMenuItemWithParams:params];
[_menu addItem:item];
}
}
- (void) addMenuSeperatorItem {
NSLog(@"addMenuSeperatorItem");
[_menu addItem:[NSMenuItem separatorItem]];
}
- (void) showMenu {
NSLog(@"showMenu");
_menu.delegate = self;
[self addDefaultMenuItems:_menu];
self.statusItem.menu = _menu;
[self.statusItem popUpStatusItemMenu:self.statusItem.menu];
}
- (void) showWebInspector {
WebView * webview = (WebView*) self.statusItem.view;
WebInspector * inspector = [WebInspector.alloc initWithWebView:webview];
// [inspector detach:sender];
[inspector showConsole:webview];
}
@end
================================================
FILE: archive/bitbar/App/BitBar/Images.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "bitbar-16.png",
"scale" : "1x"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "bitbar-32.png",
"scale" : "2x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "bitbar-33.png",
"scale" : "1x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "bitbar-64.png",
"scale" : "2x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "bitbar-128.png",
"scale" : "1x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "bitbar-256.png",
"scale" : "2x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "bitbar-257.png",
"scale" : "1x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "bitbar-512.png",
"scale" : "2x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "bitbar-513.png",
"scale" : "1x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "bitbar-1024.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: archive/bitbar/App/BitBar/NSColor+Hex.h
================================================
//
// NSColor+Hex.h
// BitBar
//
// Created by Mathias Leppich on 03/02/14.
// Copyright (c) 2014 Bit Bar. All rights reserved.
//
#import
@interface NSColor (Hex)
+ (NSColor*) colorWithWebColorString:(NSString*)color;
+ (NSColor*) colorWithHexColorString:(NSString*)hex;
@end
================================================
FILE: archive/bitbar/App/BitBar/NSColor+Hex.m
================================================
//
// NSColor+Hex.m
// BitBar
//
// Created by Mathias Leppich on 03/02/14.
// Copyright (c) 2014 Bit Bar. All rights reserved.
//
#import "NSColor+Hex.h"
@implementation NSColor (Hex)
+ (NSDictionary *)cssColors {
static NSDictionary *cssDictionary = nil;
return cssDictionary = cssDictionary ?: @{@"lightseagreen":@"20b2aa", @"floralwhite":@"fffaf0", @"lightgray":@"d3d3d3", @"darkgoldenrod":@"b8860b", @"paleturquoise":@"afeeee", @"goldenrod":@"daa520", @"skyblue":@"87ceeb", @"indianred":@"cd5c5c", @"darkgray":@"a9a9a9", @"khaki":@"f0e68c", @"blue":@"0000ff", @"darkred":@"8b0000", @"lightyellow":@"ffffe0", @"midnightblue":@"191970", @"chartreuse":@"7fff00", @"lightsteelblue":@"b0c4de", @"slateblue":@"6a5acd", @"firebrick":@"b22222", @"moccasin":@"ffe4b5", @"salmon":@"fa8072", @"sienna":@"a0522d", @"slategray":@"708090", @"teal":@"008080", @"lightsalmon":@"ffa07a", @"pink":@"ffc0cb", @"burlywood":@"deb887", @"gold":@"ffd700", @"springgreen":@"00ff7f", @"lightcoral":@"f08080", @"black":@"000000", @"blueviolet":@"8a2be2", @"chocolate":@"d2691e", @"aqua":@"00ffff", @"darkviolet":@"9400d3", @"indigo":@"4b0082", @"darkcyan":@"008b8b", @"orange":@"ffa500", @"antiquewhite":@"faebd7", @"peru":@"cd853f", @"silver":@"c0c0c0", @"purple":@"800080", @"saddlebrown":@"8b4513", @"lawngreen":@"7cfc00", @"dodgerblue":@"1e90ff", @"lime":@"00ff00", @"linen":@"faf0e6", @"lightblue":@"add8e6", @"darkslategray":@"2f4f4f", @"lightskyblue":@"87cefa", @"mintcream":@"f5fffa", @"olive":@"808000", @"hotpink":@"ff69b4", @"papayawhip":@"ffefd5", @"mediumseagreen":@"3cb371", @"mediumspringgreen":@"00fa9a", @"cornflowerblue":@"6495ed", @"plum":@"dda0dd", @"seagreen":@"2e8b57", @"palevioletred":@"db7093", @"bisque":@"ffe4c4", @"beige":@"f5f5dc", @"darkorchid":@"9932cc", @"royalblue":@"4169e1", @"darkolivegreen":@"556b2f", @"darkmagenta":@"8b008b", @"orange red":@"ff4500", @"lavender":@"e6e6fa", @"fuchsia":@"ff00ff", @"darkseagreen":@"8fbc8f", @"lavenderblush":@"fff0f5", @"wheat":@"f5deb3", @"steelblue":@"4682b4", @"lightgoldenrodyellow":@"fafad2", @"lightcyan":@"e0ffff", @"mediumaquamarine":@"66cdaa", @"turquoise":@"40e0d0", @"dark blue":@"00008b", @"darkorange":@"ff8c00", @"brown":@"a52a2a", @"dimgray":@"696969", @"deeppink":@"ff1493", @"powderblue":@"b0e0e6", @"red":@"ff0000", @"darkgreen":@"006400", @"ghostwhite":@"f8f8ff", @"white":@"ffffff", @"navajowhite":@"ffdead", @"navy":@"000080", @"ivory":@"fffff0", @"palegreen":@"98fb98", @"whitesmoke":@"f5f5f5", @"gainsboro":@"dcdcdc", @"mediumslateblue":@"7b68ee", @"olivedrab":@"6b8e23", @"mediumpurple":@"9370db", @"darkslateblue":@"483d8b", @"blanchedalmond":@"ffebcd", @"darkkhaki":@"bdb76b", @"green":@"008000", @"limegreen":@"32cd32", @"snow":@"fffafa", @"tomato":@"ff6347", @"darkturquoise":@"00ced1", @"orchid":@"da70d6", @"yellow":@"ffff00", @"green yellow":@"adff2f", @"azure":@"f0ffff", @"mistyrose":@"ffe4e1", @"cadetblue":@"5f9ea0", @"oldlace":@"fdf5e6", @"gray":@"808080", @"honeydew":@"f0fff0", @"peachpuff":@"ffdab9", @"tan":@"d2b48c", @"thistle":@"d8bfd8", @"palegoldenrod":@"eee8aa", @"mediumorchid":@"ba55d3", @"rosybrown":@"bc8f8f", @"mediumturquoise":@"48d1cc", @"lemonchiffon":@"fffacd", @"maroon":@"800000", @"mediumvioletred":@"c71585", @"violet":@"ee82ee", @"yellow green":@"9acd32", @"coral":@"ff7f50", @"lightgreen":@"90ee90", @"cornsilk":@"fff8dc", @"mediumblue":@"0000cd", @"aliceblue":@"f0f8ff", @"forestgreen":@"228b22", @"aquamarine":@"7fffd4", @"deepskyblue":@"00bfff", @"lightslategray":@"778899", @"darksalmon":@"e9967a", @"crimson":@"dc143c", @"sandybrown":@"f4a460", @"lightpink":@"ffb6c1", @"seashell":@"fff5ee"};
}
+ (NSColor*)colorWithWebColorString:(NSString*)colorString
{
NSString * hexString = [colorString hasPrefix:@"#"]
? [colorString substringWithRange:NSMakeRange(1,colorString.length - 1)]
: self.cssColors[colorString.lowercaseString];
return [self colorWithHexColorString:hexString];
}
+ (NSColor*)colorWithHexColorString:(NSString*)inColorString
{
NSColor* result = nil;
unsigned colorCode = 0;
unsigned char redByte, greenByte, blueByte;
if (nil != inColorString)
{
NSScanner* scanner = [NSScanner scannerWithString:inColorString];
(void) [scanner scanHexInt:&colorCode]; // ignore error
}
redByte = (unsigned char)(colorCode >> 16);
greenByte = (unsigned char)(colorCode >> 8);
blueByte = (unsigned char)(colorCode); // masks off high bits
result = [NSColor
colorWithCalibratedRed:(CGFloat)redByte / 0xff
green:(CGFloat)greenByte / 0xff
blue:(CGFloat)blueByte / 0xff
alpha:1.0];
return result;
}
@end
================================================
FILE: archive/bitbar/App/BitBar/NSString+ANSI.h
================================================
//
// NSString+ANSI.h
// BitBar
//
// Created by Kent Karlsson on 3/11/16.
// Copyright © 2016 Bit Bar. All rights reserved.
//
#import
@interface NSString (ANSI)
- (BOOL)containsANSICodes;
- (NSMutableAttributedString*)attributedStringParsingANSICodes;
@end
================================================
FILE: archive/bitbar/App/BitBar/NSString+ANSI.m
================================================
//
// NSString+ANSI.m
// BitBar
//
// Created by Kent Karlsson on 3/11/16.
// Copyright © 2016 Bit Bar. All rights reserved.
//
#import "Cocoa/Cocoa.h"
#import "NSString+ANSI.h"
#import "NSColor+Hex.h"
@implementation NSMutableDictionary (ANSI)
- (NSMutableDictionary*)modifyAttributesForANSICodes:(NSString*)codes {
BOOL bold = NO;
NSFont* font = self[NSFontAttributeName];
NSArray* codeArray = [codes componentsSeparatedByString:@";"];
for (NSString* codeString in codeArray) {
int code = codeString.intValue;
switch (code) {
case 0:
[self removeAllObjects];
// remove italic and bold from font here
if (font) self[NSFontAttributeName] = font;
break;
case 1:
case 22:
bold = (code == 1);
break;
// case 3: italic
// case 23: italic off
// case 4: underlined
// case 24: underlined off
case 30:
self[NSForegroundColorAttributeName] = [NSColor colorWithHexColorString:bold ? @"7f7f7f" : @"000000"];
break;
case 31:
self[NSForegroundColorAttributeName] = [NSColor colorWithHexColorString:bold ? @"cd0000" : @"ff0000"];
break;
case 32:
self[NSForegroundColorAttributeName] = [NSColor colorWithHexColorString:bold ? @"00cd00" : @"00ff00"];
break;
case 33:
self[NSForegroundColorAttributeName] = [NSColor colorWithHexColorString:bold ? @"cdcd00" : @"ffff00"];
break;
case 34:
self[NSForegroundColorAttributeName] = [NSColor colorWithHexColorString:bold ? @"0000ee" : @"5c5cff"];
break;
case 35:
self[NSForegroundColorAttributeName] = [NSColor colorWithHexColorString:bold ? @"cd00cd" : @"ff00ff"];
break;
case 36:
self[NSForegroundColorAttributeName] = [NSColor colorWithHexColorString:bold ? @"00cdcd" : @"00ffff"];
break;
case 37:
self[NSForegroundColorAttributeName] = [NSColor colorWithHexColorString:bold ? @"e5e5e5" : @"ffffff"];
break;
case 39:
[self removeObjectForKey:NSForegroundColorAttributeName];
break;
case 40:
self[NSBackgroundColorAttributeName] = [NSColor colorWithHexColorString:@"7f7f7f"];
break;
case 41:
self[NSBackgroundColorAttributeName] = [NSColor colorWithHexColorString:@"cd0000"];
break;
case 42:
self[NSBackgroundColorAttributeName] = [NSColor colorWithHexColorString:@"00cd00"];
break;
case 43:
self[NSBackgroundColorAttributeName] = [NSColor colorWithHexColorString:@"cdcd00"];
break;
case 44:
self[NSBackgroundColorAttributeName] = [NSColor colorWithHexColorString:@"0000ee"];
break;
case 45:
self[NSBackgroundColorAttributeName] = [NSColor colorWithHexColorString:@"cd00cd"];
break;
case 46:
self[NSBackgroundColorAttributeName] = [NSColor colorWithHexColorString:@"00cdcd"];
break;
case 47:
self[NSBackgroundColorAttributeName] = [NSColor colorWithHexColorString:@"e5e5e5"];
break;
case 49:
[self removeObjectForKey:NSBackgroundColorAttributeName];
break;
default:
break;
}
}
return self;
}
@end
@implementation NSString (ANSI)
- (BOOL)containsANSICodes {
return [self rangeOfString:@"\033["].location != NSNotFound;
}
- (NSMutableAttributedString*)attributedStringParsingANSICodes {
NSMutableAttributedString* result = [[NSMutableAttributedString alloc] init];
NSMutableDictionary* attributes = [NSMutableDictionary.alloc init];
NSArray* parts = [self componentsSeparatedByString:@"\033["];
[result appendAttributedString:[NSAttributedString.alloc initWithString:parts.firstObject attributes:nil]];
for (NSString* part in [parts subarrayWithRange:NSMakeRange(1, parts.count - 1)]) {
if (part.length == 0)
continue;
NSArray* sequence = [part componentsSeparatedByString:@"m"];
NSString* text = sequence.lastObject;
if (sequence.count < 2) {
[result appendAttributedString:[NSAttributedString.alloc initWithString:text attributes:attributes]];
} else if (sequence.count >= 2) {
text = [[sequence subarrayWithRange:NSMakeRange(1, sequence.count - 1)] componentsJoinedByString:@"m"];
[attributes modifyAttributesForANSICodes:sequence[0]];
[result appendAttributedString:[NSAttributedString.alloc initWithString:text attributes:attributes]];
}
}
return result;
}
@end
================================================
FILE: archive/bitbar/App/BitBar/NSUserDefaults+Settings.h
================================================
//
// Settings.h
// BitBar
//
// Created by Mat Ryer on 11/13/13.
// Copyright (c) 2013 Bit Bar. All rights reserved.
//
@import Foundation;
@interface NSUserDefaults (Settings)
@property NSString* pluginsDirectory;
@property BOOL isFirstTimeAppRun;
@property BOOL userConfigDisabled;
@end
#define DEFS NSUserDefaults.standardUserDefaults
================================================
FILE: archive/bitbar/App/BitBar/NSUserDefaults+Settings.m
================================================
//
// Settings.m
// BitBar
//
// Created by Mat Ryer on 11/13/13.
// Copyright (c) 2013 Bit Bar. All rights reserved.
//
#import "NSUserDefaults+Settings.h"
@implementation NSUserDefaults (Settings)
- (NSString *)pluginsDirectory {
#ifdef DISTRO
return [self stringForKey:@"pluginsDirectory"] ?: [NSBundle mainBundle].executablePath.stringByDeletingLastPathComponent;
#else
return [self stringForKey:@"pluginsDirectory"];
#endif
}
- (void) setPluginsDirectory:(NSString*)value {
[self setObject:value forKey:@"pluginsDirectory"];
}
- (BOOL) isFirstTimeAppRun { return ![self boolForKey:@"appHasRun"]; }
- (void) setIsFirstTimeAppRun:(BOOL)firstTime {
[self setBool:!firstTime forKey:@"appHasRun"];
}
- (BOOL)userConfigDisabled {
#ifdef DISTRO
id disabled = [self objectForKey:@"userConfigDisabled"];
return disabled ? [disabled boolValue] : YES;
#else
return [self boolForKey:@"userConfigDisabled"];
#endif
}
- (void)setUserConfigDisabled:(BOOL)disabled {
[self setBool:disabled forKey:@"userConfigDisabled"];
}
@end
================================================
FILE: archive/bitbar/App/BitBar/Plugin.h
================================================
//
// Plugin.h
// BitBar
//
// Created by Mat Ryer on 11/12/13.
// Copyright (c) 2013 Bit Bar. All rights reserved.
//
@import AppKit;
@class PluginManager;
@interface Plugin : NSObject
@property (nonatomic) NSInteger currentLine, cycleLinesIntervalSeconds;
@property (nonatomic) BOOL lastCommandWasError, pluginIsVisible, menuIsOpen;
@property (readonly) BOOL isMultiline;
@property (readonly) NSString *lastUpdatedString;
@property (nonatomic, copy) NSString *path, *name, *content, *allContent, *errorContent;
@property (nonatomic) NSArray *allContentLines;
@property (nonatomic) NSArray *titleLines;
@property (nonatomic) NSNumber *refreshIntervalSeconds;
@property (nonatomic) NSMenuItem *lastUpdatedMenuItem;
@property (nonatomic) NSDate *lastUpdated;
@property (weak, readonly) PluginManager *manager;
// UI
@property (nonatomic) NSStatusItem *statusItem;
- initWithManager:(PluginManager*)manager;
- (void) close;
- (NSMenuItem*) buildMenuItemForLine:(NSString *)line;
- (NSMenuItem*) buildMenuItemWithParams:(NSDictionary *)params;
- (NSDictionary *)dictionaryForLine:(NSString *)line;
- (void) rebuildMenuForStatusItem:(NSStatusItem*)statusItem;
- (void) addAdditionalMenuItems:(NSMenu *)menu;
- (void) addDefaultMenuItems:(NSMenu *)menu;
- (void)performRefreshNow;
- (BOOL) refresh;
- (void) cycleLines;
- (void) contentHasChanged;
- (BOOL) isFontValid:(NSString *)fontName;
// actions
- (void)changePluginsDirectorySelected:(id)sender;
@end
================================================
FILE: archive/bitbar/App/BitBar/Plugin.m
================================================
//
// Plugin.m
// BitBar
//
// Created by Mat Ryer on 11/12/13.
// Copyright (c) 2013 Bit Bar. All rights reserved.
//
#import "Plugin.h"
#import "PluginManager.h"
#import "STPrivilegedTask.h"
#import "NSDate+DateTools.h"
#import "NSColor+Hex.h"
#import "NSString+Emojize.h"
#import "NSString+ANSI.h"
#define DEFAULT_TIME_INTERVAL_SECONDS ((double)60.)
@implementation Plugin
- init { return (self = super.init) ? _currentLine = -1, _cycleLinesIntervalSeconds = 5, self : nil; }
- initWithManager:(PluginManager*)manager { return (self = self.init) ? _manager = manager, self : nil; }
- (NSStatusItem *)statusItem { return _statusItem = _statusItem ?: ({
// make the status item
_statusItem = [self.manager.statusBar statusItemWithLength:NSVariableStatusItemLength];
// build the menu
[self rebuildMenuForStatusItem:_statusItem]; _statusItem; });
}
- (NSImage*) createImageFromBase64:(NSString*)string isTemplate:(BOOL)template{
NSData * imageData;
if ([NSData instancesRespondToSelector:@selector(initWithBase64EncodedString:options:)]) {
imageData = [[NSData alloc] initWithBase64EncodedString:string options:0];
}else {
imageData = [[NSData alloc] initWithBase64Encoding:string];
}
NSImage * image = [[NSImage alloc] initWithData:imageData];
if (template) {
[image setTemplate:true];
}
return image;
}
- (NSMenuItem*) buildMenuItemWithParams:(NSDictionary *)params {
if ([[params[@"dropdown"] lowercaseString] isEqualToString:@"false"]) {
return nil;
}
NSString * fullTitle = params[@"title"];
if (![[params[@"emojize"] lowercaseString] isEqualToString:@"false"]) {
fullTitle = [fullTitle emojizedString];
}
if (![[params[@"trim"] lowercaseString] isEqualToString:@"false"]) {
fullTitle = [fullTitle stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceCharacterSet];
}
CGFloat titleLength = [fullTitle length];
CGFloat lengthParam = params[@"length"] ? [params[@"length"] floatValue] : titleLength;
CGFloat truncLength = lengthParam >= titleLength ? titleLength : lengthParam;
NSString * title = truncLength < titleLength ? [[fullTitle substringToIndex:truncLength] stringByAppendingString:@"…"] : fullTitle;
SEL sel = params[@"href"] ? @selector(performMenuItemHREFAction:)
: params[@"bash"] ? @selector(performMenuItemOpenTerminalAction:)
: params[@"refresh"] ? @selector(performRefreshNow):
nil;
NSMenuItem * item = [NSMenuItem.alloc initWithTitle:title action:sel keyEquivalent:@""];
if (truncLength < titleLength)
[item setToolTip:fullTitle];
item.representedObject = params;
if (sel) {
[item setTarget:self];
}
BOOL parseANSI = [fullTitle containsANSICodes] && ![[params[@"ansi"] lowercaseString] isEqualToString:@"false"];
if (params[@"font"] || params[@"size"] || params[@"color"] || parseANSI)
item.attributedTitle = [self attributedTitleWithParams:params];
if (params[@"alternate"]) {
item.alternate = YES;
item.keyEquivalentModifierMask = NSAlternateKeyMask;
}
if (params[@"templateImage"]) {
item.image = [self createImageFromBase64:params[@"templateImage"] isTemplate:true];
}else if (params[@"image"]) {
item.image = [self createImageFromBase64:params[@"image"] isTemplate:false];
}
return item;
}
- (NSAttributedString*) attributedTitleWithParams:(NSDictionary *)params {
NSString * fullTitle = params[@"title"];
if (![[params[@"emojize"] lowercaseString] isEqualToString:@"false"]) {
fullTitle = [fullTitle emojizedString];
}
if (![[params[@"trim"] lowercaseString] isEqualToString:@"false"]) {
fullTitle = [fullTitle stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceCharacterSet];
}
CGFloat titleLength = [fullTitle length];
CGFloat lengthParam = params[@"length"] ? [params[@"length"] floatValue] : titleLength;
CGFloat truncLength = lengthParam >= titleLength ? titleLength : lengthParam;
NSString * title = truncLength < titleLength ? [[fullTitle substringToIndex:truncLength] stringByAppendingString:@"…"] : fullTitle;
CGFloat size = params[@"size"] ? [params[@"size"] floatValue] : 14;
NSFont * font;
if ([NSFont respondsToSelector:@selector(monospacedDigitSystemFontOfSize:weight:)]) {
font = [self isFontValid:params[@"font"]] ? [NSFont fontWithName:params[@"font"] size:size]
: [NSFont monospacedDigitSystemFontOfSize:size weight:NSFontWeightRegular]
?: [NSFont monospacedDigitSystemFontOfSize:size weight:NSFontWeightRegular];
} else {
font = [self isFontValid:params[@"font"]] ? [NSFont fontWithName:params[@"font"] size:size]
: [NSFont menuFontOfSize:size]
?: [NSFont menuFontOfSize:size];
}
NSNumber * offset;
if (@available(macOS 11.0.1, *)) {
offset = @-1;
} else {
offset = @0;
}
NSDictionary* attributes = @{NSFontAttributeName: font, NSBaselineOffsetAttributeName : offset};
BOOL parseANSI = [fullTitle containsANSICodes] && ![[params[@"ansi"] lowercaseString] isEqualToString:@"false"];
if (parseANSI) {
NSMutableAttributedString * attributedTitle = [title attributedStringParsingANSICodes];
[attributedTitle addAttributes:attributes range:NSMakeRange(0, attributedTitle.length)];
return attributedTitle;
} else {
NSColor * fgColor;
NSMutableAttributedString * attributedTitle = [NSMutableAttributedString.alloc initWithString:title attributes:attributes];
if (!params[@"color"]) return attributedTitle;
if ((fgColor = [NSColor colorWithWebColorString:[params objectForKey:@"color"]]))
[attributedTitle addAttribute:NSForegroundColorAttributeName value:fgColor range:NSMakeRange(0, title.length)];
return attributedTitle;
}
}
- (NSMenuItem*) buildMenuItemForLine:(NSString *)line { return [self buildMenuItemWithParams:[self dictionaryForLine:line]]; }
- (NSDictionary*) dictionaryForLine:(NSString *)line {
// Find the title
NSRange found = [line rangeOfString:@"|"];
if (found.location == NSNotFound) return @{ @"title": line };
NSString * title = [line substringToIndex:found.location];
NSMutableDictionary * params = @{@"title":title}.mutableCopy;
// Find the parameters
NSString * paramStr = [line substringFromIndex:found.location + found.length];
NSScanner* scanner = [NSScanner scannerWithString:paramStr];
NSMutableCharacterSet* keyValueSeparator = [NSMutableCharacterSet characterSetWithCharactersInString:@"=:"];
NSMutableCharacterSet* quoteSeparator = [NSMutableCharacterSet characterSetWithCharactersInString:@"\"'"];
while (![scanner isAtEnd]) {
NSString *key = @""; NSString* value = @"";
[scanner scanUpToCharactersFromSet:keyValueSeparator intoString:&key];
[scanner scanCharactersFromSet:keyValueSeparator intoString:NULL];
if ([scanner scanCharactersFromSet:quoteSeparator intoString:NULL]) {
[scanner scanUpToCharactersFromSet:quoteSeparator intoString:&value];
[scanner scanCharactersFromSet:quoteSeparator intoString:NULL];
} else {
[scanner scanUpToString:@" " intoString:&value];
}
// Remove extraneous spaces from key and value
key = [key stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
params[key] = value;
if([key isEqualToString:@"args"]){
params[key] = [value componentsSeparatedByString:@"__"];
}
}
return params;
}
- (void)performRefreshNow {
NSLog(@"Nothing to refresh in this plugin");
}
- (void)performHREFAction:(NSDictionary *)params {
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:params[@"href"]]];
}
- (void) performMenuItemHREFAction:(NSMenuItem *)menuItem {
[self performHREFAction:menuItem.representedObject];
}
- (void) startTask:(NSMutableDictionary*)params {
id task = [params[@"root"] isEqualToString:@"true"] ? STPrivilegedTask.new : NSTask.new;
[(NSTask*)task setLaunchPath:params[@"bash"]];
[(NSTask*)task setArguments:params[@"args"]];
((NSTask*)task).terminationHandler = ^(NSTask *task) {
if (params[@"refresh"]) {
[self performSelectorOnMainThread:@selector(performRefreshNow) withObject:NULL waitUntilDone:false];
}
};
@try {
[(NSTask*)task launch];
} @catch (NSException *e) {
NSLog(@"Error launching command for %@:\n\tCMD: %@\n\tARGS: %@\n%@", self.name, params[@"bash"], params[@"args"], e);
}
[(NSTask*)task waitUntilExit];
}
- (void)performOpenTerminalAction:(NSMutableDictionary *)params {
NSString *bash = [params[@"bash"] stringByStandardizingPath].stringByResolvingSymlinksInPath,
*param1 = params[@"param1"] ?: @"",
*param2 = params[@"param2"] ?: @"",
*param3 = params[@"param3"] ?: @"",
*param4 = params[@"param4"] ?: @"",
*param5 = params[@"param5"] ?: @"",
*terminal = params[@"terminal"] ?: [NSString stringWithFormat:@"%s", "true"];
NSArray *args = params[@"args"] ?: ({
NSMutableArray *argArray = @[].mutableCopy;
for (int i = 1; i < 6; i ++) {
id x = params[[NSString stringWithFormat:@"param%i", i]];
if (x) [argArray addObject:x];
}
argArray.copy;
});
if([terminal isEqual: @"false"]){
NSLog(@"Args: %@", args);
[params setObject:bash forKey:@"bash"];
[params setObject:args forKey:@"args"];
[self performSelectorInBackground:@selector(startTask:) withObject:params];
} else {
NSString *full_link = [NSString stringWithFormat:@"'%@' %@ %@ %@ %@ %@", bash, param1, param2, param3, param4, param5];
NSString *s = [NSString stringWithFormat:@"tell application \"Terminal\" \n\
do script \"%@\" \n\
activate \n\
end tell", full_link];
NSAppleScript *as = [NSAppleScript.alloc initWithSource: s];
[as executeAndReturnError:nil];
}
}
- (void)performMenuItemOpenTerminalAction:(NSMenuItem *)menuItem {
[self performOpenTerminalAction:menuItem.representedObject];
}
- (void) rebuildMenuForStatusItem:(NSStatusItem*)statusItem {
// build the menu
NSMenu *menu = NSMenu.new;
[menu setDelegate:self];
if (self.isMultiline) {
// put all content as an item
NSString *line;
if ([self.titleLines count] > 1) {
for (line in self.titleLines) {
NSMenuItem * item = [self buildMenuItemForLine:line];
if (item) {
[menu addItem:item];
}
}
// add the seperator
[menu addItem:[NSMenuItem separatorItem]];
}
// are there any allContentLines?
if (self.allContentLines.count > 0) {
// put all content as an item
NSString *line;
for (line in self.allContentLines) {
if ([line isEqualToString:@"---"]) {
[menu addItem:[NSMenuItem separatorItem]];
} else {
NSMenu *submenu = menu;
// traverse submenus up to the menu to add the item to
while ([line hasPrefix:@"--"]) {
line = [line substringFromIndex:2];
NSMenuItem *lastItem = submenu.itemArray.lastObject;
if (!lastItem.submenu) {
lastItem.submenu = [[NSMenu alloc] init];
lastItem.submenu.delegate = self;
}
submenu = lastItem.submenu;
if ([line isEqualToString:@"---"]) {
break;
}
}
if ([line isEqualToString:@"---"]) {
[submenu addItem:[NSMenuItem separatorItem]];
} else {
NSMenuItem * item = [self buildMenuItemForLine:line];
if(item)
[submenu addItem:item];
}
}
}
// add the seperator
[menu addItem:[NSMenuItem separatorItem]];
}
}
if (self.lastUpdated != nil) {
self.lastUpdatedMenuItem = [NSMenuItem.alloc initWithTitle:@"Updated just now" action:nil keyEquivalent:@""];
[menu addItem:self.lastUpdatedMenuItem];
}
[self addAdditionalMenuItems:menu];
[self addDefaultMenuItems:menu];
// set the menu
statusItem.menu = menu;
}
- (void) addDefaultMenuItems:(NSMenu *)menu {
[self.manager addHelperItemsToMenu:menu asSubMenu:(menu.itemArray.count>0)];
}
- (void) addAdditionalMenuItems:(NSMenu *)menu { }
- (void) changePluginsDirectorySelected:_ {
_manager.path = nil;
[_manager reset];
}
- (NSNumber*) refreshIntervalSeconds {
if (_refreshIntervalSeconds == nil) {
NSArray *segments = [self.name componentsSeparatedByString:@"."];
if (segments.count < 3)
return _refreshIntervalSeconds = @(DEFAULT_TIME_INTERVAL_SECONDS);
NSString *timeStr = [segments[1] lowercaseString];
if ([timeStr length] < 2) {
_refreshIntervalSeconds = @(DEFAULT_TIME_INTERVAL_SECONDS);
return _refreshIntervalSeconds;
}
NSString *numberPart = [timeStr substringToIndex:[timeStr length]-1];
double numericalValue = numberPart.doubleValue ?: DEFAULT_TIME_INTERVAL_SECONDS;
if ([timeStr hasSuffix:@"s"]) {
// this is ok - but nothing to do
} else if ([timeStr hasSuffix:@"m"]) numericalValue *= 60;
else if ([timeStr hasSuffix:@"h"]) numericalValue *= 60*60;
else if ([timeStr hasSuffix:@"d"]) numericalValue *= 60*60*24;
else
return _refreshIntervalSeconds = @(DEFAULT_TIME_INTERVAL_SECONDS);
_refreshIntervalSeconds = @(numericalValue);
}
return _refreshIntervalSeconds;
}
- (BOOL) refresh {
return YES;
}
- (void) close {
}
- (NSString*) lastUpdatedString { return [self.lastUpdated timeAgoSinceNow].lowercaseString; }
- (void) cycleLines {
// do nothing if the menu is open
if (self.menuIsOpen) { return; };
// update the status item
self.currentLine++;
// if we've gone too far - wrap around
if ((NSUInteger)self.currentLine >= self.titleLines.count) {
self.currentLine = 0;
}
if (self.titleLines.count > 0) {
NSDictionary * params = [self dictionaryForLine:self.titleLines[self.currentLine]];
// skip alternate line
if (params[@"alternate"]) {
[self cycleLines];
return;
}
if (params[@"href"] || params[@"bash"] || params[@"refresh"]) {
self.statusItem.menu = nil;
self.statusItem.action = @selector(statusItemClicked);
self.statusItem.target = self;
} else if (!self.statusItem.menu) {
self.statusItem.action = NULL;
self.statusItem.target = nil;
[self rebuildMenuForStatusItem:self.statusItem];
}
// Add image if present
if (params[@"templateImage"]) {
self.statusItem.image = [self createImageFromBase64:params[@"templateImage"] isTemplate:true];
}else if (params[@"image"]) {
self.statusItem.image = [self createImageFromBase64:params[@"image"] isTemplate:false];
} else {
self.statusItem.image = nil;
}
self.statusItem.attributedTitle = [self attributedTitleWithParams:params];
self.pluginIsVisible = YES;
} else {
self.statusItem = nil;
self.pluginIsVisible = NO;
}
}
- (void) contentHasChanged {
_allContent = nil;
_titleLines = nil;
_allContentLines = nil;
}
- (BOOL) isFontValid:(NSString *)fontName {
if (fontName == nil) {
return NO;
}
NSFontDescriptor *fontDescriptor = [NSFontDescriptor fontDescriptorWithFontAttributes:@{NSFontNameAttribute:fontName}];
NSArray *matches = [fontDescriptor matchingFontDescriptorsWithMandatoryKeys: nil];
return ([matches count] > 0);
}
- (void) setContent:(NSString *)content {
_content = content;
[self contentHasChanged];
}
- (void) setErrorContent:(NSString *)errorContent {
_errorContent = errorContent;
[self contentHasChanged];
}
- (NSString *)allContent {
if (!_allContent) {
_allContent = self.content;
if (self.errorContent.length > 0) {
_allContent = [@"⚠️" stringByAppendingString:_allContent];
_allContent = [_allContent stringByAppendingString:@"\n---\n"];
_allContent = [_allContent stringByAppendingString:self.errorContent];
}
}
return _allContent;
}
- (NSArray *)titleLines {
return _titleLines = _titleLines ?: ({
NSMutableArray *cleanLines = @[].mutableCopy;
for (NSString *lineEval in [self.allContent componentsSeparatedByCharactersInSet:NSCharacterSet.newlineCharacterSet]) {
// strip whitespace
NSString *line = [self cleanLine:lineEval];
// add the line if we have something in it
if (line.length) {
if ([line isEqualToString:@"---"]) break;
[cleanLines addObject:line];
}
}
cleanLines.copy;
});
}
- (NSString*) cleanLine:(NSString*)line {
NSArray *splitLine = [line componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
if ([[splitLine componentsJoinedByString:@""] isEqualToString:@""])
return @"";
return line; //[splitLine componentsJoinedByString:@" "];
//return [regex stringByReplacingMatchesInString:line options:0 range:NSMakeRange(0, line.length) withTemplate:@" "];
}
- (NSArray*) allContentLines {
if (_allContentLines == nil) {
NSArray *lines = [self.allContent componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
NSMutableArray *cleanLines = [NSMutableArray.alloc initWithCapacity:lines.count];
NSString *line;
BOOL firstBreakFound = NO;
for (line in lines) {
// strip whitespace
line = [self cleanLine:line];
// add the line if we have something in it
if (line.length > 0) {
if ([line isEqualToString:@"---"]) {
if (firstBreakFound) {
[cleanLines addObject:line];
}
firstBreakFound = YES;
} else {
if (firstBreakFound) {
[cleanLines addObject:line];
}
}
}
}
_allContentLines = [NSArray arrayWithArray:cleanLines];
}
return _allContentLines;
}
- (BOOL) isMultiline {
return [self.titleLines count] > 1 || [self.allContentLines count]>0;
}
- (void)statusItemClicked {
NSDictionary *params = [self dictionaryForLine:self.titleLines[self.currentLine]];
if (params[@"href"]) {
[self performHREFAction:params];
} else if (params[@"bash"]) {
[self performOpenTerminalAction:[NSMutableDictionary dictionaryWithDictionary:params]];
} else if (params[@"refresh"]) {
[self performRefreshNow];
}
}
#pragma mark - NSMenuDelegate
- (void)menuWillOpen:(NSMenu *)menu {
if (menu.supermenu) {
return;
}
self.menuIsOpen = YES;
if (self.currentLine >= 0 && self.currentLine < self.titleLines.count) {
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithDictionary:[self dictionaryForLine:self.titleLines[self.currentLine]]];
if (params[@"color"]) {
[params removeObjectForKey:@"color"];
self.statusItem.attributedTitle = [self attributedTitleWithParams:params];
}
}
[self.statusItem setHighlightMode:YES];
[self.lastUpdatedMenuItem setTitle:self.lastUpdated ? [NSString stringWithFormat:@"Updated %@", self.lastUpdatedString] : @"Refreshing…"];
}
- (void)menuDidClose:(NSMenu *)menu {
if (menu.supermenu) {
return;
}
self.menuIsOpen = NO;
[self.statusItem setHighlightMode:NO];
if (self.currentLine >= 0 && self.currentLine < self.titleLines.count) {
NSDictionary *params = [self dictionaryForLine:self.titleLines[self.currentLine]];
if (params[@"color"]) {
self.statusItem.attributedTitle = [self attributedTitleWithParams:params];
}
}
}
- (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item {
// restore about to be unhighlighted item
if (menu.highlightedItem.representedObject && menu.highlightedItem.attributedTitle) {
NSDictionary *params = menu.highlightedItem.representedObject;
if (params[@"color"]) {
menu.highlightedItem.attributedTitle = [self attributedTitleWithParams:params];
}
}
// remove about to be highlighted item color
if (item.representedObject && item.attributedTitle) {
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithDictionary:item.representedObject];
if (params[@"color"]) {
[params removeObjectForKey:@"color"];
item.attributedTitle = [self attributedTitleWithParams:params];
}
}
}
@end
================================================
FILE: archive/bitbar/App/BitBar/PluginManager.h
================================================
//
// PluginManager.h
// BitBar
//
// Created by Mat Ryer on 11/12/13.
// Copyright (c) 2013 Bit Bar. All rights reserved.
//
@import AppKit;
@class Plugin;
@interface PluginManager : NSObject
@property (nonatomic, copy) NSString *path;
@property (nonatomic) NSArray *plugins;
@property (nonatomic) NSStatusBar *statusBar;
@property (nonatomic) NSStatusItem *defaultStatusItem;
@property (nonatomic, readonly) NSDictionary *environment;
- initWithPluginPath:(NSString *)path;
- (NSArray*) pluginFilesWithAsking:(BOOL)shouldAsk;
- (void) reset;
- (void) setupAllPlugins;
- (void) clearPathAndReset;
- (void) showSystemStatusItemWithMessage:(NSString*)message;
- (void) addHelperItemsToMenu:(NSMenu*)menu asSubMenu:(BOOL)submenu;
- (void) pluginDidUdpdateItself:(Plugin*)plugin;
- (void) updateEnvironment;
@end
================================================
FILE: archive/bitbar/App/BitBar/PluginManager.m
================================================
//
// PluginManager.m
// BitBar
//
// Created by Mat Ryer on 11/12/13.
// Copyright (c) 2013 Bit Bar. All rights reserved.
//
#import "PluginManager.h"
#import "Plugin.h"
#import "ExecutablePlugin.h"
#import "HTMLPlugin.h"
#import "NSUserDefaults+Settings.h"
#import "LaunchAtLoginController.h"
#import
NSString *const AppleInterfaceThemeChangedNotification = @"AppleInterfaceThemeChangedNotification";
@interface PluginManager () {
LaunchAtLoginController *_launchAtLoginController;
}
@property (nonatomic, readwrite) NSDictionary *environment;
@end
@implementation PluginManager
- initWithPluginPath:(NSString*)path {
if (self = [super init]) {
_path = [path stringByStandardizingPath];
_launchAtLoginController = [[LaunchAtLoginController alloc] init];
[self updateEnvironment];
[self setupObserver];
}
return self;
}
- (void)dealloc {
[NSDistributedNotificationCenter.defaultCenter removeObserver:self name:AppleInterfaceThemeChangedNotification object:nil];
}
- (void)setupObserver {
[NSDistributedNotificationCenter.defaultCenter addObserver:self selector:@selector(updateEnvironment) name:AppleInterfaceThemeChangedNotification object:nil];
}
- (void) showSystemStatusItemWithMessage:(NSString*)message {
[self.statusBar removeStatusItem:self.defaultStatusItem];
// make default menu item
self.defaultStatusItem = [self.statusBar statusItemWithLength:NSVariableStatusItemLength];
[self.defaultStatusItem setTitle:NSProcessInfo.processInfo.processName];
[(self.defaultStatusItem.menu = NSMenu.new) setDelegate:self];
if (message.length) {
NSMenuItem *messageMenuItem = [NSMenuItem.alloc initWithTitle:message action:nil keyEquivalent:@""];
[self.defaultStatusItem.menu addItem:messageMenuItem];
[self.defaultStatusItem.menu addItem:NSMenuItem.separatorItem];
}
[self addHelperItemsToMenu:self.defaultStatusItem.menu asSubMenu:NO];
}
#define ADD_MENU(TITLE,SELECTOR,SHORTCUT,TARGET) ({ \
NSMenuItem *item = [NSMenuItem.alloc initWithTitle:TITLE action:NSStringFromSelector(@selector(SELECTOR)) ? @selector(SELECTOR) : NULL keyEquivalent:SHORTCUT?:@""];\
if (TARGET) [item setTarget:TARGET]; \
[targetMenu addItem:item]; item; })
- (void) addHelperItemsToMenu:(NSMenu*)menu asSubMenu:(BOOL)submenu {
NSMenu *targetMenu;
NSMenuItem *moreItem = nil;
if (submenu) {
NSMenu *moreMenu = [NSMenu.alloc initWithTitle:@"Preferences"];
moreItem = [NSMenuItem.alloc initWithTitle:@"Preferences" action:nil keyEquivalent:@""];
moreItem.submenu = moreMenu;
[menu addItem:moreItem];
targetMenu = moreMenu;
} else targetMenu = menu;
// add reset, aka refreshMenuItem
ADD_MENU(@"Refresh all", reset, @"r", self);
[targetMenu addItem:NSMenuItem.separatorItem];
NSString *versionString = nil;
versionString = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
if (!versionString) {
versionString = [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
}
NSMenuItem *versionMenuitem = [[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@"v%@", versionString] action:nil keyEquivalent:@""];
if (!DEFS.userConfigDisabled) {
versionMenuitem.alternate = YES;
versionMenuitem.keyEquivalentModifierMask = NSAlternateKeyMask;
// add edit action, aka prefsMenuItem
ADD_MENU(@"Change Plugin Folder…", changePluginDirectory,@"",self);
// add edit action, aka openPluginFolderMenuItem
ADD_MENU(@"Open Plugin Folder…",openPluginFolder, nil, self);
// add browser item, aka openPluginBrowserMenuItem
ADD_MENU(@"Get Plugins…", openPluginsBrowser, nil, self);
[targetMenu addItem:NSMenuItem.separatorItem];
// open at login, aka openAtLoginMenuItem
[ADD_MENU(@"Open at Login", toggleOpenAtLogin:, nil, self) setState:_launchAtLoginController.launchAtLogin];
[targetMenu addItem:NSMenuItem.separatorItem];
//ADD_MENU(@"Check for Updates…", checkForUpdates:, nil, [SUUpdater sharedUpdater]);
}
[targetMenu addItem:versionMenuitem];
//
// // add troubleshooting item
// ADD_MENU(@"User Guide…", openTroubleshootingPage,@"g",self);
//
// // add troubleshooting item
// ADD_MENU(@"Report an Issue…",openHomepage,@"i",self);
//
// quit menu
ADD_MENU(@"Quit",quit, @"q",self);
}
- (void) quit {
[NSApp terminate:[NSApplication sharedApplication]];
}
#define WSPACE NSWorkspace.sharedWorkspace
- (void) openReportIssuesPage {
[WSPACE openURL:[NSURL URLWithString:@"https://github.com/matryer/bitbar/issues"]];
}
- (void) openPluginsBrowser {
[WSPACE openURL:[NSURL URLWithString:@"https://getbitbar.com/"]];
}
- (void) openHomepage {
[WSPACE openURL:[NSURL URLWithString:@"https://github.com/matryer/bitbar"]];
}
- (void) openPluginFolder {
[WSPACE openURL:[NSURL fileURLWithPath:self.path]];
}
- (void) toggleOpenAtLogin:(id)sender {
[_launchAtLoginController setLaunchAtLogin:!_launchAtLoginController.launchAtLogin];
}
- (NSArray*) pluginFilesWithAsking:(BOOL)shouldAsk {
BOOL dirIsOK = !!self.path;
if (dirIsOK) {
BOOL isDir;
if (![NSFileManager.defaultManager fileExistsAtPath:self.path isDirectory:&isDir])
dirIsOK = NO;
if (!isDir) dirIsOK = NO;
}
if (dirIsOK) {
// get the listing
NSError *error;
NSArray *dirFiles = [NSFileManager.defaultManager contentsOfDirectoryAtPath:self.path error:&error];
// handle error if there is one
if (error != nil) {
dirIsOK = NO;
} else {
// filter dot files
dirFiles = [dirFiles filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"NOT self BEGINSWITH '.'"]];
// filter markdown files
dirFiles = [dirFiles filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"NOT self ENDSWITH '.md'"]];
// filter application executable
// filter subdirectories
dirFiles = [dirFiles filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id name, NSDictionary *bindings) {
BOOL isDir;
NSString * path = [self.path stringByAppendingPathComponent:name];
return ![path isEqualToString:[NSBundle mainBundle].executablePath] && [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir] && !isDir;
}]];
return dirFiles;
}
}
return (!dirIsOK && shouldAsk) && self.beginSelectingPluginsDir ? [self pluginFilesWithAsking:NO] : nil;
}
- (BOOL) beginSelectingPluginsDir {
NSOpenPanel* openDlg = [NSOpenPanel openPanel];
[openDlg setCanChooseDirectories:YES];
[openDlg setCanChooseFiles:NO];
[openDlg setCanCreateDirectories:YES];
[openDlg setPrompt:@"Use as Plugins Directory"];
[openDlg setTitle:@"Select BitBar Plugins Directory"];
if (openDlg.runModal == NSOKButton) {
if (!openDlg.URL.isFileURL) {
// TODO: error popup
return NO;
}
BOOL isDir = NO;
if ([[NSFileManager defaultManager] fileExistsAtPath: openDlg.URL.path isDirectory: &isDir]
&& isDir) {
// symlink bundled plugins in selected directory
self.path = [NSBundle mainBundle].executablePath.stringByDeletingLastPathComponent;
NSArray *pluginFiles = [self pluginFilesWithAsking:NO];
for (NSString *file in pluginFiles)
[[NSFileManager defaultManager] createSymbolicLinkAtPath:[openDlg.URL.path stringByAppendingPathComponent:file]
withDestinationPath:[self.path stringByAppendingPathComponent:file]
error:nil];
self.path = [openDlg.URL path];
[DEFS setPluginsDirectory:self.path];
return YES;
}
// TODO: error popup
return NO;
} else self.path = DEFS.pluginsDirectory;
return NO;
}
- (void) reset {
// remove all status items
for (Plugin *plugin in _plugins) {
[self.statusBar removeStatusItem:plugin.statusItem];
[plugin close];
}
_plugins = nil;
[self.statusBar removeStatusItem:self.defaultStatusItem];
[self setupAllPlugins];
}
- (void) clearPathAndReset {
self.path = nil;
[self reset];
}
- (void)changePluginDirectory {
if ([self beginSelectingPluginsDir] == YES) {
[self reset];
}
}
- (NSArray *)plugins {
return _plugins = _plugins ?: ({
NSArray *pluginFiles = [self pluginFilesWithAsking:YES];
NSMutableArray *plugins = [NSMutableArray.alloc initWithCapacity:[pluginFiles count]];
NSString *file;
for (file in pluginFiles) {
// setup this plugin
Plugin *plugin;
if ([@[@"html",@"htm"] containsObject:file.pathExtension.lowercaseString]) {
plugin = [HTMLPlugin.alloc initWithManager:self];
} else {
plugin = [ExecutablePlugin.alloc initWithManager:self];
}
[plugin setPath:[self.path stringByAppendingPathComponent:file]];
[plugin setName:file];
[plugin.statusItem setTitle:@"…"];
[plugins addObject:plugin];
}
plugins.copy;
});
}
- (void)updateEnvironment {
NSMutableDictionary *env = NSProcessInfo.processInfo.environment.mutableCopy;
env[@"BitBar"] = [@YES stringValue];
// Determine if Mac is in Dark Mode
NSString *osxMode = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"];
if ([osxMode isEqualToString:@"Dark"]) {
env[@"BitBarDarkMode"] = [@YES stringValue];
}
self.environment = env;
}
- (void) pluginDidUdpdateItself:(Plugin*)plugin {
[self checkForNoPlugins];
}
- (void)checkForNoPlugins {
Plugin *plugin;
NSInteger visiblePlugins = 0;
for (plugin in self.plugins) {
if (plugin.pluginIsVisible)
visiblePlugins++;
}
visiblePlugins != 0 ? [self.statusBar removeStatusItem:self.defaultStatusItem]
: [self showSystemStatusItemWithMessage:@"No plugins found"];
}
- (NSStatusBar *)statusBar { return _statusBar = _statusBar ?: NSStatusBar.systemStatusBar; }
- (void) setupAllPlugins {
NSArray *plugins = self.plugins;
if (!plugins.count) [self checkForNoPlugins];
else {
for (Plugin *plugin in plugins) [plugin refresh];
}
}
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem {
if ([menuItem action] == @selector(toggleOpenAtLogin:)) {
[menuItem setState:_launchAtLoginController.launchAtLogin ? NSOnState : NSOffState];
}
return YES;
}
#pragma mark - NSMenuDelegate
- (void)menuWillOpen:(NSMenu *)menu {
[self.defaultStatusItem setHighlightMode:YES];
}
- (void)menuDidClose:(NSMenu *)menu {
[self.defaultStatusItem setHighlightMode:NO];
}
@end
================================================
FILE: archive/bitbar/App/BitBar/incoming-url-tests.html
================================================
Incoming URL tests
BitBar - Incoming URL tests
Link
Expectation
Normal
Should open and install 'Cycle Text and Detail' plugin
Missing title
Should open and install 'Cycle Text and Detail' plugin but use cycle_text_and_detail.sh as title
Empty title
Should open and install 'Cycle Text and Detail' plugin but use cycle_text_and_detail.sh as title
Unofficial repo
Should open and install test plugin but have additional warnings - and use full URL (not title)
================================================
FILE: archive/bitbar/App/BitBar.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
0531DCD91844070A007F0A96 /* App.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0531DCD81844070A007F0A96 /* App.xib */; };
05322A49183406E2004D9AFE /* NSUserDefaults+Settings.m in Sources */ = {isa = PBXBuildFile; fileRef = 05322A48183406E2004D9AFE /* NSUserDefaults+Settings.m */; };
055819781834172E00B44B00 /* LaunchAtLoginController.m in Sources */ = {isa = PBXBuildFile; fileRef = 055819771834172E00B44B00 /* LaunchAtLoginController.m */; };
059971961833394500EA6D8D /* Plugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 059971951833394500EA6D8D /* Plugin.m */; };
0599719818333DB300EA6D8D /* PluginTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0599719718333DB300EA6D8D /* PluginTest.m */; };
05DAE007183323DD00409786 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 05DAE006183323DD00409786 /* AppDelegate.m */; };
05DAE02D1833274100409786 /* PluginManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 05DAE02C1833274100409786 /* PluginManager.m */; };
05DAE02F1833276C00409786 /* PluginManagerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 05DAE02E1833276C00409786 /* PluginManagerTest.m */; };
05DB995C1C3D4B80008B5159 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 05DB995B1C3D4B80008B5159 /* Images.xcassets */; };
36372DCC1C9424DB0005EB32 /* PluginTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0599719718333DB300EA6D8D /* PluginTest.m */; };
36372DCE1C9424DB0005EB32 /* PluginManagerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 05DAE02E1833276C00409786 /* PluginManagerTest.m */; };
36372DCF1C9424DB0005EB32 /* PluginManager+Test.m in Sources */ = {isa = PBXBuildFile; fileRef = AE7303DF1C93848400AF5499 /* PluginManager+Test.m */; };
36372DD21C9424DB0005EB32 /* TestPlugins in Resources */ = {isa = PBXBuildFile; fileRef = AE7303DC1C93721600AF5499 /* TestPlugins */; };
36D0CE0A1D0AF012001AFB77 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 36D0CDFF1D0AF009001AFB77 /* Sparkle.framework */; };
36D0CE0B1D0AF012001AFB77 /* Sparkle.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 36D0CDFF1D0AF009001AFB77 /* Sparkle.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
36D0CE101D0AF018001AFB77 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 36D0CDFF1D0AF009001AFB77 /* Sparkle.framework */; };
36D0CE111D0AF019001AFB77 /* Sparkle.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 36D0CDFF1D0AF009001AFB77 /* Sparkle.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
36DCD8BE1C76027C004DE286 /* AHProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D03BB21C3D95E600A64968 /* AHProxy.m */; };
36DCD8BF1C76027C004DE286 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 05DAE006183323DD00409786 /* AppDelegate.m */; };
36DCD8C01C76027C004DE286 /* DTConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A21581B9F0F10002539F7 /* DTConstants.m */; };
36DCD8C11C76027C004DE286 /* HTMLPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = A281BDB71890670800C380A4 /* HTMLPlugin.m */; };
36DCD8C21C76027C004DE286 /* STPrivilegedTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A21501B9F0BE6002539F7 /* STPrivilegedTask.m */; };
36DCD8C31C76027C004DE286 /* ExecutablePlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = A281BDB4189066DE00C380A4 /* ExecutablePlugin.m */; };
36DCD8C41C76027C004DE286 /* DTTimePeriodGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A21621B9F0F10002539F7 /* DTTimePeriodGroup.m */; };
36DCD8C51C76027C004DE286 /* NSTask+useSystemProxies.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D03BB61C3D95E600A64968 /* NSTask+useSystemProxies.m */; };
36DCD8C61C76027C004DE286 /* PluginManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 05DAE02C1833274100409786 /* PluginManager.m */; };
36DCD8C71C76027C004DE286 /* DTError.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A215A1B9F0F10002539F7 /* DTError.m */; };
36DCD8C81C76027C004DE286 /* DTTimePeriodCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A21601B9F0F10002539F7 /* DTTimePeriodCollection.m */; };
36DCD8C91C76027C004DE286 /* NSUserDefaults+Settings.m in Sources */ = {isa = PBXBuildFile; fileRef = 05322A48183406E2004D9AFE /* NSUserDefaults+Settings.m */; };
36DCD8CA1C76027C004DE286 /* NSDate+DateTools.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A21641B9F0F10002539F7 /* NSDate+DateTools.m */; };
36DCD8CB1C76027C004DE286 /* NSColor+Hex.m in Sources */ = {isa = PBXBuildFile; fileRef = A22AF328189F823E0011DFCD /* NSColor+Hex.m */; };
36DCD8CC1C76027C004DE286 /* Plugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 059971951833394500EA6D8D /* Plugin.m */; };
36DCD8CD1C76027C004DE286 /* DTTimePeriodChain.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A215E1B9F0F10002539F7 /* DTTimePeriodChain.m */; };
36DCD8CE1C76027C004DE286 /* LaunchAtLoginController.m in Sources */ = {isa = PBXBuildFile; fileRef = 055819771834172E00B44B00 /* LaunchAtLoginController.m */; };
36DCD8CF1C76027C004DE286 /* AHProxySettings.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D03BB41C3D95E600A64968 /* AHProxySettings.m */; };
36DCD8D01C76027C004DE286 /* DTTimePeriod.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A215C1B9F0F10002539F7 /* DTTimePeriod.m */; };
36DCD8D21C76027C004DE286 /* App.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0531DCD81844070A007F0A96 /* App.xib */; };
36DCD8D31C76027C004DE286 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 05DB995B1C3D4B80008B5159 /* Images.xcassets */; };
36DCD8D41C76027C004DE286 /* DateTools.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 7B9A21551B9F0F10002539F7 /* DateTools.bundle */; };
7B9A21531B9F0BE6002539F7 /* STPrivilegedTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A21501B9F0BE6002539F7 /* STPrivilegedTask.m */; };
7B9A21651B9F0F10002539F7 /* DateTools.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 7B9A21551B9F0F10002539F7 /* DateTools.bundle */; };
7B9A21661B9F0F10002539F7 /* DTConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A21581B9F0F10002539F7 /* DTConstants.m */; };
7B9A21671B9F0F10002539F7 /* DTError.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A215A1B9F0F10002539F7 /* DTError.m */; };
7B9A21681B9F0F10002539F7 /* DTTimePeriod.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A215C1B9F0F10002539F7 /* DTTimePeriod.m */; };
7B9A21691B9F0F10002539F7 /* DTTimePeriodChain.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A215E1B9F0F10002539F7 /* DTTimePeriodChain.m */; };
7B9A216A1B9F0F10002539F7 /* DTTimePeriodCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A21601B9F0F10002539F7 /* DTTimePeriodCollection.m */; };
7B9A216B1B9F0F10002539F7 /* DTTimePeriodGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A21621B9F0F10002539F7 /* DTTimePeriodGroup.m */; };
7B9A216C1B9F0F10002539F7 /* NSDate+DateTools.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A21641B9F0F10002539F7 /* NSDate+DateTools.m */; };
A22AF329189F823E0011DFCD /* NSColor+Hex.m in Sources */ = {isa = PBXBuildFile; fileRef = A22AF328189F823E0011DFCD /* NSColor+Hex.m */; };
A281BDB5189066DE00C380A4 /* ExecutablePlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = A281BDB4189066DE00C380A4 /* ExecutablePlugin.m */; };
A281BDB81890670800C380A4 /* HTMLPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = A281BDB71890670800C380A4 /* HTMLPlugin.m */; };
AE3C167A1C93F71B009AF7CA /* NSString+Emojize.m in Sources */ = {isa = PBXBuildFile; fileRef = AE7303D81C935BDE00AF5499 /* NSString+Emojize.m */; };
AE4B1E391C9B2B0F009540AD /* NSString+ANSI.m in Sources */ = {isa = PBXBuildFile; fileRef = AE7303EC1C93984C00AF5499 /* NSString+ANSI.m */; };
AE4B1E4D1C9C631B009540AD /* PluginManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 05DAE02C1833274100409786 /* PluginManager.m */; };
AE4B1E4E1C9C631B009540AD /* Plugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 059971951833394500EA6D8D /* Plugin.m */; };
AE4B1E4F1C9C631B009540AD /* ExecutablePlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = A281BDB4189066DE00C380A4 /* ExecutablePlugin.m */; };
AE4B1E501C9C632A009540AD /* PluginManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 05DAE02C1833274100409786 /* PluginManager.m */; };
AE4B1E511C9C632A009540AD /* Plugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 059971951833394500EA6D8D /* Plugin.m */; };
AE4B1E521C9C632A009540AD /* ExecutablePlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = A281BDB4189066DE00C380A4 /* ExecutablePlugin.m */; };
AE4B1E531C9C6351009540AD /* HTMLPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = A281BDB71890670800C380A4 /* HTMLPlugin.m */; };
AE4B1E541C9C6351009540AD /* NSUserDefaults+Settings.m in Sources */ = {isa = PBXBuildFile; fileRef = 05322A48183406E2004D9AFE /* NSUserDefaults+Settings.m */; };
AE4B1E551C9C6351009540AD /* NSString+ANSI.m in Sources */ = {isa = PBXBuildFile; fileRef = AE7303EC1C93984C00AF5499 /* NSString+ANSI.m */; };
AE4B1E561C9C6351009540AD /* NSString+Emojize.m in Sources */ = {isa = PBXBuildFile; fileRef = AE7303D81C935BDE00AF5499 /* NSString+Emojize.m */; };
AE4B1E571C9C6351009540AD /* AHProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D03BB21C3D95E600A64968 /* AHProxy.m */; };
AE4B1E581C9C6351009540AD /* AHProxySettings.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D03BB41C3D95E600A64968 /* AHProxySettings.m */; };
AE4B1E591C9C6351009540AD /* NSTask+useSystemProxies.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D03BB61C3D95E600A64968 /* NSTask+useSystemProxies.m */; };
AE4B1E5A1C9C6351009540AD /* DTConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A21581B9F0F10002539F7 /* DTConstants.m */; };
AE4B1E5B1C9C6351009540AD /* DTError.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A215A1B9F0F10002539F7 /* DTError.m */; };
AE4B1E5C1C9C6351009540AD /* DTTimePeriod.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A215C1B9F0F10002539F7 /* DTTimePeriod.m */; };
AE4B1E5D1C9C6351009540AD /* DTTimePeriodChain.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A215E1B9F0F10002539F7 /* DTTimePeriodChain.m */; };
AE4B1E5E1C9C6351009540AD /* DTTimePeriodCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A21601B9F0F10002539F7 /* DTTimePeriodCollection.m */; };
AE4B1E5F1C9C6351009540AD /* DTTimePeriodGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A21621B9F0F10002539F7 /* DTTimePeriodGroup.m */; };
AE4B1E601C9C6351009540AD /* NSDate+DateTools.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A21641B9F0F10002539F7 /* NSDate+DateTools.m */; };
AE4B1E611C9C6351009540AD /* STPrivilegedTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A21501B9F0BE6002539F7 /* STPrivilegedTask.m */; };
AE4B1E621C9C6351009540AD /* LaunchAtLoginController.m in Sources */ = {isa = PBXBuildFile; fileRef = 055819771834172E00B44B00 /* LaunchAtLoginController.m */; };
AE4B1E631C9C6351009540AD /* NSColor+Hex.m in Sources */ = {isa = PBXBuildFile; fileRef = A22AF328189F823E0011DFCD /* NSColor+Hex.m */; };
AE4B1E641C9C636A009540AD /* HTMLPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = A281BDB71890670800C380A4 /* HTMLPlugin.m */; };
AE4B1E651C9C636A009540AD /* NSUserDefaults+Settings.m in Sources */ = {isa = PBXBuildFile; fileRef = 05322A48183406E2004D9AFE /* NSUserDefaults+Settings.m */; };
AE4B1E661C9C636A009540AD /* NSString+ANSI.m in Sources */ = {isa = PBXBuildFile; fileRef = AE7303EC1C93984C00AF5499 /* NSString+ANSI.m */; };
AE4B1E671C9C636A009540AD /* NSString+Emojize.m in Sources */ = {isa = PBXBuildFile; fileRef = AE7303D81C935BDE00AF5499 /* NSString+Emojize.m */; };
AE4B1E681C9C636A009540AD /* AHProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D03BB21C3D95E600A64968 /* AHProxy.m */; };
AE4B1E691C9C636A009540AD /* AHProxySettings.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D03BB41C3D95E600A64968 /* AHProxySettings.m */; };
AE4B1E6A1C9C636A009540AD /* NSTask+useSystemProxies.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D03BB61C3D95E600A64968 /* NSTask+useSystemProxies.m */; };
AE4B1E6B1C9C636A009540AD /* DTConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A21581B9F0F10002539F7 /* DTConstants.m */; };
AE4B1E6C1C9C636A009540AD /* DTError.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A215A1B9F0F10002539F7 /* DTError.m */; };
AE4B1E6D1C9C636A009540AD /* DTTimePeriod.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A215C1B9F0F10002539F7 /* DTTimePeriod.m */; };
AE4B1E6E1C9C636A009540AD /* DTTimePeriodChain.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A215E1B9F0F10002539F7 /* DTTimePeriodChain.m */; };
AE4B1E6F1C9C636A009540AD /* DTTimePeriodCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A21601B9F0F10002539F7 /* DTTimePeriodCollection.m */; };
AE4B1E701C9C636A009540AD /* DTTimePeriodGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A21621B9F0F10002539F7 /* DTTimePeriodGroup.m */; };
AE4B1E711C9C636A009540AD /* NSDate+DateTools.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A21641B9F0F10002539F7 /* NSDate+DateTools.m */; };
AE4B1E721C9C636A009540AD /* STPrivilegedTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B9A21501B9F0BE6002539F7 /* STPrivilegedTask.m */; };
AE4B1E731C9C636A009540AD /* LaunchAtLoginController.m in Sources */ = {isa = PBXBuildFile; fileRef = 055819771834172E00B44B00 /* LaunchAtLoginController.m */; };
AE4B1E741C9C636A009540AD /* NSColor+Hex.m in Sources */ = {isa = PBXBuildFile; fileRef = A22AF328189F823E0011DFCD /* NSColor+Hex.m */; };
AE7303DB1C935BDE00AF5499 /* NSString+Emojize.m in Sources */ = {isa = PBXBuildFile; fileRef = AE7303D81C935BDE00AF5499 /* NSString+Emojize.m */; };
AE7303DD1C93721600AF5499 /* TestPlugins in Resources */ = {isa = PBXBuildFile; fileRef = AE7303DC1C93721600AF5499 /* TestPlugins */; };
AE7303E01C93848400AF5499 /* PluginManager+Test.m in Sources */ = {isa = PBXBuildFile; fileRef = AE7303DF1C93848400AF5499 /* PluginManager+Test.m */; };
AE7303ED1C93984C00AF5499 /* NSString+ANSI.m in Sources */ = {isa = PBXBuildFile; fileRef = AE7303EC1C93984C00AF5499 /* NSString+ANSI.m */; };
F8D03BB71C3D95E600A64968 /* AHProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D03BB21C3D95E600A64968 /* AHProxy.m */; };
F8D03BB81C3D95E600A64968 /* AHProxySettings.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D03BB41C3D95E600A64968 /* AHProxySettings.m */; };
F8D03BB91C3D95E600A64968 /* NSTask+useSystemProxies.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D03BB61C3D95E600A64968 /* NSTask+useSystemProxies.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
05DAE015183323DD00409786 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 05DADFE8183323DD00409786 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 05DADFEF183323DD00409786;
remoteInfo = BitBar;
};
36372DC01C9424DB0005EB32 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 05DADFE8183323DD00409786 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 36DCD8BC1C76027C004DE286;
remoteInfo = BitBarDistro;
};
36D0CDFE1D0AF009001AFB77 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 36D0CDF21D0AF009001AFB77 /* Sparkle.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 8DC2EF5B0486A6940098B216;
remoteInfo = Sparkle;
};
36D0CE001D0AF009001AFB77 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 36D0CDF21D0AF009001AFB77 /* Sparkle.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 61B5F90209C4CEE200B25A18;
remoteInfo = "Sparkle Test App";
};
36D0CE021D0AF009001AFB77 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 36D0CDF21D0AF009001AFB77 /* Sparkle.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 612279D90DB5470200AB99EA;
remoteInfo = "Sparkle Unit Tests";
};
36D0CE041D0AF009001AFB77 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 36D0CDF21D0AF009001AFB77 /* Sparkle.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 5D06E8D00FD68C7C005AE3F6;
remoteInfo = BinaryDelta;
};
36D0CE061D0AF009001AFB77 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 36D0CDF21D0AF009001AFB77 /* Sparkle.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 55C14BB7136EEF1500649790;
remoteInfo = Autoupdate;
};
36D0CE081D0AF009001AFB77 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 36D0CDF21D0AF009001AFB77 /* Sparkle.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 726B2B5D1C645FC900388755;
remoteInfo = "UI Tests";
};
36D0CE0C1D0AF012001AFB77 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 36D0CDF21D0AF009001AFB77 /* Sparkle.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = 8DC2EF4F0486A6940098B216;
remoteInfo = Sparkle;
};
36D0CE121D0AF019001AFB77 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 36D0CDF21D0AF009001AFB77 /* Sparkle.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = 8DC2EF4F0486A6940098B216;
remoteInfo = Sparkle;
};
3ACB54592561958E00407243 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 36D0CDF21D0AF009001AFB77 /* Sparkle.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 722954B41D04ADAF00ECF9CA;
remoteInfo = fileop;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
36D0CE0F1D0AF013001AFB77 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
36D0CE0B1D0AF012001AFB77 /* Sparkle.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
36D0CE151D0AF019001AFB77 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
36D0CE111D0AF019001AFB77 /* Sparkle.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
0531DCD81844070A007F0A96 /* App.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = App.xib; sourceTree = ""; };
05322A47183406E2004D9AFE /* NSUserDefaults+Settings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSUserDefaults+Settings.h"; sourceTree = ""; };
05322A48183406E2004D9AFE /* NSUserDefaults+Settings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSUserDefaults+Settings.m"; sourceTree = ""; };
055819761834172E00B44B00 /* LaunchAtLoginController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LaunchAtLoginController.h; sourceTree = ""; };
055819771834172E00B44B00 /* LaunchAtLoginController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LaunchAtLoginController.m; sourceTree = ""; };
05590ACE1C3E74C100352E77 /* CHANGELOG.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = ""; };
059971941833394500EA6D8D /* Plugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Plugin.h; sourceTree = ""; };
059971951833394500EA6D8D /* Plugin.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = Plugin.m; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
0599719718333DB300EA6D8D /* PluginTest.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PluginTest.m; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
05DADFF0183323DD00409786 /* BitBar.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BitBar.app; sourceTree = BUILT_PRODUCTS_DIR; };
05DADFFB183323DD00409786 /* BitBar-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "BitBar-Info.plist"; sourceTree = ""; };
05DAE006183323DD00409786 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = BitBar/AppDelegate.m; sourceTree = ""; };
05DAE011183323DD00409786 /* BitBarTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BitBarTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
05DAE019183323DD00409786 /* BitBarTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "BitBarTests-Info.plist"; sourceTree = ""; };
05DAE02B1833274100409786 /* PluginManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PluginManager.h; sourceTree = ""; };
05DAE02C1833274100409786 /* PluginManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PluginManager.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
05DAE02E1833276C00409786 /* PluginManagerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PluginManagerTest.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
05DB995B1C3D4B80008B5159 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
36372DD61C9424DB0005EB32 /* BitBarDistroTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BitBarDistroTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
36D0CDF21D0AF009001AFB77 /* Sparkle.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Sparkle.xcodeproj; path = Vendor/Sparkle/Sparkle.xcodeproj; sourceTree = SOURCE_ROOT; };
36DCD8D81C76027C004DE286 /* BitBarDistro.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BitBarDistro.app; sourceTree = BUILT_PRODUCTS_DIR; };
7B5D08F91BA8EF6300400886 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../../README.md; sourceTree = ""; };
7B9A214F1B9F0BE6002539F7 /* STPrivilegedTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STPrivilegedTask.h; path = Vendor/STPrivilegedTask/STPrivilegedTask.h; sourceTree = SOURCE_ROOT; };
7B9A21501B9F0BE6002539F7 /* STPrivilegedTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = STPrivilegedTask.m; path = Vendor/STPrivilegedTask/STPrivilegedTask.m; sourceTree = SOURCE_ROOT; };
7B9A21551B9F0F10002539F7 /* DateTools.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = DateTools.bundle; sourceTree = ""; };
7B9A21561B9F0F10002539F7 /* DateTools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DateTools.h; sourceTree = ""; };
7B9A21571B9F0F10002539F7 /* DTConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTConstants.h; sourceTree = ""; };
7B9A21581B9F0F10002539F7 /* DTConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTConstants.m; sourceTree = ""; };
7B9A21591B9F0F10002539F7 /* DTError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTError.h; sourceTree = ""; };
7B9A215A1B9F0F10002539F7 /* DTError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTError.m; sourceTree = ""; };
7B9A215B1B9F0F10002539F7 /* DTTimePeriod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTTimePeriod.h; sourceTree = ""; };
7B9A215C1B9F0F10002539F7 /* DTTimePeriod.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTTimePeriod.m; sourceTree = ""; };
7B9A215D1B9F0F10002539F7 /* DTTimePeriodChain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTTimePeriodChain.h; sourceTree = ""; };
7B9A215E1B9F0F10002539F7 /* DTTimePeriodChain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTTimePeriodChain.m; sourceTree = ""; };
7B9A215F1B9F0F10002539F7 /* DTTimePeriodCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTTimePeriodCollection.h; sourceTree = ""; };
7B9A21601B9F0F10002539F7 /* DTTimePeriodCollection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTTimePeriodCollection.m; sourceTree = ""; };
7B9A21611B9F0F10002539F7 /* DTTimePeriodGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTTimePeriodGroup.h; sourceTree = ""; };
7B9A21621B9F0F10002539F7 /* DTTimePeriodGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTTimePeriodGroup.m; sourceTree = ""; };
7B9A21631B9F0F10002539F7 /* NSDate+DateTools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+DateTools.h"; sourceTree = ""; };
7B9A21641B9F0F10002539F7 /* NSDate+DateTools.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+DateTools.m"; sourceTree = ""; };
A22AF327189F823E0011DFCD /* NSColor+Hex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSColor+Hex.h"; sourceTree = ""; };
A22AF328189F823E0011DFCD /* NSColor+Hex.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSColor+Hex.m"; sourceTree = ""; wrapsLines = 1; };
A281BDB3189066DE00C380A4 /* ExecutablePlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExecutablePlugin.h; sourceTree = ""; };
A281BDB4189066DE00C380A4 /* ExecutablePlugin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ExecutablePlugin.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
A281BDB61890670800C380A4 /* HTMLPlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLPlugin.h; sourceTree = ""; };
A281BDB71890670800C380A4 /* HTMLPlugin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = HTMLPlugin.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
AE7303D61C935BDE00AF5499 /* emojis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = emojis.h; sourceTree = ""; };
AE7303D71C935BDE00AF5499 /* NSString+Emojize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+Emojize.h"; sourceTree = ""; };
AE7303D81C935BDE00AF5499 /* NSString+Emojize.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+Emojize.m"; sourceTree = ""; };
AE7303DC1C93721600AF5499 /* TestPlugins */ = {isa = PBXFileReference; lastKnownFileType = folder; path = TestPlugins; sourceTree = ""; };
AE7303DE1C93848400AF5499 /* PluginManager+Test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "PluginManager+Test.h"; sourceTree = ""; };
AE7303DF1C93848400AF5499 /* PluginManager+Test.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "PluginManager+Test.m"; sourceTree = ""; };
AE7303EB1C93984C00AF5499 /* NSString+ANSI.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = "NSString+ANSI.h"; sourceTree = ""; tabWidth = 2; };
AE7303EC1C93984C00AF5499 /* NSString+ANSI.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = "NSString+ANSI.m"; sourceTree = ""; tabWidth = 2; };
F8D03BB11C3D95E600A64968 /* AHProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AHProxy.h; sourceTree = ""; };
F8D03BB21C3D95E600A64968 /* AHProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AHProxy.m; sourceTree = ""; };
F8D03BB31C3D95E600A64968 /* AHProxySettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AHProxySettings.h; sourceTree = ""; };
F8D03BB41C3D95E600A64968 /* AHProxySettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AHProxySettings.m; sourceTree = ""; };
F8D03BB51C3D95E600A64968 /* NSTask+useSystemProxies.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTask+useSystemProxies.h"; sourceTree = ""; };
F8D03BB61C3D95E600A64968 /* NSTask+useSystemProxies.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTask+useSystemProxies.m"; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
05DAE00E183323DD00409786 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
36372DD01C9424DB0005EB32 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
36D0CE0E1D0AF013001AFB77 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
36D0CE0A1D0AF012001AFB77 /* Sparkle.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
36D0CE141D0AF019001AFB77 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
36D0CE101D0AF018001AFB77 /* Sparkle.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
05322A46183406D7004D9AFE /* Settings */ = {
isa = PBXGroup;
children = (
05322A47183406E2004D9AFE /* NSUserDefaults+Settings.h */,
05322A48183406E2004D9AFE /* NSUserDefaults+Settings.m */,
);
name = Settings;
path = BitBar;
sourceTree = "";
};
055819751834171900B44B00 /* LaunchAtLoginController */ = {
isa = PBXGroup;
children = (
055819761834172E00B44B00 /* LaunchAtLoginController.h */,
055819771834172E00B44B00 /* LaunchAtLoginController.m */,
);
name = LaunchAtLoginController;
path = ../Vendor/LaunchAtLoginController;
sourceTree = "";
};
055EB10C183472C400FF83A6 /* Vendor */ = {
isa = PBXGroup;
children = (
36D0CDF21D0AF009001AFB77 /* Sparkle.xcodeproj */,
AE7303D51C935BDE00AF5499 /* NSStringEmojize */,
F8D03BB01C3D95E600A64968 /* AHProxySettings */,
7B9A21541B9F0F10002539F7 /* DateTools */,
7B9A214F1B9F0BE6002539F7 /* STPrivilegedTask.h */,
7B9A21501B9F0BE6002539F7 /* STPrivilegedTask.m */,
055819751834171900B44B00 /* LaunchAtLoginController */,
A22AF327189F823E0011DFCD /* NSColor+Hex.h */,
A22AF328189F823E0011DFCD /* NSColor+Hex.m */,
);
name = Vendor;
path = BitBar;
sourceTree = "";
};
05DADFE7183323DD00409786 = {
isa = PBXGroup;
children = (
05DAE006183323DD00409786 /* AppDelegate.m */,
05DAE0271833241D00409786 /* Plugins */,
05322A46183406D7004D9AFE /* Settings */,
AE3C16771C93B135009AF7CA /* Extensions */,
055EB10C183472C400FF83A6 /* Vendor */,
05DADFFA183323DD00409786 /* Supporting Files */,
05DAE017183323DD00409786 /* BitBarTests */,
05DADFF1183323DD00409786 /* Products */,
);
indentWidth = 2;
sourceTree = "";
tabWidth = 2;
};
05DADFF1183323DD00409786 /* Products */ = {
isa = PBXGroup;
children = (
05DADFF0183323DD00409786 /* BitBar.app */,
05DAE011183323DD00409786 /* BitBarTests.xctest */,
36DCD8D81C76027C004DE286 /* BitBarDistro.app */,
36372DD61C9424DB0005EB32 /* BitBarDistroTests.xctest */,
);
name = Products;
sourceTree = "";
};
05DADFFA183323DD00409786 /* Supporting Files */ = {
isa = PBXGroup;
children = (
05DB995B1C3D4B80008B5159 /* Images.xcassets */,
7B5D08F91BA8EF6300400886 /* README.md */,
05DADFFB183323DD00409786 /* BitBar-Info.plist */,
0531DCD81844070A007F0A96 /* App.xib */,
05590ACE1C3E74C100352E77 /* CHANGELOG.md */,
);
name = "Supporting Files";
path = BitBar;
sourceTree = "";
};
05DAE017183323DD00409786 /* BitBarTests */ = {
isa = PBXGroup;
children = (
AE7303DC1C93721600AF5499 /* TestPlugins */,
05DAE02E1833276C00409786 /* PluginManagerTest.m */,
0599719718333DB300EA6D8D /* PluginTest.m */,
AE4B1E4C1C9B7C4B009540AD /* Test Extensions */,
05DAE018183323DD00409786 /* Supporting Files */,
);
path = BitBarTests;
sourceTree = "";
};
05DAE018183323DD00409786 /* Supporting Files */ = {
isa = PBXGroup;
children = (
05DAE019183323DD00409786 /* BitBarTests-Info.plist */,
);
name = "Supporting Files";
sourceTree = "";
};
05DAE0271833241D00409786 /* Plugins */ = {
isa = PBXGroup;
children = (
05DAE02B1833274100409786 /* PluginManager.h */,
05DAE02C1833274100409786 /* PluginManager.m */,
059971941833394500EA6D8D /* Plugin.h */,
059971951833394500EA6D8D /* Plugin.m */,
A281BDB3189066DE00C380A4 /* ExecutablePlugin.h */,
A281BDB4189066DE00C380A4 /* ExecutablePlugin.m */,
A281BDB61890670800C380A4 /* HTMLPlugin.h */,
A281BDB71890670800C380A4 /* HTMLPlugin.m */,
);
name = Plugins;
path = BitBar;
sourceTree = "";
};
36D0CDF31D0AF009001AFB77 /* Products */ = {
isa = PBXGroup;
children = (
36D0CDFF1D0AF009001AFB77 /* Sparkle.framework */,
36D0CE011D0AF009001AFB77 /* Sparkle Test App.app */,
36D0CE031D0AF009001AFB77 /* Sparkle Unit Tests.xctest */,
36D0CE051D0AF009001AFB77 /* BinaryDelta */,
36D0CE071D0AF009001AFB77 /* Autoupdate.app */,
36D0CE091D0AF009001AFB77 /* UI Tests.xctest */,
3ACB545A2561958E00407243 /* fileop */,
);
name = Products;
sourceTree = "";
};
7B9A21541B9F0F10002539F7 /* DateTools */ = {
isa = PBXGroup;
children = (
7B9A21551B9F0F10002539F7 /* DateTools.bundle */,
7B9A21561B9F0F10002539F7 /* DateTools.h */,
7B9A21571B9F0F10002539F7 /* DTConstants.h */,
7B9A21581B9F0F10002539F7 /* DTConstants.m */,
7B9A21591B9F0F10002539F7 /* DTError.h */,
7B9A215A1B9F0F10002539F7 /* DTError.m */,
7B9A215B1B9F0F10002539F7 /* DTTimePeriod.h */,
7B9A215C1B9F0F10002539F7 /* DTTimePeriod.m */,
7B9A215D1B9F0F10002539F7 /* DTTimePeriodChain.h */,
7B9A215E1B9F0F10002539F7 /* DTTimePeriodChain.m */,
7B9A215F1B9F0F10002539F7 /* DTTimePeriodCollection.h */,
7B9A21601B9F0F10002539F7 /* DTTimePeriodCollection.m */,
7B9A21611B9F0F10002539F7 /* DTTimePeriodGroup.h */,
7B9A21621B9F0F10002539F7 /* DTTimePeriodGroup.m */,
7B9A21631B9F0F10002539F7 /* NSDate+DateTools.h */,
7B9A21641B9F0F10002539F7 /* NSDate+DateTools.m */,
);
name = DateTools;
path = Vendor/DateTools/DateTools;
sourceTree = SOURCE_ROOT;
};
AE3C16771C93B135009AF7CA /* Extensions */ = {
isa = PBXGroup;
children = (
AE7303EB1C93984C00AF5499 /* NSString+ANSI.h */,
AE7303EC1C93984C00AF5499 /* NSString+ANSI.m */,
);
name = Extensions;
path = BitBar;
sourceTree = "";
};
AE4B1E4C1C9B7C4B009540AD /* Test Extensions */ = {
isa = PBXGroup;
children = (
AE7303DE1C93848400AF5499 /* PluginManager+Test.h */,
AE7303DF1C93848400AF5499 /* PluginManager+Test.m */,
);
name = "Test Extensions";
sourceTree = "";
};
AE7303D51C935BDE00AF5499 /* NSStringEmojize */ = {
isa = PBXGroup;
children = (
AE7303D61C935BDE00AF5499 /* emojis.h */,
AE7303D71C935BDE00AF5499 /* NSString+Emojize.h */,
AE7303D81C935BDE00AF5499 /* NSString+Emojize.m */,
);
name = NSStringEmojize;
path = Vendor/NSStringEmojize/NSStringEmojize;
sourceTree = SOURCE_ROOT;
};
F8D03BB01C3D95E600A64968 /* AHProxySettings */ = {
isa = PBXGroup;
children = (
F8D03BB11C3D95E600A64968 /* AHProxy.h */,
F8D03BB21C3D95E600A64968 /* AHProxy.m */,
F8D03BB31C3D95E600A64968 /* AHProxySettings.h */,
F8D03BB41C3D95E600A64968 /* AHProxySettings.m */,
F8D03BB51C3D95E600A64968 /* NSTask+useSystemProxies.h */,
F8D03BB61C3D95E600A64968 /* NSTask+useSystemProxies.m */,
);
name = AHProxySettings;
path = Vendor/AHProxySettings/AHProxySettings;
sourceTree = SOURCE_ROOT;
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
05DADFEF183323DD00409786 /* BitBar */ = {
isa = PBXNativeTarget;
buildConfigurationList = 05DAE021183323DD00409786 /* Build configuration list for PBXNativeTarget "BitBar" */;
buildPhases = (
05DADFEC183323DD00409786 /* Sources */,
05DADFEE183323DD00409786 /* Resources */,
36D0CE0E1D0AF013001AFB77 /* Frameworks */,
36D0CE0F1D0AF013001AFB77 /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
36D0CE0D1D0AF012001AFB77 /* PBXTargetDependency */,
);
name = BitBar;
productName = BitBar;
productReference = 05DADFF0183323DD00409786 /* BitBar.app */;
productType = "com.apple.product-type.application";
};
05DAE010183323DD00409786 /* BitBarTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 05DAE024183323DD00409786 /* Build configuration list for PBXNativeTarget "BitBarTests" */;
buildPhases = (
05DAE00D183323DD00409786 /* Sources */,
05DAE00E183323DD00409786 /* Frameworks */,
05DAE00F183323DD00409786 /* Resources */,
);
buildRules = (
);
dependencies = (
05DAE016183323DD00409786 /* PBXTargetDependency */,
);
name = BitBarTests;
productName = BitBarTests;
productReference = 05DAE011183323DD00409786 /* BitBarTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
36372DBC1C9424DB0005EB32 /* BitBarDistroTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 36372DD31C9424DB0005EB32 /* Build configuration list for PBXNativeTarget "BitBarDistroTests" */;
buildPhases = (
36372DC11C9424DB0005EB32 /* Sources */,
36372DD01C9424DB0005EB32 /* Frameworks */,
36372DD11C9424DB0005EB32 /* Resources */,
);
buildRules = (
);
dependencies = (
36372DBF1C9424DB0005EB32 /* PBXTargetDependency */,
);
name = BitBarDistroTests;
productName = BitBarTests;
productReference = 36372DD61C9424DB0005EB32 /* BitBarDistroTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
36DCD8BC1C76027C004DE286 /* BitBarDistro */ = {
isa = PBXNativeTarget;
buildConfigurationList = 36DCD8D51C76027C004DE286 /* Build configuration list for PBXNativeTarget "BitBarDistro" */;
buildPhases = (
36DCD8BD1C76027C004DE286 /* Sources */,
36DCD8D11C76027C004DE286 /* Resources */,
36D0CE141D0AF019001AFB77 /* Frameworks */,
36D0CE151D0AF019001AFB77 /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
36D0CE131D0AF019001AFB77 /* PBXTargetDependency */,
);
name = BitBarDistro;
productName = BitBar;
productReference = 36DCD8D81C76027C004DE286 /* BitBarDistro.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
05DADFE8183323DD00409786 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0700;
ORGANIZATIONNAME = "Bit Bar";
TargetAttributes = {
05DADFEF183323DD00409786 = {
DevelopmentTeam = B3T8QSC4HG;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.Sandbox = {
enabled = 0;
};
};
};
05DAE010183323DD00409786 = {
TestTargetID = 05DADFEF183323DD00409786;
};
36372DBC1C9424DB0005EB32 = {
TestTargetID = 36DCD8BC1C76027C004DE286;
};
36DCD8BC1C76027C004DE286 = {
DevelopmentTeam = B3T8QSC4HG;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 05DADFEB183323DD00409786 /* Build configuration list for PBXProject "BitBar" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
Base,
);
mainGroup = 05DADFE7183323DD00409786;
productRefGroup = 05DADFF1183323DD00409786 /* Products */;
projectDirPath = "";
projectReferences = (
{
ProductGroup = 36D0CDF31D0AF009001AFB77 /* Products */;
ProjectRef = 36D0CDF21D0AF009001AFB77 /* Sparkle.xcodeproj */;
},
);
projectRoot = "";
targets = (
05DADFEF183323DD00409786 /* BitBar */,
05DAE010183323DD00409786 /* BitBarTests */,
36DCD8BC1C76027C004DE286 /* BitBarDistro */,
36372DBC1C9424DB0005EB32 /* BitBarDistroTests */,
);
};
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
36D0CDFF1D0AF009001AFB77 /* Sparkle.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework;
path = Sparkle.framework;
remoteRef = 36D0CDFE1D0AF009001AFB77 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
36D0CE011D0AF009001AFB77 /* Sparkle Test App.app */ = {
isa = PBXReferenceProxy;
fileType = wrapper.application;
path = "Sparkle Test App.app";
remoteRef = 36D0CE001D0AF009001AFB77 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
36D0CE031D0AF009001AFB77 /* Sparkle Unit Tests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = "Sparkle Unit Tests.xctest";
remoteRef = 36D0CE021D0AF009001AFB77 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
36D0CE051D0AF009001AFB77 /* BinaryDelta */ = {
isa = PBXReferenceProxy;
fileType = "compiled.mach-o.executable";
path = BinaryDelta;
remoteRef = 36D0CE041D0AF009001AFB77 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
36D0CE071D0AF009001AFB77 /* Autoupdate.app */ = {
isa = PBXReferenceProxy;
fileType = wrapper.application;
path = Autoupdate.app;
remoteRef = 36D0CE061D0AF009001AFB77 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
36D0CE091D0AF009001AFB77 /* UI Tests.xctest */ = {
isa = PBXReferenceProxy;
fileType = wrapper.cfbundle;
path = "UI Tests.xctest";
remoteRef = 36D0CE081D0AF009001AFB77 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
3ACB545A2561958E00407243 /* fileop */ = {
isa = PBXReferenceProxy;
fileType = "compiled.mach-o.executable";
path = fileop;
remoteRef = 3ACB54592561958E00407243 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
05DADFEE183323DD00409786 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0531DCD91844070A007F0A96 /* App.xib in Resources */,
05DB995C1C3D4B80008B5159 /* Images.xcassets in Resources */,
7B9A21651B9F0F10002539F7 /* DateTools.bundle in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
05DAE00F183323DD00409786 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
AE7303DD1C93721600AF5499 /* TestPlugins in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
36372DD11C9424DB0005EB32 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
36372DD21C9424DB0005EB32 /* TestPlugins in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
36DCD8D11C76027C004DE286 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
36DCD8D21C76027C004DE286 /* App.xib in Resources */,
36DCD8D31C76027C004DE286 /* Images.xcassets in Resources */,
36DCD8D41C76027C004DE286 /* DateTools.bundle in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
05DADFEC183323DD00409786 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
AE3C167A1C93F71B009AF7CA /* NSString+Emojize.m in Sources */,
F8D03BB71C3D95E600A64968 /* AHProxy.m in Sources */,
05DAE007183323DD00409786 /* AppDelegate.m in Sources */,
7B9A21661B9F0F10002539F7 /* DTConstants.m in Sources */,
A281BDB81890670800C380A4 /* HTMLPlugin.m in Sources */,
7B9A21531B9F0BE6002539F7 /* STPrivilegedTask.m in Sources */,
A281BDB5189066DE00C380A4 /* ExecutablePlugin.m in Sources */,
7B9A216B1B9F0F10002539F7 /* DTTimePeriodGroup.m in Sources */,
F8D03BB91C3D95E600A64968 /* NSTask+useSystemProxies.m in Sources */,
05DAE02D1833274100409786 /* PluginManager.m in Sources */,
7B9A21671B9F0F10002539F7 /* DTError.m in Sources */,
7B9A216A1B9F0F10002539F7 /* DTTimePeriodCollection.m in Sources */,
05322A49183406E2004D9AFE /* NSUserDefaults+Settings.m in Sources */,
7B9A216C1B9F0F10002539F7 /* NSDate+DateTools.m in Sources */,
A22AF329189F823E0011DFCD /* NSColor+Hex.m in Sources */,
059971961833394500EA6D8D /* Plugin.m in Sources */,
7B9A21691B9F0F10002539F7 /* DTTimePeriodChain.m in Sources */,
AE7303ED1C93984C00AF5499 /* NSString+ANSI.m in Sources */,
055819781834172E00B44B00 /* LaunchAtLoginController.m in Sources */,
F8D03BB81C3D95E600A64968 /* AHProxySettings.m in Sources */,
7B9A21681B9F0F10002539F7 /* DTTimePeriod.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
05DAE00D183323DD00409786 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
AE4B1E531C9C6351009540AD /* HTMLPlugin.m in Sources */,
AE4B1E541C9C6351009540AD /* NSUserDefaults+Settings.m in Sources */,
AE4B1E551C9C6351009540AD /* NSString+ANSI.m in Sources */,
AE4B1E561C9C6351009540AD /* NSString+Emojize.m in Sources */,
AE4B1E571C9C6351009540AD /* AHProxy.m in Sources */,
AE4B1E581C9C6351009540AD /* AHProxySettings.m in Sources */,
AE4B1E591C9C6351009540AD /* NSTask+useSystemProxies.m in Sources */,
AE4B1E5A1C9C6351009540AD /* DTConstants.m in Sources */,
AE4B1E5B1C9C6351009540AD /* DTError.m in Sources */,
AE4B1E5C1C9C6351009540AD /* DTTimePeriod.m in Sources */,
AE4B1E5D1C9C6351009540AD /* DTTimePeriodChain.m in Sources */,
AE4B1E5E1C9C6351009540AD /* DTTimePeriodCollection.m in Sources */,
AE4B1E5F1C9C6351009540AD /* DTTimePeriodGroup.m in Sources */,
AE4B1E601C9C6351009540AD /* NSDate+DateTools.m in Sources */,
AE4B1E611C9C6351009540AD /* STPrivilegedTask.m in Sources */,
AE4B1E621C9C6351009540AD /* LaunchAtLoginController.m in Sources */,
AE4B1E631C9C6351009540AD /* NSColor+Hex.m in Sources */,
AE4B1E4D1C9C631B009540AD /* PluginManager.m in Sources */,
AE4B1E4E1C9C631B009540AD /* Plugin.m in Sources */,
AE4B1E4F1C9C631B009540AD /* ExecutablePlugin.m in Sources */,
0599719818333DB300EA6D8D /* PluginTest.m in Sources */,
05DAE02F1833276C00409786 /* PluginManagerTest.m in Sources */,
AE7303E01C93848400AF5499 /* PluginManager+Test.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
36372DC11C9424DB0005EB32 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
AE4B1E641C9C636A009540AD /* HTMLPlugin.m in Sources */,
AE4B1E651C9C636A009540AD /* NSUserDefaults+Settings.m in Sources */,
AE4B1E661C9C636A009540AD /* NSString+ANSI.m in Sources */,
AE4B1E671C9C636A009540AD /* NSString+Emojize.m in Sources */,
AE4B1E681C9C636A009540AD /* AHProxy.m in Sources */,
AE4B1E691C9C636A009540AD /* AHProxySettings.m in Sources */,
AE4B1E6A1C9C636A009540AD /* NSTask+useSystemProxies.m in Sources */,
AE4B1E6B1C9C636A009540AD /* DTConstants.m in Sources */,
AE4B1E6C1C9C636A009540AD /* DTError.m in Sources */,
AE4B1E6D1C9C636A009540AD /* DTTimePeriod.m in Sources */,
AE4B1E6E1C9C636A009540AD /* DTTimePeriodChain.m in Sources */,
AE4B1E6F1C9C636A009540AD /* DTTimePeriodCollection.m in Sources */,
AE4B1E701C9C636A009540AD /* DTTimePeriodGroup.m in Sources */,
AE4B1E711C9C636A009540AD /* NSDate+DateTools.m in Sources */,
AE4B1E721C9C636A009540AD /* STPrivilegedTask.m in Sources */,
AE4B1E731C9C636A009540AD /* LaunchAtLoginController.m in Sources */,
AE4B1E741C9C636A009540AD /* NSColor+Hex.m in Sources */,
AE4B1E501C9C632A009540AD /* PluginManager.m in Sources */,
AE4B1E511C9C632A009540AD /* Plugin.m in Sources */,
AE4B1E521C9C632A009540AD /* ExecutablePlugin.m in Sources */,
36372DCC1C9424DB0005EB32 /* PluginTest.m in Sources */,
36372DCE1C9424DB0005EB32 /* PluginManagerTest.m in Sources */,
36372DCF1C9424DB0005EB32 /* PluginManager+Test.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
36DCD8BD1C76027C004DE286 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
36DCD8BE1C76027C004DE286 /* AHProxy.m in Sources */,
36DCD8BF1C76027C004DE286 /* AppDelegate.m in Sources */,
36DCD8C01C76027C004DE286 /* DTConstants.m in Sources */,
36DCD8C11C76027C004DE286 /* HTMLPlugin.m in Sources */,
36DCD8C21C76027C004DE286 /* STPrivilegedTask.m in Sources */,
36DCD8C31C76027C004DE286 /* ExecutablePlugin.m in Sources */,
36DCD8C41C76027C004DE286 /* DTTimePeriodGroup.m in Sources */,
36DCD8C51C76027C004DE286 /* NSTask+useSystemProxies.m in Sources */,
36DCD8C61C76027C004DE286 /* PluginManager.m in Sources */,
36DCD8C71C76027C004DE286 /* DTError.m in Sources */,
36DCD8C81C76027C004DE286 /* DTTimePeriodCollection.m in Sources */,
36DCD8C91C76027C004DE286 /* NSUserDefaults+Settings.m in Sources */,
36DCD8CA1C76027C004DE286 /* NSDate+DateTools.m in Sources */,
AE4B1E391C9B2B0F009540AD /* NSString+ANSI.m in Sources */,
36DCD8CB1C76027C004DE286 /* NSColor+Hex.m in Sources */,
36DCD8CC1C76027C004DE286 /* Plugin.m in Sources */,
36DCD8CD1C76027C004DE286 /* DTTimePeriodChain.m in Sources */,
36DCD8CE1C76027C004DE286 /* LaunchAtLoginController.m in Sources */,
36DCD8CF1C76027C004DE286 /* AHProxySettings.m in Sources */,
36DCD8D01C76027C004DE286 /* DTTimePeriod.m in Sources */,
AE7303DB1C935BDE00AF5499 /* NSString+Emojize.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
05DAE016183323DD00409786 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 05DADFEF183323DD00409786 /* BitBar */;
targetProxy = 05DAE015183323DD00409786 /* PBXContainerItemProxy */;
};
36372DBF1C9424DB0005EB32 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 36DCD8BC1C76027C004DE286 /* BitBarDistro */;
targetProxy = 36372DC01C9424DB0005EB32 /* PBXContainerItemProxy */;
};
36D0CE0D1D0AF012001AFB77 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = Sparkle;
targetProxy = 36D0CE0C1D0AF012001AFB77 /* PBXContainerItemProxy */;
};
36D0CE131D0AF019001AFB77 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = Sparkle;
targetProxy = 36D0CE121D0AF019001AFB77 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
05DAE01F183323DD00409786 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = c11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 11.0;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
};
name = Debug;
};
05DAE020183323DD00409786 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
GCC_C_LANGUAGE_STANDARD = c11;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 11.0;
SDKROOT = macosx;
};
name = Release;
};
05DAE022183323DD00409786 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1.10.2;
DEVELOPMENT_TEAM = B3T8QSC4HG;
HEADER_SEARCH_PATHS = "./Vendor/**";
INFOPLIST_FILE = "BitBar/BitBar-Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.9;
MARKETING_VERSION = 1.10.2;
PRODUCT_BUNDLE_IDENTIFIER = "com.matryer.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
WRAPPER_EXTENSION = app;
};
name = Debug;
};
05DAE023183323DD00409786 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1.10.2;
DEVELOPMENT_TEAM = B3T8QSC4HG;
HEADER_SEARCH_PATHS = "./Vendor/**";
INFOPLIST_FILE = "BitBar/BitBar-Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.9;
MARKETING_VERSION = 1.10.2;
PRODUCT_BUNDLE_IDENTIFIER = "com.matryer.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
WRAPPER_EXTENSION = app;
};
name = Release;
};
05DAE025183323DD00409786 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
);
GCC_PRECOMPILE_PREFIX_HEADER = NO;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = "BitBarTests/BitBarTests-Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "com.bitbarapp.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/BitBar.app/Contents/MacOS/BitBar";
WRAPPER_EXTENSION = xctest;
};
name = Debug;
};
05DAE026183323DD00409786 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
);
GCC_PRECOMPILE_PREFIX_HEADER = NO;
INFOPLIST_FILE = "BitBarTests/BitBarTests-Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "com.bitbarapp.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/BitBar.app/Contents/MacOS/BitBar";
WRAPPER_EXTENSION = xctest;
};
name = Release;
};
36372DD41C9424DB0005EB32 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
);
GCC_PRECOMPILE_PREFIX_HEADER = NO;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
DISTRO,
);
INFOPLIST_FILE = "BitBarTests/BitBarTests-Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "com.bitbarapp.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/BitBarDistro.app/Contents/MacOS/BitBarDistro";
WRAPPER_EXTENSION = xctest;
};
name = Debug;
};
36372DD51C9424DB0005EB32 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
);
GCC_PRECOMPILE_PREFIX_HEADER = NO;
GCC_PREPROCESSOR_DEFINITIONS = DISTRO;
INFOPLIST_FILE = "BitBarTests/BitBarTests-Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "com.bitbarapp.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/BitBarDistro.app/Contents/MacOS/BitBarDistro";
WRAPPER_EXTENSION = xctest;
};
name = Release;
};
36DCD8D61C76027C004DE286 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1.10.2;
DEVELOPMENT_TEAM = B3T8QSC4HG;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
DISTRO,
);
INFOPLIST_FILE = "$(SRCROOT)/BitBar/BitBar-Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.9;
MARKETING_VERSION = 1.10.2;
PRODUCT_BUNDLE_IDENTIFIER = "com.matryer.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
WRAPPER_EXTENSION = app;
};
name = Debug;
};
36DCD8D71C76027C004DE286 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1.10.2;
DEVELOPMENT_TEAM = B3T8QSC4HG;
GCC_PREPROCESSOR_DEFINITIONS = DISTRO;
INFOPLIST_FILE = "$(SRCROOT)/BitBar/BitBar-Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.9;
MARKETING_VERSION = 1.10.2;
PRODUCT_BUNDLE_IDENTIFIER = "com.matryer.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
WRAPPER_EXTENSION = app;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
05DADFEB183323DD00409786 /* Build configuration list for PBXProject "BitBar" */ = {
isa = XCConfigurationList;
buildConfigurations = (
05DAE01F183323DD00409786 /* Debug */,
05DAE020183323DD00409786 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
05DAE021183323DD00409786 /* Build configuration list for PBXNativeTarget "BitBar" */ = {
isa = XCConfigurationList;
buildConfigurations = (
05DAE022183323DD00409786 /* Debug */,
05DAE023183323DD00409786 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
05DAE024183323DD00409786 /* Build configuration list for PBXNativeTarget "BitBarTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
05DAE025183323DD00409786 /* Debug */,
05DAE026183323DD00409786 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
36372DD31C9424DB0005EB32 /* Build configuration list for PBXNativeTarget "BitBarDistroTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
36372DD41C9424DB0005EB32 /* Debug */,
36372DD51C9424DB0005EB32 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
36DCD8D51C76027C004DE286 /* Build configuration list for PBXNativeTarget "BitBarDistro" */ = {
isa = XCConfigurationList;
buildConfigurations = (
36DCD8D61C76027C004DE286 /* Debug */,
36DCD8D71C76027C004DE286 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 05DADFE8183323DD00409786 /* Project object */;
}
================================================
FILE: archive/bitbar/App/BitBar.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: archive/bitbar/App/BitBar.xcodeproj/project.xcworkspace/xcshareddata/BitBar.xccheckout
================================================
IDESourceControlProjectFavoriteDictionaryKey
IDESourceControlProjectIdentifier
B2EB30C0-666C-46EA-85F2-0586829722B1
IDESourceControlProjectName
BitBar
IDESourceControlProjectOriginsDictionary
300A25E6089E8365F1B9BCC0BF644BF304850FDB
https://github.com/kamenevn/bitbar.git
IDESourceControlProjectPath
App/BitBar.xcodeproj
IDESourceControlProjectRelativeInstallPathDictionary
300A25E6089E8365F1B9BCC0BF644BF304850FDB
../../..
IDESourceControlProjectURL
https://github.com/kamenevn/bitbar.git
IDESourceControlProjectVersion
111
IDESourceControlProjectWCCIdentifier
300A25E6089E8365F1B9BCC0BF644BF304850FDB
IDESourceControlProjectWCConfigurations
IDESourceControlRepositoryExtensionIdentifierKey
public.vcs.git
IDESourceControlWCCIdentifierKey
300A25E6089E8365F1B9BCC0BF644BF304850FDB
IDESourceControlWCCName
bitbar
================================================
FILE: archive/bitbar/App/BitBar.xcodeproj/project.xcworkspace/xcshareddata/BitBar.xcscmblueprint
================================================
{
"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "300A25E6089E8365F1B9BCC0BF644BF304850FDB",
"DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
},
"DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
"C0AF55779579B522417152BFAB32AD2A49AFBDFE" : 0,
"EF1CF5E1F342919DE309B5C9DAEDDCF1D12D0402" : 0,
"4FA437A61B0C4384CD084682AFD40F7D2624731D" : 0,
"EFCDA5DAAD3299C621AB4AD8A1985311413BE697" : 0,
"5A18CC4105103F3DCAAD74EC93EFD3FF8BB5508A" : 0,
"F8622BA04EBD09F8BA8DC9C0C199149407552BFA" : 0,
"300A25E6089E8365F1B9BCC0BF644BF304850FDB" : 0
},
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "B2EB30C0-666C-46EA-85F2-0586829722B1",
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
"C0AF55779579B522417152BFAB32AD2A49AFBDFE" : "bitbar\/App\/Vendor\/AHProxySettings\/",
"EF1CF5E1F342919DE309B5C9DAEDDCF1D12D0402" : "bitbar\/App\/Vendor\/Sparkle\/",
"4FA437A61B0C4384CD084682AFD40F7D2624731D" : "bitbar\/App\/Vendor\/LaunchAtLoginController\/",
"EFCDA5DAAD3299C621AB4AD8A1985311413BE697" : "bitbar\/App\/Vendor\/NSStringEmojize\/",
"5A18CC4105103F3DCAAD74EC93EFD3FF8BB5508A" : "bitbar\/App\/Vendor\/STPrivilegedTask\/",
"F8622BA04EBD09F8BA8DC9C0C199149407552BFA" : "bitbar\/App\/Vendor\/DateTools\/",
"300A25E6089E8365F1B9BCC0BF644BF304850FDB" : "bitbar"
},
"DVTSourceControlWorkspaceBlueprintNameKey" : "BitBar",
"DVTSourceControlWorkspaceBlueprintVersion" : 204,
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "App\/BitBar.xcodeproj",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/kamenevn\/bitbar.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "300A25E6089E8365F1B9BCC0BF644BF304850FDB"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/biocross\/LaunchAtLoginController--with-ARC-.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "4FA437A61B0C4384CD084682AFD40F7D2624731D"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/sveinbjornt\/STPrivilegedTask.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "5A18CC4105103F3DCAAD74EC93EFD3FF8BB5508A"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/eahrold\/AHProxySettings.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "C0AF55779579B522417152BFAB32AD2A49AFBDFE"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/sparkle-project\/Sparkle.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "EF1CF5E1F342919DE309B5C9DAEDDCF1D12D0402"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/diy\/NSStringEmojize.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "EFCDA5DAAD3299C621AB4AD8A1985311413BE697"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/MatthewYork\/DateTools.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "F8622BA04EBD09F8BA8DC9C0C199149407552BFA"
}
]
}
================================================
FILE: archive/bitbar/App/BitBar.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
IDEDidComputeMac32BitWarning
================================================
FILE: archive/bitbar/App/BitBar.xcodeproj/xcshareddata/xcschemes/BitBar.xcscheme
================================================
================================================
FILE: archive/bitbar/App/BitBar.xcodeproj/xcshareddata/xcschemes/BitBarDistro.xcscheme
================================================
================================================
FILE: archive/bitbar/App/BitBarTests/BitBarTests-Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleExecutable
${EXECUTABLE_NAME}
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundlePackageType
BNDL
CFBundleShortVersionString
1.0
CFBundleSignature
????
CFBundleVersion
1
LSUIElement
================================================
FILE: archive/bitbar/App/BitBarTests/PluginManager+Test.h
================================================
//
// PluginManager+Test.h
// BitBar
//
// Created by Kent Karlsson on 3/11/16.
// Copyright © 2016 Bit Bar. All rights reserved.
//
#import
#import "PluginManager.h"
@interface PluginManager (Test)
+ (NSString*)pluginPath;
+ (PluginManager*)testManager;
@end
================================================
FILE: archive/bitbar/App/BitBarTests/PluginManager+Test.m
================================================
//
// PluginManager+Test.m
// BitBar
//
// Created by Kent Karlsson on 3/11/16.
// Copyright © 2016 Bit Bar. All rights reserved.
//
#import "PluginManager+Test.h"
// This class is just here so that we can get the path to the test bundle
@interface BBTestClass : NSObject
+ (NSString*)pluginPath;
@end
@implementation BBTestClass
+ (NSString*)pluginPath {
return [[[NSBundle bundleForClass:[self class]] resourcePath] stringByAppendingPathComponent:@"TestPlugins"];
}
@end
@implementation PluginManager (Test)
+ (NSString*)pluginPath {
return [BBTestClass pluginPath];
}
+ (PluginManager*)testManager {
id delegate = [NSApplication sharedApplication].delegate;
return [delegate valueForKey:@"pluginManager"];
}
@end
================================================
FILE: archive/bitbar/App/BitBarTests/PluginManagerTest.m
================================================
//
// PluginManagerTest.m
// BitBar
//
// Created by Mat Ryer on 11/12/13.
// Copyright (c) 2013 Bit Bar. All rights reserved.
//
#import
#import "PluginManager+Test.h"
#import "Plugin.h"
@interface PluginManagerTest : XCTestCase
@end
@implementation PluginManagerTest
- (void)testInit
{
PluginManager *manager = [PluginManager testManager];
XCTAssert([manager.path isEqualToString:[PluginManager pluginPath]]);
XCTAssertNotNil(manager.path);
}
- (void)testPluginFiles {
PluginManager *manager = [PluginManager testManager];
NSArray *pluginFiles = manager.plugins;
XCTAssertEqual((NSUInteger)3, [pluginFiles count], @"pluginFiles count");
}
- (void)testPlugins {
PluginManager *manager = [PluginManager testManager];
NSArray *plugins = manager.plugins;
XCTAssertEqual((NSUInteger)3, [plugins count], @"plugins count");
Plugin *one = [plugins objectAtIndex:0];
XCTAssertNotNil(one, @"one shouldn't be nil");
XCTAssertEqual(manager, one.manager, @"manager");
XCTAssert([one.name isEqualToString:@"one.10s.sh"], @"name");
XCTAssert([one.path isEqualToString:[[PluginManager pluginPath] stringByAppendingPathComponent:@"one.10s.sh"]], @"path");
}
- (void)testStatusBar {
PluginManager *manager = [PluginManager testManager];
NSStatusBar *statusBar = manager.statusBar;
XCTAssertNotNil(statusBar, @"statusBar");
XCTAssertEqual([NSStatusBar systemStatusBar], statusBar, @"statusBar should default to system one");
// set on explicitly
NSStatusBar *newBar = NSStatusBar.new;
manager.statusBar = newBar;
XCTAssertEqual(newBar, manager.statusBar);
}
@end
================================================
FILE: archive/bitbar/App/BitBarTests/PluginTest.m
================================================
//
// PluginTest.m
// BitBar
//
// Created by Mat Ryer on 11/12/13.
// Copyright (c) 2013 Bit Bar. All rights reserved.
//
#import
#import "ExecutablePlugin.h"
#import "PluginManager+Test.h"
@interface PluginTest : XCTestCase
@end
@implementation PluginTest
- (void)testInitWithManager {
PluginManager *manager = [PluginManager testManager];
XCTAssertNotNil(manager);
Plugin *p = [Plugin.alloc initWithManager:manager];
XCTAssertNotNil(p);
XCTAssertEqual(p.manager, manager);
XCTAssertEqual((NSInteger)-1, p.currentLine);
XCTAssertEqual((NSInteger)5, p.cycleLinesIntervalSeconds);
}
- (void)testStatusItem {
PluginManager *manager = [PluginManager testManager];
Plugin *p = [Plugin.alloc initWithManager:manager];
NSStatusItem *item = p.statusItem;
XCTAssertNotNil(item, @"item nil?");
XCTAssertEqual((CGFloat)NSVariableStatusItemLength, item.length, @"length == NSVariableStatusItemLength");
// make sure it has a menu
XCTAssertNotNil(item.menu, @"menu");
}
- (void)testExample
{
PluginManager *manager = [PluginManager testManager];
Plugin *p = [Plugin.alloc initWithManager:manager];
p.name = @"name.10s.sh";
p.refreshIntervalSeconds = nil;
XCTAssertEqual((double)10, [p.refreshIntervalSeconds doubleValue], @"10s");
p.name = @"name.10m.sh";
p.refreshIntervalSeconds = nil;
XCTAssertEqual((double)(10*60), [p.refreshIntervalSeconds doubleValue], @"10m");
p.name = @"name.10h.sh";
p.refreshIntervalSeconds = nil;
XCTAssertEqual((double)(10*60*60), [p.refreshIntervalSeconds doubleValue], @"10h");
p.name = @"name.10d.sh";
p.refreshIntervalSeconds = nil;
XCTAssertEqual((double)(10*60*60*24), [p.refreshIntervalSeconds doubleValue], @"10d");
p.name = @"name.10S.sh";
p.refreshIntervalSeconds = nil;
XCTAssertEqual((double)10, [p.refreshIntervalSeconds doubleValue], @"10S");
p.name = @"name.10M.sh";
p.refreshIntervalSeconds = nil;
XCTAssertEqual((double)(10*60), [p.refreshIntervalSeconds doubleValue], @"10M");
p.name = @"name.10H.sh";
p.refreshIntervalSeconds = nil;
XCTAssertEqual((double)(10*60*60), [p.refreshIntervalSeconds doubleValue], @"10H");
p.name = @"name.10D.sh";
p.refreshIntervalSeconds = nil;
XCTAssertEqual((double)(10*60*60*24), [p.refreshIntervalSeconds doubleValue], @"10D");
// and some failures
p.name = @"name.10.sh";
p.refreshIntervalSeconds = nil;
XCTAssertEqual((double)(60), [p.refreshIntervalSeconds doubleValue], @"10");
p.name = @"name.sh";
p.refreshIntervalSeconds = nil;
XCTAssertEqual((double)(60), [p.refreshIntervalSeconds doubleValue], @"name.sh");
p.name = @"name.bollocks.sh";
p.refreshIntervalSeconds = nil;
XCTAssertEqual((double)(60), [p.refreshIntervalSeconds doubleValue], @"name.sh");
}
- (void)testRefreshContentByExecutingCommandSuccess {
PluginManager *manager = [PluginManager testManager];
ExecutablePlugin *p = [ExecutablePlugin.alloc initWithManager:manager];
p.name = @"one.10s.sh";
p.path = [[PluginManager pluginPath] stringByAppendingPathComponent:p.name];
XCTAssertEqual(YES, [p refreshContentByExecutingCommand]);
XCTAssert([p.content isEqualToString:@"This is just a test.\n"], @"Content");
XCTAssert([[p allContent] isEqualToString:@"This is just a test.\n"], @"all content");
XCTAssertEqual(NO, p.lastCommandWasError);
p.name = @"two.5m.sh";
p.path = [[PluginManager pluginPath] stringByAppendingPathComponent:p.name];
XCTAssertEqual(NO, [p refreshContentByExecutingCommand]);
XCTAssert([p.content isEqualToString:@""], @"content");
XCTAssert([p.allContent isEqualToString:@"⚠️\n---\nSomething went tits up."], @"all content");
XCTAssertEqual(YES, p.lastCommandWasError);
}
- (void)testRefreshContentByExecutingCommandError {
PluginManager *manager = [PluginManager testManager];
ExecutablePlugin *p = [ExecutablePlugin.alloc initWithManager:manager];
p.name = @"two.5m.sh";
p.path = [[PluginManager pluginPath] stringByAppendingPathComponent:p.name];
XCTAssertEqual(NO, [p refreshContentByExecutingCommand]);
XCTAssert([p.errorContent isEqualToString:@"Something went tits up."], @"Error content");
XCTAssert([p.allContent isEqualToString:@"⚠️\n---\nSomething went tits up."], @"all content");
XCTAssertEqual(YES, p.lastCommandWasError);
p.name = @"one.10s.sh";
p.path = [[PluginManager pluginPath] stringByAppendingPathComponent:p.name];
XCTAssertEqual(YES, [p refreshContentByExecutingCommand]);
XCTAssert([p.errorContent isEqualToString:@""], @"Error content");
XCTAssert([p.allContent isEqualToString:@"This is just a test.\n"], @"all content");
XCTAssertEqual(NO, p.lastCommandWasError);
}
- (void)testContentLines {
PluginManager *manager = [PluginManager testManager];
Plugin *p = [Plugin.alloc initWithManager:manager];
p.content = @"---\nHello\nWorld\nOf\nBitBar";
NSArray *lines = p.allContentLines;
XCTAssertEqual((NSUInteger)4, lines.count);
XCTAssert([lines[0] isEqualToString:@"Hello"]);
XCTAssert([lines[1] isEqualToString:@"World"]);
XCTAssert([lines[2] isEqualToString:@"Of"]);
XCTAssert([lines[3] isEqualToString:@"BitBar"]);
p.content = @"---\n Hello \t \n\tWorld\t\n Of \n BitBar";
[p contentHasChanged];
lines = p.allContentLines;
XCTAssertEqual((NSUInteger)4, lines.count);
XCTAssert([lines[0] isEqualToString:@" Hello \t "]);
XCTAssert([lines[1] isEqualToString:@"\tWorld\t"]);
XCTAssert([lines[2] isEqualToString:@" Of "]);
XCTAssert([lines[3] isEqualToString:@" BitBar"]);
p.content = @"---\n\n\n Hello \t \n\t\n\n\nWorld\t\n\n\n\n Of \n BitBar";
[p contentHasChanged];
lines = p.allContentLines;
XCTAssertEqual((NSUInteger)4, lines.count);
XCTAssert([lines[0] isEqualToString:@" Hello \t "]);
XCTAssert([lines[1] isEqualToString:@"World\t"]);
XCTAssert([lines[2] isEqualToString:@" Of "]);
XCTAssert([lines[3] isEqualToString:@" BitBar"]);
p.content = @"---\n\n\n Hello \t \n\t\nWorld\n\n---\nThe World\t\n\n\n\n Of \n BitBar";
[p contentHasChanged];
lines = p.allContentLines;
XCTAssertEqual((NSUInteger)6, lines.count);
XCTAssert([lines[0] isEqualToString:@" Hello \t "]);
XCTAssert([lines[1] isEqualToString:@"World"]);
XCTAssert([lines[2] isEqualToString:@"---"]);
XCTAssert([lines[3] isEqualToString:@"The World\t"]);
XCTAssert([lines[4] isEqualToString:@" Of "]);
XCTAssert([lines[5] isEqualToString:@" BitBar"]);
}
- (void)testIsMultiline {
PluginManager *manager = [PluginManager testManager];
Plugin *p = [Plugin.alloc initWithManager:manager];
p.content = @"Hello\nWorld\nOf\nBitBar";
XCTAssertEqual(YES, p.isMultiline);
p.content = @"One line mate";
XCTAssertEqual(NO, p.isMultiline);
}
- (void)testRefresh {
PluginManager *manager = [PluginManager testManager];
ExecutablePlugin *p = [ExecutablePlugin.alloc initWithManager:manager];
p.name = @"three.7d.sh";
p.path = [[PluginManager pluginPath] stringByAppendingPathComponent:p.name];
XCTAssertEqual(YES, [p refresh]);
[self keyValueObservingExpectationForObject:p keyPath:@"currentLine" expectedValue:0];
[self waitForExpectationsWithTimeout:5 handler:^(NSError * _Nullable error) {
XCTAssert([p.statusItem.title isEqualToString:@"line 1"]);
}];
}
- (void)testCycleLinesAndCurrentLine {
PluginManager *manager = [PluginManager testManager];
ExecutablePlugin *p = [ExecutablePlugin.alloc initWithManager:manager];
p.name = @"three.7d.sh";
p.path = [[PluginManager pluginPath] stringByAppendingPathComponent:p.name];
XCTAssertEqual((NSInteger)-1, p.currentLine);
[p refresh];
[self keyValueObservingExpectationForObject:p keyPath:@"currentLine" expectedValue:0];
[self waitForExpectationsWithTimeout:5 handler:^(NSError * _Nullable error) {
XCTAssertEqual((NSInteger)0, p.currentLine);
XCTAssert([p.statusItem.title isEqualToString:@"line 1"]);
[p cycleLines];
XCTAssertEqual((NSInteger)1, p.currentLine);
XCTAssert([p.statusItem.title isEqualToString:@"line 2"]);
[p cycleLines];
XCTAssertEqual((NSInteger)2, p.currentLine);
XCTAssert([p.statusItem.title isEqualToString:@"line 3"]);
[p cycleLines];
XCTAssertEqual((NSInteger)0, p.currentLine);
XCTAssert([p.statusItem.title isEqualToString:@"line 1"]);
[p cycleLines];
XCTAssertEqual((NSInteger)1, p.currentLine);
XCTAssert([p.statusItem.title isEqualToString:@"line 2"]);
[p cycleLines];
XCTAssertEqual((NSInteger)2, p.currentLine);
XCTAssert([p.statusItem.title isEqualToString:@"line 3"]);
}];
}
- (void)testRebuildMenuForStatusItem {
PluginManager *manager = [PluginManager testManager];
ExecutablePlugin *p = [ExecutablePlugin.alloc initWithManager:manager];
p.name = @"three.7d.sh";
p.path = [[PluginManager pluginPath] stringByAppendingPathComponent:p.name];
[p refreshContentByExecutingCommand];
[p rebuildMenuForStatusItem:p.statusItem];
NSUInteger itemCount = 3;
#ifdef DISTRO
itemCount += 2;
#else
itemCount += 3;
#endif
XCTAssertEqual(itemCount, [[p.statusItem.menu itemArray] count]);
}
- (void)testParameterANSI {
PluginManager *manager = [PluginManager testManager];
Plugin *p = [Plugin.alloc initWithManager:manager];
NSMenuItem* item;
NSString* helloWorld = @"\033[1;31mH\033[0mello \033[32mW\033[0morld";
// test disabling ansi parsing
item = [p buildMenuItemForLine:[NSString stringWithFormat:@"%@ | ansi=false", helloWorld]];
XCTAssert([item.title isEqualToString:helloWorld]); // unchanged
// test foreground and resetting
item = [p buildMenuItemForLine:[NSString stringWithFormat:@"%@", helloWorld]];
XCTAssertEqual(item.title.length, 11);
NSDictionary *hAttr, *wAttr, *nAttr;
hAttr = [item.attributedTitle attributesAtIndex:0 effectiveRange:nil]; // H
nAttr = [item.attributedTitle attributesAtIndex:1 effectiveRange:nil]; // space
wAttr = [item.attributedTitle attributesAtIndex:6 effectiveRange:nil]; // W
XCTAssertNotEqual(hAttr[NSForegroundColorAttributeName], wAttr[NSForegroundColorAttributeName]); // different colors
XCTAssertNil(nAttr[NSForegroundColorAttributeName]); // no color
// test background, resetting and that font isn't touched
item = [p buildMenuItemForLine:@"a\033[40mb\033[0mc | font=courier"];
NSDictionary *attr;
attr = [item.attributedTitle attributesAtIndex:0 effectiveRange:nil]; // a, no background, font courier
XCTAssertNil(attr[NSBackgroundColorAttributeName]);
XCTAssert([[(NSFont*)attr[NSFontAttributeName] fontName] isEqualToString:@"Courier"]);
attr = [item.attributedTitle attributesAtIndex:1 effectiveRange:nil]; // b, has background, font courier
XCTAssertNotNil(attr[NSBackgroundColorAttributeName]);
XCTAssert([[(NSFont*)attr[NSFontAttributeName] fontName] isEqualToString:@"Courier"]);
attr = [item.attributedTitle attributesAtIndex:2 effectiveRange:nil]; // c, no background, font courier
XCTAssertNil(attr[NSBackgroundColorAttributeName]);
XCTAssert([[(NSFont*)attr[NSFontAttributeName] fontName] isEqualToString:@"Courier"]);
}
- (void)testEmoji {
PluginManager *manager = [PluginManager testManager];
Plugin *p = [Plugin.alloc initWithManager:manager];
p.content = @":dog:\n:dog: | emojize=false\n:made_up:\n";
[p rebuildMenuForStatusItem:p.statusItem];
NSArray* items = p.statusItem.menu.itemArray;
XCTAssertEqual(((NSMenuItem*)items[0]).title.length, 2); // should parse (dog is 2 UTF-16 characters)
XCTAssertEqual(((NSMenuItem*)items[1]).title.length, 5); // should not
XCTAssertEqual(((NSMenuItem*)items[2]).title.length, 9); // should not
}
- (void)testSubmenus {
PluginManager *manager = [PluginManager testManager];
Plugin *p = [[Plugin alloc] initWithManager:manager];
NSString *item = @"Main menu";
NSString *subItem = @"Sub menu";
NSString *subItem2 = @"Sub menu item two";
NSString *subItem2Sub = @"Sub, sub, menu item";
p.content = [NSString stringWithFormat:@"---\n%@\n--%@\n-----\n--%@\n----%@", item, subItem, subItem2, subItem2Sub];
[p rebuildMenuForStatusItem:p.statusItem];
NSArray *items = p.statusItem.menu.itemArray;
XCTAssertEqualObjects(items[0].title, item);
items = items[0].submenu.itemArray;
XCTAssertEqual(items.count, 3);
XCTAssertEqualObjects(items[0].title, subItem);
XCTAssertNil(items[0].submenu);
XCTAssertTrue(items[1].separatorItem);
XCTAssertEqualObjects(items[2].title, subItem2);
XCTAssertEqual(items[2].submenu.itemArray.count, 1);
XCTAssertEqualObjects(items[2].submenu.itemArray[0].title, subItem2Sub);
}
- (void)testStatusItemAction {
PluginManager *manager = [PluginManager testManager];
Plugin *p = [[Plugin alloc] initWithManager:manager];
p.content = @"No action\n|href=\n|bash=\n|refresh=";
for (NSUInteger i = 0; i < p.titleLines.count + 1; i++) {
[p cycleLines];
NSUInteger currentLine = i % p.titleLines.count;
XCTAssertEqual(p.currentLine, currentLine);
if (currentLine == 0) {
XCTAssertNotNil(p.statusItem.menu);
XCTAssertEqual(p.statusItem.action, NULL);
XCTAssertNil(p.statusItem.target);
} else {
XCTAssertNil(p.statusItem.menu);
XCTAssertEqual(p.statusItem.action, NSSelectorFromString(@"statusItemClicked"));
XCTAssertEqual(p.statusItem.target, p);
NSDictionary *params = [p dictionaryForLine:p.titleLines[currentLine]];
if (currentLine == 1) {
XCTAssertNotNil(params[@"href"]);
} else if (currentLine == 2) {
XCTAssertNotNil(params[@"bash"]);
} else if (currentLine == 3) {
XCTAssertNotNil(params[@"refresh"]);
}
}
}
}
@end
================================================
FILE: archive/bitbar/App/BitBarTests/TestPlugins/one.10s.sh
================================================
#!/bin/bash
# one.sh - a test BitBar plugin
# BitBar
#
# Created by Mat Ryer on 11/12/13.
# Copyright (c) 2013 Bit Bar. All rights reserved.
echo "This is just a test."
================================================
FILE: archive/bitbar/App/BitBarTests/TestPlugins/three.7d.sh
================================================
#!/bin/bash
# three.sh - this test contains multiple lines with whitespace
# BitBar
#
# Created by Mat Ryer on 11/12/13.
# Copyright (c) 2013 Bit Bar. All rights reserved.
echo ""
echo "line 1"
echo " "
echo "line 2"
echo " "
echo "line 3"
================================================
FILE: archive/bitbar/App/BitBarTests/TestPlugins/two.5m.sh
================================================
#!/bin/bash
# two.sh
# BitBar
#
# Created by Mat Ryer on 11/12/13.
# Copyright (c) 2013 Bit Bar. All rights reserved.
echoerr() { echo -n "$@" 1>&2; }
echoerr Something went tits up.
exit 1
================================================
FILE: archive/bitbar/App/Vendor/AHProxySettings/.gitignore
================================================
# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
#
# Pods/
================================================
FILE: archive/bitbar/App/Vendor/AHProxySettings/AHProxyExampe/AppDelegate.h
================================================
//
// AppDelegate.h
// AHProxyExampe
//
// Created by Eldon on 11/11/14.
// Copyright (c) 2014 Eldon Ahrold. All rights reserved.
//
#import
@interface AppDelegate : NSObject
@property (weak) IBOutlet NSTextField *HTTPProxy;
@property (weak) IBOutlet NSTextField *HTTPSProxy;
@property (weak) IBOutlet NSTextField *FTPProxy;
@property (weak) IBOutlet NSTextField *SOCKSProxy;
@property (weak) IBOutlet NSTextField *AUTOProxy;
@property (weak) IBOutlet NSButton *useFailoverButton;
@property (weak) IBOutlet NSButton *runButton;
@property (weak) IBOutlet NSButton *runWithoutButton;
@property (weak) IBOutlet NSTextField *runStatusTF;
@property (weak) IBOutlet NSTextField *testURL;
- (IBAction)refresh:(id)sender;
- (IBAction)runTaskWithProxy:(NSButton *)sender;
@end
================================================
FILE: archive/bitbar/App/Vendor/AHProxySettings/AHProxyExampe/AppDelegate.m
================================================
//
// AppDelegate.m
// AHProxyExampe
//
// Created by Eldon on 11/11/14.
// Copyright (c) 2014 Eldon Ahrold. All rights reserved.
//
#import "AppDelegate.h"
#import "AHProxySettings.h"
#import "NSTask+useSystemProxies.h"
@interface AppDelegate () {
AHProxySettings *_settings;
NSTask *_task;
}
@property (weak) IBOutlet NSWindow *window;
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
_testURL.stringValue = @"https://github.com";
[self refresh:nil];
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
}
- (IBAction)refresh:(id)sender {
_settings = [[AHProxySettings alloc] init];
_settings.useAutoDetectAsFailover = _useFailoverButton.state;
_settings.destinationURL = _testURL.stringValue;
_HTTPProxy.stringValue =
_settings.HTTPProxy ? _settings.HTTPProxy.exportString : @"";
_HTTPSProxy.stringValue =
_settings.HTTPSProxy ? _settings.HTTPSProxy.exportString : @"";
_FTPProxy.stringValue =
_settings.FTPProxy ? _settings.FTPProxy.exportString : @"";
_SOCKSProxy.stringValue =
_settings.SOCKSProxy ? _settings.SOCKSProxy.exportString : @"";
_AUTOProxy.stringValue =
_settings.autoDetectedProxies
? [[_settings.autoDetectedProxies firstObject] exportString]
: @"";
}
- (IBAction)runTaskWithProxy:(NSButton *)sender {
[self setupTask];
[_task useSystemProxiesForDestination:_testURL.stringValue];
NSLog(@"%@",_task.environment);
[_task launch];
}
- (IBAction)runTaskWithOutProxy:(id)sender {
[self setupTask];
[_task launch];
}
- (void)setupTask {
_runStatusTF.stringValue = @"Checking...";
[_runButton setEnabled:NO];
[_runWithoutButton setEnabled:NO];
_task = [[NSTask alloc] init];
_task.launchPath = @"/usr/bin/curl";
_task.arguments = @[ @"-k", _testURL.stringValue ];
_task.standardOutput = [NSPipe pipe];
_task.standardError = [NSPipe pipe];
__weak typeof(self) weakSelf = self;
[_task setTerminationHandler:^(NSTask *task) {
typeof(self) strongSelf = weakSelf;
if (task.terminationStatus > 0) {
NSData *data = [[task.standardError fileHandleForReading] readDataToEndOfFile];
NSString *errString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",errString);
strongSelf.runStatusTF.stringValue = [NSString stringWithFormat:@"Unable to connect to server [error code:%d]",task.terminationStatus ];
} else {
strongSelf.runStatusTF.stringValue = @"Successfully connected to server";
}
[strongSelf.runButton setEnabled:YES];
[strongSelf.runWithoutButton setEnabled:YES];
}];
}
- (IBAction)cancelTask:(id)sender {
if (_task && _task.isRunning) {
[_task terminate];
}
}
@end
================================================
FILE: archive/bitbar/App/Vendor/AHProxySettings/AHProxyExampe/Base.lproj/MainMenu.xib
================================================
Default
Left to Right
Right to Left
Default
Left to Right
Right to Left
Gw
================================================
FILE: archive/bitbar/App/Vendor/AHProxySettings/AHProxyExampe/Images.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"idiom" : "mac",
"size" : "16x16",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "16x16",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "32x32",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "32x32",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "128x128",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "128x128",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "256x256",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "256x256",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "512x512",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "512x512",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: archive/bitbar/App/Vendor/AHProxySettings/AHProxyExampe/Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIconFile
CFBundleIdentifier
com.eeaapps.$(PRODUCT_NAME:rfc1034identifier)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
APPL
CFBundleShortVersionString
1.0
CFBundleSignature
????
CFBundleVersion
1
LSMinimumSystemVersion
$(MACOSX_DEPLOYMENT_TARGET)
NSHumanReadableCopyright
Copyright © 2014 Eldon Ahrold. All rights reserved.
NSMainNibFile
MainMenu
NSPrincipalClass
NSApplication
================================================
FILE: archive/bitbar/App/Vendor/AHProxySettings/AHProxyExampe/main.m
================================================
//
// main.m
// AHProxyExampe
//
// Created by Eldon on 11/11/14.
// Copyright (c) 2014 Eldon Ahrold. All rights reserved.
//
#import
int main(int argc, const char * argv[]) {
return NSApplicationMain(argc, argv);
}
================================================
FILE: archive/bitbar/App/Vendor/AHProxySettings/AHProxySettings/AHProxy.h
================================================
// AHProxy.h
//
// Copyright (c) 2014 Eldon Ahrold
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import
/**
* Proxy Type
*/
typedef NS_ENUM(NSInteger, AHProxyType) {
/**
* Undefined type
*/
kAHProxyTypeUnknown,
/**
* HTTP type
*/
kAHProxyTypeHTTP,
/**
* HTTPS type
*/
kAHProxyTypeHTTPS,
/**
* FTP type
*/
kAHProxyTypeFTP,
/**
* SOCKS type
*/
kAHProxyTypeSOCKS,
};
/**
* Proxy Object
*/
@interface AHProxy : NSObject
/**
* Proxy Server URL
*/
@property (copy, nonatomic, readonly) NSString *server;
/**
* Proxy Server Port
*/
@property (copy, nonatomic, readonly) NSNumber *port;
/**
* Proxy Server User
*/
@property (copy, nonatomic, readonly) NSString *user;
/**
* Proxy Server Password
*/
@property (copy, nonatomic, readonly) NSString *password;
/**
* Type of Proxy Server
*/
@property (assign, nonatomic, readonly) AHProxyType type;
/**
* export string appropriate for shell (url encoded)
*/
@property (copy, nonatomic, readonly) NSString *exportString;
@end
================================================
FILE: archive/bitbar/App/Vendor/AHProxySettings/AHProxySettings/AHProxy.m
================================================
// AHProxy.m
//
// Copyright (c) 2014 Eldon Ahrold
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "AHProxy.h"
#import
@interface AHProxy ()
@property (copy, nonatomic, readwrite) NSString *server;
@property (copy, nonatomic, readwrite) NSNumber *port;
@property (copy, nonatomic, readwrite) NSString *user;
@property (copy, nonatomic, readwrite) NSString *password;
@property (assign, nonatomic, readwrite) AHProxyType type;
@end
NSString *urlEncodedString(NSString *string) {
NSString *result = CFBridgingRelease(
CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(__bridge CFStringRef)string,
NULL,
CFSTR(":/?#[]@$&’+,;="),
kCFStringEncodingUTF8));
return result;
}
@implementation AHProxy
- (NSString *)description {
return self.exportString;
}
- (NSString *)password {
if (!_password && (_server && _user)) {
CFTypeRef results = NULL;
NSData *passwordData = nil;
NSDictionary *query = @{
(__bridge id)kSecClass : (__bridge id)kSecClassInternetPassword,
(__bridge id)kSecMatchLimit : (__bridge id)kSecMatchLimitOne,
(__bridge id)kSecAttrService : _server,
(__bridge id)kSecAttrAccount : _user,
(__bridge id)kSecReturnData : @YES,
};
if (SecItemCopyMatching((__bridge CFDictionaryRef)query, &results) ==
errSecSuccess) {
passwordData = CFBridgingRelease(results);
if (passwordData) {
_password =
[[NSString alloc] initWithData:passwordData
encoding:NSUTF8StringEncoding];
}
}
}
return _password;
}
- (NSString *)exportString {
NSString *exportString = nil;
if (_server) {
NSMutableString *workingExportString =
[[NSMutableString alloc] initWithString:[self prefixForType]];
if (_user && self.password) {
[workingExportString
appendFormat:@"%@:%@@", _user, urlEncodedString(_password)];
}
[workingExportString appendString:_server];
if (_port) {
[workingExportString appendFormat:@":%@", _port];
}
exportString = [NSString stringWithString:workingExportString];
}
return exportString;
}
- (NSString *)prefixForType {
NSString *prefix;
switch (_type) {
case kAHProxyTypeFTP:
case kAHProxyTypeHTTP:
prefix = @"http://";
break;
case kAHProxyTypeHTTPS:
prefix = @"https://";
break;
case kAHProxyTypeSOCKS:
prefix = @"socks://";
break;
default:
prefix = @"";
break;
}
return prefix;
}
@end
================================================
FILE: archive/bitbar/App/Vendor/AHProxySettings/AHProxySettings/AHProxySettings.h
================================================
// AHProxySettings.h
//
// Copyright (c) 2014 Eldon Ahrold
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import
#import "AHProxy.h"
/**
* String for key representing export HTTP_PROXY for NSTasks
*/
extern NSString *const kAHProxyExportHTTP;
/**
* String for key representing export HTTPS_PROXY for NSTasks
*/
extern NSString *const kAHProxyExportHTTPS;
/**
* String for key representing export FTP_PROXY for NSTasks
*/
extern NSString *const kAHProxyExportFTP;
/**
* String for key representing export ALL_PROXY which is used for socks exports
* for NSTasks
*/
extern NSString *const kAHProxyExportSOCKS;
/**
* String for key representing export NO_PROXY for NSTasks
*/
extern NSString *const kAHProxyExportExceptions;
/**
* Access information about the current system proxy configuration
*/
@interface AHProxySettings : NSObject
/**
* AHProxy object representing the System Web Proxy (HTTP)
*/
@property (copy, nonatomic, readonly) AHProxy *HTTPProxy;
/**
* AHProxy object representing the System Secure Web Proxy (HTTPS)
*/
@property (copy, nonatomic, readonly) AHProxy *HTTPSProxy;
/**
* AHProxy object representing the System FTP Proxy
*/
@property (copy, nonatomic, readonly) AHProxy *FTPProxy;
/**
* AHProxy object representing the System SOCKS Proxy (HTTP)
*/
@property (copy, nonatomic, readonly) AHProxy *SOCKSProxy;
/**
* Array of automatically discovered AHProxy objects from PAC / WPAD
*/
@property (copy, nonatomic, readonly) NSArray *autoDetectedProxies;
/**
* List of bypassed hosts and domains used by the system
*/
@property (copy, nonatomic, readonly) NSArray *exceptionsList;
/**
* URL used during the execution a PAC script to determine the appropriate
* proxies
*/
@property (copy, nonatomic) NSString *destinationURL;
/**
* Return a dictionary suitable for NSTask's proxies environment
*/
@property (copy, nonatomic) NSDictionary *taskDictionary;
/**
* Whether to use auto-detected proxies as failover for HTTP, HTTPS, and FTP
* @note Defaults to true
*/
@property (nonatomic, assign) BOOL useAutoDetectAsFailover;
/**
* Initialize the
*
* @param destURL URL used during the execution a PAC script to determine the
* appropriate proxies
*
* @return initialized AHProxySettings
*/
- (instancetype)initWithDestination:(NSString *)destURL;
@end
================================================
FILE: archive/bitbar/App/Vendor/AHProxySettings/AHProxySettings/AHProxySettings.m
================================================
// AHProxySettings.m
//
// Copyright (c) 2014 Eldon Ahrold
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "AHProxySettings.h"
#import
NSString *const kAHProxyExportHTTP = @"HTTP_PROXY";
NSString *const kAHProxyExportHTTPS = @"HTTPS_PROXY";
NSString *const kAHProxyExportFTP = @"FTP_PROXY";
NSString *const kAHProxyExportExceptions = @"NO_PROXY";
NSString *const kAHProxyExportSOCKS = @"ALL_PROXY";
NSString *const kNSProxyHTTP;
NSString *const kNSProxyHTTPS;
@interface AHProxy ()
@property (copy, nonatomic, readwrite) NSString *server;
@property (copy, nonatomic, readwrite) NSNumber *port;
@property (copy, nonatomic, readwrite) NSString *user;
@property (assign, nonatomic, readwrite) AHProxyType type;
@end
@implementation AHProxySettings {
NSDictionary *_systemProxies;
NSString *_pacFunction;
BOOL _pacFileRetrievalFailed;
}
@synthesize autoDetectedProxies = _autoDetectedProxies;
@synthesize exceptionsList = _exceptionsList;
- (id)init {
self = [super init];
if (self) {
_systemProxies = CFBridgingRelease(SCDynamicStoreCopyProxies(NULL));
_useAutoDetectAsFailover = YES;
}
return self;
}
- (instancetype)initWithDestination:(NSString *)destURL {
self = [self init];
if (self) {
_destinationURL = destURL;
}
return self;
}
- (AHProxy *)HTTPProxy {
return [self proxyForType:@"HTTP"];
}
- (AHProxy *)HTTPSProxy {
return [self proxyForType:@"HTTPS"];
}
- (AHProxy *)FTPProxy {
return [self proxyForType:@"FTP"];
}
- (AHProxy *)SOCKSProxy {
return [self proxyForType:@"SOCKS"];
}
- (NSArray *)autoDetectedProxies {
if (_systemProxies[@"ProxyAutoConfigEnable"] ||
_systemProxies[@"ProxyAutoDiscoveryEnable"]) {
if (!_pacFunction && !_pacFileRetrievalFailed) {
NSString *urlString = _systemProxies[@"ProxyAutoConfigURLString"];
if (urlString && urlString.length > 0) {
NSURL *pacFileURL = [NSURL URLWithString:urlString];
NSURLRequest *req = [NSURLRequest
requestWithURL:pacFileURL
cachePolicy:
NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:5.0];
// Initialize our response and error objects
NSHTTPURLResponse *resp;
NSError *error = nil;
// Get the PAC file data
NSData *reqData =
[NSURLConnection sendSynchronousRequest:req
returningResponse:&resp
error:&error];
if (reqData && (![resp respondsToSelector:@selector(statusCode)] || resp.statusCode < 400)) {
_pacFunction =
[[NSString alloc] initWithData:reqData
encoding:NSASCIIStringEncoding];
} else {
_pacFileRetrievalFailed = YES;
NSLog(@"Error retrieving PAC file. %@",error ?
error.localizedDescription:@"");
}
}
}
if (_pacFunction && self.destinationURL) {
CFErrorRef err;
NSURL *url = [NSURL URLWithString:_destinationURL];
NSArray *proxies = CFBridgingRelease(
CFNetworkCopyProxiesForAutoConfigurationScript(
(__bridge CFStringRef)(_pacFunction),
(__bridge CFURLRef)(url),
&err));
if (err) {
NSLog(@"%@", CFBridgingRelease(err));
} else {
NSMutableArray *workingProxies = [NSMutableArray new];
for (NSDictionary *proxyDict in proxies) {
AHProxy *proxy = [[AHProxy alloc] init];
proxy.server =
proxyDict[@"kCFProxyHostNameKey"];
proxy.port =
proxyDict[@"kCFProxyPortNumberKey"];
if (proxy.server && proxy.port) {
[workingProxies addObject:proxy];
}
}
if (workingProxies.count) {
_autoDetectedProxies =
[NSArray arrayWithArray:workingProxies];
}
}
}
}
return _autoDetectedProxies;
}
- (NSArray *)exceptionsList {
_exceptionsList = _systemProxies[@"ExceptionsList"];
return _exceptionsList;
}
- (NSString *)destinationURL {
if (!_destinationURL) {
_destinationURL = @"http://0.0.0.0";
}
return _destinationURL;
}
- (NSDictionary *)taskDictionary {
NSMutableDictionary *exportDictionary =
[[NSMutableDictionary alloc] initWithCapacity:5];
AHProxy *httpProxy = self.HTTPProxy;
if (httpProxy) {
NSString *proxy = httpProxy.exportString;
if (proxy) {
[exportDictionary setObject:proxy forKey:kAHProxyExportHTTP];
[exportDictionary setObject:proxy
forKey:[kAHProxyExportHTTP lowercaseString]];
}
}
AHProxy *httpsProxy = self.HTTPSProxy;
if (httpsProxy) {
NSString *proxy = httpsProxy.exportString;
if (proxy) {
[exportDictionary setObject:proxy forKey:kAHProxyExportHTTPS];
[exportDictionary setObject:proxy
forKey:[kAHProxyExportHTTPS lowercaseString]];
}
}
AHProxy *socksProxy = self.SOCKSProxy;
if (socksProxy) {
NSString *proxy = socksProxy.exportString;
if (proxy) {
[exportDictionary setObject:proxy forKey:kAHProxyExportSOCKS];
[exportDictionary setObject:proxy
forKey:[kAHProxyExportSOCKS lowercaseString]];
}
}
NSArray *autoDetectedProxies = self.autoDetectedProxies;
if (autoDetectedProxies) {
NSString *proxy = [[autoDetectedProxies firstObject] exportString];
if (!httpProxy) {
[exportDictionary setObject:proxy forKey:kAHProxyExportHTTP];
[exportDictionary setObject:proxy
forKey:[kAHProxyExportHTTP lowercaseString]];
}
if (!httpsProxy) {
[exportDictionary setObject:proxy forKey:kAHProxyExportHTTPS];
[exportDictionary setObject:proxy
forKey:[kAHProxyExportHTTPS lowercaseString]];
}
}
// If there are not keys added to the dictionary yet, skip the exception
// list
if ((exportDictionary.count > 0) && self.exceptionsList) {
NSMutableArray *exceptionList = [[NSMutableArray alloc] init];
// The NO_PROXY key is formatted differently than set in system
// you can't start with wild cards, instead you specify
// domain extensions directly (e.g. *.mit.edu is just .mit.edu)
for (NSString *exception in _exceptionsList) {
if (exception.length > 2 &&
[[exception substringToIndex:2] isEqualToString:@"*."]) {
[exceptionList addObject:[exception substringFromIndex:1]];
} else { [exceptionList addObject:exception]; }
}
NSString *exceptions = [exceptionList componentsJoinedByString:@","];
[exportDictionary setObject:exceptions forKey:kAHProxyExportExceptions];
}
return exportDictionary.count
? [NSDictionary dictionaryWithDictionary:exportDictionary]
: nil;
}
#pragma mark - Private
- (AHProxy *)proxyForType:(NSString *)type {
AHProxy *proxy = nil;
NSString *typeEnabled = [type stringByAppendingString:@"Enable"];
if (_systemProxies[typeEnabled]) {
NSString *proxyServer = [type stringByAppendingString:@"Proxy"];
// If there is a value for the key init an AHProxy object.
if (_systemProxies[proxyServer]) {
proxy = [[AHProxy alloc] init];
proxy.server = _systemProxies[proxyServer];
// Set the port.
NSString *proxyPort = [type stringByAppendingString:@"Port"];
proxy.port = _systemProxies[proxyPort];
// Set the user.
NSString *proxyUser = [type stringByAppendingString:@"User"];
proxy.user = _systemProxies[proxyUser];
// Set the type.
if ([type isEqualToString:@"HTTP"]) {
proxy.type = kAHProxyTypeHTTP;
} else if ([type isEqualToString:@"HTTPS"]) {
proxy.type = kAHProxyTypeHTTPS;
} else if ([type isEqualToString:@"FTP"]) {
proxy.type = kAHProxyTypeFTP;
} else if ([type isEqualToString:@"SOCKS"]) {
proxy.type = kAHProxyTypeSOCKS;
}
}
}
// unless disabled try to
if (!proxy && _useAutoDetectAsFailover) {
if ([type isEqualToString:@"HTTP"] || [type isEqualToString:@"HTTPS"] ||
[type isEqualToString:@"FTP"]) {
proxy = [self.autoDetectedProxies firstObject];
}
}
return proxy;
}
@end
================================================
FILE: archive/bitbar/App/Vendor/AHProxySettings/AHProxySettings/NSTask+useSystemProxies.h
================================================
//
// NSTask+useSystemProxies.h
// AHProxySettings
//
// Copyright (c) 2014 Eldon Ahrold
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import
/**
* Set the task to use system proxies
*/
@interface NSTask (useSystemProxies)
/**
* Use system proxies
*/
- (void)useSystemProxies;
/**
* Dynamically determine proxies based on supplied url
*
* @param URLString destination url to check against PAC / WPAD file
*/
- (void)useSystemProxiesForDestination:(NSString *)URLString;
@end
================================================
FILE: archive/bitbar/App/Vendor/AHProxySettings/AHProxySettings/NSTask+useSystemProxies.m
================================================
//
// NSTask+useSystemProxies.m
// AHProxySettings
//
// Copyright (c) 2014 Eldon Ahrold
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "NSTask+useSystemProxies.h"
#import "AHProxySettings.h"
@implementation NSTask (useSystemProxies)
- (void)useSystemProxies {
[self useSystemProxiesForDestination:nil];
}
- (void)useSystemProxiesForDestination:(NSString *)URLString {
AHProxySettings *settings;
if (URLString) {
settings = [[AHProxySettings alloc] initWithDestination:URLString];
} else {
settings = [[AHProxySettings alloc] init];
}
if (settings.taskDictionary) {
NSMutableDictionary *environment = [[NSMutableDictionary alloc]init];
if (!self.environment) {
[environment addEntriesFromDictionary:[[NSProcessInfo processInfo] environment]];
} else {
[environment addEntriesFromDictionary:self.environment];
}
[environment addEntriesFromDictionary:settings.taskDictionary];
self.environment = [NSDictionary dictionaryWithDictionary:environment];
}
}
@end
================================================
FILE: archive/bitbar/App/Vendor/AHProxySettings/AHProxySettings.podspec
================================================
Pod::Spec.new do |spec|
spec.name = 'AHProxySettings'
spec.version = '0.1.1'
spec.platform = :osx
spec.license = 'MIT'
spec.summary = 'Objective-c lib to easily acquire the current system proxy settings'
spec.homepage = 'https://github.com/eahrold/AHProxySettings'
spec.authors = { 'Eldon Ahrold' => 'eldon.ahrold@gmail.com' }
spec.source = { :git => 'https://github.com/eahrold/AHProxySettings.git', :tag => "v#{spec.version}" }
spec.requires_arc = true
spec.frameworks = 'Foundation','SystemConfiguration','Security'
spec.public_header_files = 'AHProxySettings/*.h'
spec.source_files = 'AHProxySettings/*.{h,m}'
end
================================================
FILE: archive/bitbar/App/Vendor/AHProxySettings/AHProxySettings.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
BE013D281A10693600C29B2E /* AHProxySettingsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = BE013D271A10693600C29B2E /* AHProxySettingsTest.m */; };
BE013D2C1A10696C00C29B2E /* libAHProxySettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BECB2D6C1A0E699400AFA935 /* libAHProxySettings.a */; };
BE013D2E1A1069F800C29B2E /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BE013D2D1A1069F800C29B2E /* SystemConfiguration.framework */; };
BE013D301A1069FE00C29B2E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BE013D2F1A1069FE00C29B2E /* Security.framework */; };
BE013D461A11435700C29B2E /* AHProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = BE013D441A11435700C29B2E /* AHProxy.h */; };
BE013D471A11435700C29B2E /* AHProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = BE013D451A11435700C29B2E /* AHProxy.m */; };
BE582A611A14741E007A1C11 /* NSTask+useSystemProxies.h in Headers */ = {isa = PBXBuildFile; fileRef = BE582A5F1A14741E007A1C11 /* NSTask+useSystemProxies.h */; };
BE582A621A14741E007A1C11 /* NSTask+useSystemProxies.m in Sources */ = {isa = PBXBuildFile; fileRef = BE582A601A14741E007A1C11 /* NSTask+useSystemProxies.m */; };
BECB2D701A0E699400AFA935 /* AHProxySettings.h in Headers */ = {isa = PBXBuildFile; fileRef = BECB2D6F1A0E699400AFA935 /* AHProxySettings.h */; };
BECB2D721A0E699400AFA935 /* AHProxySettings.m in Sources */ = {isa = PBXBuildFile; fileRef = BECB2D711A0E699400AFA935 /* AHProxySettings.m */; };
BED077D81A1313E3009690DD /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BED077D71A1313E3009690DD /* main.m */; };
BED077DB1A1313E3009690DD /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = BED077DA1A1313E3009690DD /* AppDelegate.m */; };
BED077DD1A1313E3009690DD /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BED077DC1A1313E3009690DD /* Images.xcassets */; };
BED077E01A1313E3009690DD /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = BED077DE1A1313E3009690DD /* MainMenu.xib */; };
BED077F51A131708009690DD /* libAHProxySettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BECB2D6C1A0E699400AFA935 /* libAHProxySettings.a */; };
BED077F71A13176E009690DD /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BE013D2F1A1069FE00C29B2E /* Security.framework */; };
BED077F81A13177A009690DD /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BE013D2D1A1069F800C29B2E /* SystemConfiguration.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
BE013D2A1A10696700C29B2E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BECB2D641A0E699400AFA935 /* Project object */;
proxyType = 1;
remoteGlobalIDString = BECB2D6B1A0E699400AFA935;
remoteInfo = AHProxySettings;
};
BED077F31A1316FF009690DD /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BECB2D641A0E699400AFA935 /* Project object */;
proxyType = 1;
remoteGlobalIDString = BECB2D6B1A0E699400AFA935;
remoteInfo = AHProxySettings;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
BE013D271A10693600C29B2E /* AHProxySettingsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AHProxySettingsTest.m; sourceTree = ""; };
BE013D2D1A1069F800C29B2E /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
BE013D2F1A1069FE00C29B2E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
BE013D441A11435700C29B2E /* AHProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AHProxy.h; sourceTree = ""; };
BE013D451A11435700C29B2E /* AHProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AHProxy.m; sourceTree = ""; };
BE582A5F1A14741E007A1C11 /* NSTask+useSystemProxies.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTask+useSystemProxies.h"; sourceTree = ""; };
BE582A601A14741E007A1C11 /* NSTask+useSystemProxies.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTask+useSystemProxies.m"; sourceTree = ""; };
BECB2D6C1A0E699400AFA935 /* libAHProxySettings.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libAHProxySettings.a; sourceTree = BUILT_PRODUCTS_DIR; };
BECB2D6F1A0E699400AFA935 /* AHProxySettings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AHProxySettings.h; sourceTree = ""; };
BECB2D711A0E699400AFA935 /* AHProxySettings.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AHProxySettings.m; sourceTree = ""; };
BECB2D771A0E699400AFA935 /* AHProxySettingsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AHProxySettingsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
BECB2D7A1A0E699400AFA935 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
BED077D31A1313E3009690DD /* AHProxyExampe.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AHProxyExampe.app; sourceTree = BUILT_PRODUCTS_DIR; };
BED077D61A1313E3009690DD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
BED077D71A1313E3009690DD /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
BED077D91A1313E3009690DD /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
BED077DA1A1313E3009690DD /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
BED077DC1A1313E3009690DD /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
BED077DF1A1313E3009690DD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
BECB2D691A0E699400AFA935 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
BECB2D741A0E699400AFA935 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
BE013D301A1069FE00C29B2E /* Security.framework in Frameworks */,
BE013D2E1A1069F800C29B2E /* SystemConfiguration.framework in Frameworks */,
BE013D2C1A10696C00C29B2E /* libAHProxySettings.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
BED077D01A1313E3009690DD /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
BED077F51A131708009690DD /* libAHProxySettings.a in Frameworks */,
BED077F71A13176E009690DD /* Security.framework in Frameworks */,
BED077F81A13177A009690DD /* SystemConfiguration.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
BECB2D631A0E699400AFA935 = {
isa = PBXGroup;
children = (
BECB2D6E1A0E699400AFA935 /* AHProxySettings */,
BECB2D781A0E699400AFA935 /* AHProxySettingsTests */,
BED077D41A1313E3009690DD /* AHProxyExampe */,
BED077F61A131759009690DD /* Frameworks */,
BECB2D6D1A0E699400AFA935 /* Products */,
);
sourceTree = "";
};
BECB2D6D1A0E699400AFA935 /* Products */ = {
isa = PBXGroup;
children = (
BECB2D6C1A0E699400AFA935 /* libAHProxySettings.a */,
BECB2D771A0E699400AFA935 /* AHProxySettingsTests.xctest */,
BED077D31A1313E3009690DD /* AHProxyExampe.app */,
);
name = Products;
sourceTree = "";
};
BECB2D6E1A0E699400AFA935 /* AHProxySettings */ = {
isa = PBXGroup;
children = (
BECB2D6F1A0E699400AFA935 /* AHProxySettings.h */,
BECB2D711A0E699400AFA935 /* AHProxySettings.m */,
BE013D441A11435700C29B2E /* AHProxy.h */,
BE013D451A11435700C29B2E /* AHProxy.m */,
BE582A5F1A14741E007A1C11 /* NSTask+useSystemProxies.h */,
BE582A601A14741E007A1C11 /* NSTask+useSystemProxies.m */,
);
path = AHProxySettings;
sourceTree = "";
};
BECB2D781A0E699400AFA935 /* AHProxySettingsTests */ = {
isa = PBXGroup;
children = (
BE013D271A10693600C29B2E /* AHProxySettingsTest.m */,
BECB2D791A0E699400AFA935 /* Supporting Files */,
);
path = AHProxySettingsTests;
sourceTree = "";
};
BECB2D791A0E699400AFA935 /* Supporting Files */ = {
isa = PBXGroup;
children = (
BECB2D7A1A0E699400AFA935 /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "";
};
BED077D41A1313E3009690DD /* AHProxyExampe */ = {
isa = PBXGroup;
children = (
BED077D91A1313E3009690DD /* AppDelegate.h */,
BED077DA1A1313E3009690DD /* AppDelegate.m */,
BED077DC1A1313E3009690DD /* Images.xcassets */,
BED077DE1A1313E3009690DD /* MainMenu.xib */,
BED077D51A1313E3009690DD /* Supporting Files */,
);
path = AHProxyExampe;
sourceTree = "";
};
BED077D51A1313E3009690DD /* Supporting Files */ = {
isa = PBXGroup;
children = (
BED077D61A1313E3009690DD /* Info.plist */,
BED077D71A1313E3009690DD /* main.m */,
);
name = "Supporting Files";
sourceTree = "";
};
BED077F61A131759009690DD /* Frameworks */ = {
isa = PBXGroup;
children = (
BE013D2F1A1069FE00C29B2E /* Security.framework */,
BE013D2D1A1069F800C29B2E /* SystemConfiguration.framework */,
);
name = Frameworks;
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
BECB2D6A1A0E699400AFA935 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
BE013D461A11435700C29B2E /* AHProxy.h in Headers */,
BE582A611A14741E007A1C11 /* NSTask+useSystemProxies.h in Headers */,
BECB2D701A0E699400AFA935 /* AHProxySettings.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
BECB2D6B1A0E699400AFA935 /* AHProxySettings */ = {
isa = PBXNativeTarget;
buildConfigurationList = BECB2D7D1A0E699400AFA935 /* Build configuration list for PBXNativeTarget "AHProxySettings" */;
buildPhases = (
BECB2D681A0E699400AFA935 /* Sources */,
BECB2D691A0E699400AFA935 /* Frameworks */,
BECB2D6A1A0E699400AFA935 /* Headers */,
);
buildRules = (
);
dependencies = (
);
name = AHProxySettings;
productName = AHProxySettingsShellExport;
productReference = BECB2D6C1A0E699400AFA935 /* libAHProxySettings.a */;
productType = "com.apple.product-type.library.static";
};
BECB2D761A0E699400AFA935 /* AHProxySettingsTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = BECB2D801A0E699400AFA935 /* Build configuration list for PBXNativeTarget "AHProxySettingsTests" */;
buildPhases = (
BECB2D731A0E699400AFA935 /* Sources */,
BECB2D741A0E699400AFA935 /* Frameworks */,
BECB2D751A0E699400AFA935 /* Resources */,
);
buildRules = (
);
dependencies = (
BE013D2B1A10696700C29B2E /* PBXTargetDependency */,
);
name = AHProxySettingsTests;
productName = AHProxySettingsShellExportTests;
productReference = BECB2D771A0E699400AFA935 /* AHProxySettingsTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
BED077D21A1313E3009690DD /* AHProxyExampe */ = {
isa = PBXNativeTarget;
buildConfigurationList = BED077F11A1313E3009690DD /* Build configuration list for PBXNativeTarget "AHProxyExampe" */;
buildPhases = (
BED077CF1A1313E3009690DD /* Sources */,
BED077D01A1313E3009690DD /* Frameworks */,
BED077D11A1313E3009690DD /* Resources */,
);
buildRules = (
);
dependencies = (
BED077F41A1316FF009690DD /* PBXTargetDependency */,
);
name = AHProxyExampe;
productName = AHProxyExampe;
productReference = BED077D31A1313E3009690DD /* AHProxyExampe.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
BECB2D641A0E699400AFA935 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0600;
ORGANIZATIONNAME = "Eldon Ahrold";
TargetAttributes = {
BECB2D6B1A0E699400AFA935 = {
CreatedOnToolsVersion = 6.0.1;
};
BECB2D761A0E699400AFA935 = {
CreatedOnToolsVersion = 6.0.1;
};
BED077D21A1313E3009690DD = {
CreatedOnToolsVersion = 6.0.1;
};
};
};
buildConfigurationList = BECB2D671A0E699400AFA935 /* Build configuration list for PBXProject "AHProxySettings" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = BECB2D631A0E699400AFA935;
productRefGroup = BECB2D6D1A0E699400AFA935 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
BECB2D6B1A0E699400AFA935 /* AHProxySettings */,
BECB2D761A0E699400AFA935 /* AHProxySettingsTests */,
BED077D21A1313E3009690DD /* AHProxyExampe */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
BECB2D751A0E699400AFA935 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
BED077D11A1313E3009690DD /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
BED077DD1A1313E3009690DD /* Images.xcassets in Resources */,
BED077E01A1313E3009690DD /* MainMenu.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
BECB2D681A0E699400AFA935 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
BECB2D721A0E699400AFA935 /* AHProxySettings.m in Sources */,
BE013D471A11435700C29B2E /* AHProxy.m in Sources */,
BE582A621A14741E007A1C11 /* NSTask+useSystemProxies.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
BECB2D731A0E699400AFA935 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
BE013D281A10693600C29B2E /* AHProxySettingsTest.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
BED077CF1A1313E3009690DD /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
BED077DB1A1313E3009690DD /* AppDelegate.m in Sources */,
BED077D81A1313E3009690DD /* main.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
BE013D2B1A10696700C29B2E /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = BECB2D6B1A0E699400AFA935 /* AHProxySettings */;
targetProxy = BE013D2A1A10696700C29B2E /* PBXContainerItemProxy */;
};
BED077F41A1316FF009690DD /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = BECB2D6B1A0E699400AFA935 /* AHProxySettings */;
targetProxy = BED077F31A1316FF009690DD /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
BED077DE1A1313E3009690DD /* MainMenu.xib */ = {
isa = PBXVariantGroup;
children = (
BED077DF1A1313E3009690DD /* Base */,
);
name = MainMenu.xib;
sourceTree = "";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
BECB2D7B1A0E699400AFA935 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.9;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
};
name = Debug;
};
BECB2D7C1A0E699400AFA935 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.9;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
};
name = Release;
};
BECB2D7E1A0E699400AFA935 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
EXECUTABLE_PREFIX = lib;
OTHER_LDFLAGS = "";
PRODUCT_NAME = AHProxySettings;
};
name = Debug;
};
BECB2D7F1A0E699400AFA935 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
EXECUTABLE_PREFIX = lib;
OTHER_LDFLAGS = "";
PRODUCT_NAME = AHProxySettings;
};
name = Release;
};
BECB2D811A0E699400AFA935 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
);
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = AHProxySettingsTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
PRODUCT_NAME = AHProxySettingsTests;
};
name = Debug;
};
BECB2D821A0E699400AFA935 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
);
INFOPLIST_FILE = AHProxySettingsTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
PRODUCT_NAME = AHProxySettingsTests;
};
name = Release;
};
BED077ED1A1313E3009690DD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "-";
COMBINE_HIDPI_IMAGES = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = AHProxyExampe/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
BED077EE1A1313E3009690DD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "-";
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = AHProxyExampe/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
BECB2D671A0E699400AFA935 /* Build configuration list for PBXProject "AHProxySettings" */ = {
isa = XCConfigurationList;
buildConfigurations = (
BECB2D7B1A0E699400AFA935 /* Debug */,
BECB2D7C1A0E699400AFA935 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
BECB2D7D1A0E699400AFA935 /* Build configuration list for PBXNativeTarget "AHProxySettings" */ = {
isa = XCConfigurationList;
buildConfigurations = (
BECB2D7E1A0E699400AFA935 /* Debug */,
BECB2D7F1A0E699400AFA935 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
BECB2D801A0E699400AFA935 /* Build configuration list for PBXNativeTarget "AHProxySettingsTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
BECB2D811A0E699400AFA935 /* Debug */,
BECB2D821A0E699400AFA935 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
BED077F11A1313E3009690DD /* Build configuration list for PBXNativeTarget "AHProxyExampe" */ = {
isa = XCConfigurationList;
buildConfigurations = (
BED077ED1A1313E3009690DD /* Debug */,
BED077EE1A1313E3009690DD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = BECB2D641A0E699400AFA935 /* Project object */;
}
================================================
FILE: archive/bitbar/App/Vendor/AHProxySettings/AHProxySettings.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: archive/bitbar/App/Vendor/AHProxySettings/AHProxySettings.xcodeproj/xcshareddata/xcschemes/AHProxySettings.xcscheme
================================================
================================================
FILE: archive/bitbar/App/Vendor/AHProxySettings/AHProxySettingsTests/AHProxySettingsTest.m
================================================
//
// AHProxySettingsTest.m
// AHProxySettings
//
// Created by Eldon on 11/9/14.
// Copyright (c) 2014 Eldon Ahrold. All rights reserved.
//
#import
#import
#import "AHProxySettings.h"
@interface AHProxySettingsTest : XCTestCase
@end
@implementation AHProxySettingsTest
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testAll {
// When running this test enable Auto Detect, HTTP, HTTPS, SOCKS, FTP
AHProxySettings *settings = [[AHProxySettings alloc] initWithDestination:@"https://github.com"];
XCTAssertNotNil(settings.HTTPProxy ,@"No HTTP proxy returned");
NSLog(@"%@", settings.HTTPProxy);
XCTAssertNotNil(settings.HTTPSProxy ,@"No HTTPS proxy returned");
NSLog(@"%@",settings.HTTPSProxy);
XCTAssertNotNil(settings.SOCKSProxy ,@"No SOCKS proxy returned");
NSLog(@"%@",settings.SOCKSProxy);
XCTAssertNotNil(settings.FTPProxy ,@"No FTP proxy returned");
NSLog(@"%@",settings.FTPProxy);
XCTAssertNotNil(settings.autoDetectedProxies ,@"No Auto Detected Proxies returned");
for (AHProxy *p in settings.autoDetectedProxies) {
NSLog(@"%@",p);
}
}
- (void)testAutoDetect {
// When running this test only have Auto Proxy Discovery Enabled
AHProxySettings *settings = [[AHProxySettings alloc] initWithDestination:@"https://github.com"];
NSLog(@"Proxy for localhost%@",settings.taskDictionary);
XCTAssertNotNil(settings.autoDetectedProxies ,@"No proxy returned");
XCTAssertNotNil(settings.HTTPProxy,@"A proxy returned, but should not have");
settings.useAutoDetectAsFailover = NO;
XCTAssertNil(settings.HTTPProxy,@"A proxy returned, but should not have");
settings.destinationURL = @"http://localhost";
XCTAssertNil(settings.autoDetectedProxies,@"A proxy returned, but should not have");
XCTAssertNil(settings.HTTPProxy,@"A proxy returned, but should not have");
}
- (void)testTaskDictOn {
// Have some proxies enabled when running this test
AHProxySettings *settings = [[AHProxySettings alloc] init];
XCTAssertNotNil(settings.taskDictionary,@"Couldn't determine task dictionary");
}
- (void)testTaskDict {
// Disable all proxies before running this test
AHProxySettings *settings = [[AHProxySettings alloc] init];
NSDictionary *dict = settings.taskDictionary;
XCTAssertNil(dict,@"There should be not task dictionary: %@",dict);
}
- (void)testPerformanceExample {
// This is an example of a performance test case.
[self measureBlock:^{
// Put the code you want to measure the time of here.
[self testAll];
}];
}
@end
================================================
FILE: archive/bitbar/App/Vendor/AHProxySettings/AHProxySettingsTests/Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
com.eeaapps.$(PRODUCT_NAME:rfc1034identifier)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
BNDL
CFBundleShortVersionString
1.0
CFBundleSignature
????
CFBundleVersion
1
================================================
FILE: archive/bitbar/App/Vendor/AHProxySettings/LICENSE
================================================
// Copyright (c) 2014 Eldon Ahrold ( https://github.com/eahrold/AHLaunchCtl )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
================================================
FILE: archive/bitbar/App/Vendor/AHProxySettings/README.md
================================================
#AHProxySettings
### Simple lib to access the OSX system proxy settings
```Objective-c
AHProxySettings *settings = [[AHProxySettings alloc] init];
NSLog(@"%@",settings.HTTPProxy.exportString);
NSLog(@"%@",settings.HTTPSProxy.exportString);
NSLog(@"%@",settings.FTProxy.exportString);
NSLog(@"%@",settings.SOCKSProxy.exportString);
NSLog(@"%@",settings.autoDetectedProxies);
// By default HTTP(S) and FTP proxy objects will be
// populated with a proxy returned from a .PAC / WPAD request.
// To disable this behavior
settings.useAutoDetectAsFailover = NO;
```
But the reason this project was started was to get the system proxy values into an NSTask, so there's a category for that to.
```
#import "NSTask+useSystemProxies.h"
NSTask *task = [NSTask alloc] init];
task.launchPath = @"/usr/bin/curl"
task.arguments = @[ @"-k", _testURL.stringValue ];
[task useSystemProxies];
// This is equivalent to
// export HTTP_PROXY = ...
// export HTTPS_PROXY = ...
// export FTP_PROXY = ...
// export NO_PROXY = ...
// based on your system settings
// or to dynamically determine if a proxy
// is needed based on a PAC file
[task useSystemProxiesForDestination:@"github.com"];
[task launch];
// ... then do what you will with the results ... //
```
if not using CocoaPods, make sure to include `-ObjC` in you build setting's other linker flags so the category isn't optimized out.
================================================
FILE: archive/bitbar/App/Vendor/DateTools/.gitignore
================================================
# Xcode
.DS_Store
*/build/*
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
profile
*.moved-aside
DerivedData
.idea/
*.hmap
*.xccheckout
#CocoaPods
Pods
================================================
FILE: archive/bitbar/App/Vendor/DateTools/.travis.yml
================================================
language: objective-c
before_script:
- gem install xcpretty
script:
- xcodebuild -project Tests/DateToolsTests/DateToolsTests.xcodeproj -scheme DateToolsTests -sdk iphonesimulator test | xcpretty -c
================================================
FILE: archive/bitbar/App/Vendor/DateTools/CREDITS.md
================================================
Credits
=======
Portions from NSDate+TimeAgo Originally based on code Christopher Pickslay posted to Forrst. Used with permission. http://twitter.com/cpickslay
Ramon Torres began support for internationalization/localization. Added es strings. http://rtorres.me/
Dennis Zhuang added zh_Hans Chinese Simplified strings. http://fnil.net/
Mozart Petter added pt_BR Brazilian Portuguese strings. http://www.mozartpetter.com/
Stéphane Gerardot added fr French strings.
Marco Sanson added it Italian strings. http://marcosanson.tumblr.com/
Almas Adilbek added ru Russian strings. Extended logic to support Russian idioms. http://mixdesign.kz/
Mallox51 added de German strings. https://github.com/Mallox51
Tieme van Veen added nl Dutch strings. http://www.tiemevanveen.nl
Árpád Goretity added hu Hungarian strings. http://apaczai.elte.hu/~13akga/
Anajavi added fi Finnish strings. https://github.com/anajavi
Tonydyb added ja Japanese strings.
Vinhnx added vi Vietnamese strings. http://vinhnx.github.io/
Ronail added zh_Hant Traditional Chinese strings. https://github.com/ronail
SorinAntohi added ro Romanian strings. https://github.com/SorinAntohi
spookd added da Danish strings. https://github.com/spookd
Barrett Jacobsen added cs Czech strings. https://github.com/barrettj
Dmitry Shmidt added nb Norwegian strings. https://github.com/shmidt
Martins Rudens added lv Latvian strings. https://github.com/rudensm
Osman Saral added tr Turkish strings. https://github.com/osrl
analogstyle added ko Korean strings. http://almacreative.net/
Flavio Caetano fixed pt Portuguese strings. http://flaviocaetano.com
kolarski added bg Bulgarian strings. http://github.com/kolarski
Vladimir Kofman added he Hebrew strings. https://github.com/vladimirkofman
Viraf Sarkari added ar Arabic, gre Greek, pl Polish, sv Swedish, and th Thai strings. https://github.com/viraf
Vasyl Skrypii added uk Ukranian strings. https://github.com/medlay
Maggi Trymbill added is Icelandic strings. https://github.com/grundvollur
Ikhsan Assaat added id Indonesian strings. http://ikhsan.me
Marc added ca Catalan strings. http://marcboquet.com/
Steffan Harries added cy Welsh strings. https://github.com/Bendihossan
mjanda added es and cs short format strings https://github.com/mjanda
Niklas Fahl added the de short format strings https://github.com/fahlout
Vlad Cacuic added the ro short format strings https://github.com/vrcaciuc
frin added sl Slovenian strings. http://github.com/frin
Nikhil Nigade added hi (Hindi) and gu (Gujarati) strings. https://github.com/dezinezync
Faiz Mokhtar added ms Malay strings. https://github.com/faizmokhtar
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DTConstants.h
================================================
// Copyright (C) 2014 by Matthew York
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and
// associated documentation files (the "Software"), to
// deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall
// be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import
FOUNDATION_EXPORT const long long SECONDS_IN_YEAR;
FOUNDATION_EXPORT const NSInteger SECONDS_IN_MONTH_28;
FOUNDATION_EXPORT const NSInteger SECONDS_IN_MONTH_29;
FOUNDATION_EXPORT const NSInteger SECONDS_IN_MONTH_30;
FOUNDATION_EXPORT const NSInteger SECONDS_IN_MONTH_31;
FOUNDATION_EXPORT const NSInteger SECONDS_IN_WEEK;
FOUNDATION_EXPORT const NSInteger SECONDS_IN_DAY;
FOUNDATION_EXPORT const NSInteger SECONDS_IN_HOUR;
FOUNDATION_EXPORT const NSInteger SECONDS_IN_MINUTE;
FOUNDATION_EXPORT const NSInteger MILLISECONDS_IN_DAY;
#import "DTError.h"
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DTConstants.m
================================================
// Copyright (C) 2014 by Matthew York
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and
// associated documentation files (the "Software"), to
// deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall
// be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "DTConstants.h"
const long long SECONDS_IN_YEAR = 31556900;
const NSInteger SECONDS_IN_MONTH_28 = 2419200;
const NSInteger SECONDS_IN_MONTH_29 = 2505600;
const NSInteger SECONDS_IN_MONTH_30 = 2592000;
const NSInteger SECONDS_IN_MONTH_31 = 2678400;
const NSInteger SECONDS_IN_WEEK = 604800;
const NSInteger SECONDS_IN_DAY = 86400;
const NSInteger SECONDS_IN_HOUR = 3600;
const NSInteger SECONDS_IN_MINUTE = 60;
const NSInteger MILLISECONDS_IN_DAY = 86400000;
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DTError.h
================================================
// Copyright (C) 2014 by Matthew York
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and
// associated documentation files (the "Software"), to
// deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall
// be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import
#pragma mark - Domain
extern NSString *const DTErrorDomain;
#pragma mark - Status Codes
static const NSUInteger DTInsertOutOfBoundsException = 0;
static const NSUInteger DTRemoveOutOfBoundsException = 1;
static const NSUInteger DTBadTypeException = 2;
@interface DTError : NSObject
+(void)throwInsertOutOfBoundsException:(NSInteger)index array:(NSArray *)array;
+(void)throwRemoveOutOfBoundsException:(NSInteger)index array:(NSArray *)array;
+(void)throwBadTypeException:(id)obj expectedClass:(Class)classType;
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DTError.m
================================================
// Copyright (C) 2014 by Matthew York
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and
// associated documentation files (the "Software"), to
// deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall
// be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "DTError.h"
#pragma mark - Domain
NSString *const DTErrorDomain = @"com.mattyork.dateTools";
@implementation DTError
+(void)throwInsertOutOfBoundsException:(NSInteger)index array:(NSArray *)array{
//Handle possible zero bounds
NSInteger arrayUpperBound = (array.count == 0)? 0:array.count;
//Create info for error
NSDictionary *userInfo = @{NSLocalizedDescriptionKey: NSLocalizedString(@"Operation was unsuccessful.", nil), NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"Attempted to insert DTTimePeriod at index %ld but the group is of size [0...%ld].", (long)index, (long)arrayUpperBound],NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Please try an index within the bounds or the group.", nil)};
//Handle Error
NSError *error = [NSError errorWithDomain:DTErrorDomain code:DTInsertOutOfBoundsException userInfo:userInfo];
[self printErrorWithCallStack:error];
}
+(void)throwRemoveOutOfBoundsException:(NSInteger)index array:(NSArray *)array{
//Handle possible zero bounds
NSInteger arrayUpperBound = (array.count == 0)? 0:array.count;
//Create info for error
NSDictionary *userInfo = @{NSLocalizedDescriptionKey: NSLocalizedString(@"Operation was unsuccessful.", nil), NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"Attempted to remove DTTimePeriod at index %ld but the group is of size [0...%ld].", (long)index, (long)arrayUpperBound],NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Please try an index within the bounds of the group.", nil)};
//Handle Error
NSError *error = [NSError errorWithDomain:DTErrorDomain code:DTRemoveOutOfBoundsException userInfo:userInfo];
[self printErrorWithCallStack:error];
}
+(void)throwBadTypeException:(id)obj expectedClass:(Class)classType{
//Create info for error
NSDictionary *userInfo = @{NSLocalizedDescriptionKey: NSLocalizedString(@"Operation was unsuccessful.", nil), NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"Attempted to insert object of class %@ when expecting object of class %@.", NSStringFromClass([obj class]), NSStringFromClass(classType)],NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Please try again by inserting a DTTimePeriod object.", nil)};
//Handle Error
NSError *error = [NSError errorWithDomain:DTErrorDomain code:DTBadTypeException userInfo:userInfo];
[self printErrorWithCallStack:error];
}
+(void)printErrorWithCallStack:(NSError *)error{
//Print error
NSLog(@"%@", error);
//Print call stack
for (NSString *symbol in [NSThread callStackSymbols]) {
NSLog(@"\n\n %@", symbol);
}
}
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DTTimePeriod.h
================================================
// Copyright (C) 2014 by Matthew York
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and
// associated documentation files (the "Software"), to
// deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall
// be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import
typedef NS_ENUM(NSUInteger, DTTimePeriodRelation){
DTTimePeriodRelationAfter,
DTTimePeriodRelationStartTouching,
DTTimePeriodRelationStartInside,
DTTimePeriodRelationInsideStartTouching,
DTTimePeriodRelationEnclosingStartTouching,
DTTimePeriodRelationEnclosing,
DTTimePeriodRelationEnclosingEndTouching,
DTTimePeriodRelationExactMatch,
DTTimePeriodRelationInside,
DTTimePeriodRelationInsideEndTouching,
DTTimePeriodRelationEndInside,
DTTimePeriodRelationEndTouching,
DTTimePeriodRelationBefore,
DTTimePeriodRelationNone //One or more of the dates does not exist
};
typedef NS_ENUM(NSUInteger, DTTimePeriodSize) {
DTTimePeriodSizeSecond,
DTTimePeriodSizeMinute,
DTTimePeriodSizeHour,
DTTimePeriodSizeDay,
DTTimePeriodSizeWeek,
DTTimePeriodSizeMonth,
DTTimePeriodSizeYear
};
typedef NS_ENUM(NSUInteger, DTTimePeriodInterval) {
DTTimePeriodIntervalOpen,
DTTimePeriodIntervalClosed
};
typedef NS_ENUM(NSUInteger, DTTimePeriodAnchor) {
DTTimePeriodAnchorStart,
DTTimePeriodAnchorCenter,
DTTimePeriodAnchorEnd
};
@interface DTTimePeriod : NSObject
/**
* The start date for a DTTimePeriod representing the starting boundary of the time period
*/
@property (nonatomic,strong) NSDate *StartDate;
/**
* The end date for a DTTimePeriod representing the ending boundary of the time period
*/
@property (nonatomic,strong) NSDate *EndDate;
#pragma mark - Custom Init / Factory Methods
-(instancetype)initWithStartDate:(NSDate *)startDate endDate:(NSDate *)endDate;
+(instancetype)timePeriodWithStartDate:(NSDate *)startDate endDate:(NSDate *)endDate;
+(instancetype)timePeriodWithSize:(DTTimePeriodSize)size startingAt:(NSDate *)date;
+(instancetype)timePeriodWithSize:(DTTimePeriodSize)size amount:(NSInteger)amount startingAt:(NSDate *)date;
+(instancetype)timePeriodWithSize:(DTTimePeriodSize)size endingAt:(NSDate *)date;
+(instancetype)timePeriodWithSize:(DTTimePeriodSize)size amount:(NSInteger)amount endingAt:(NSDate *)date;
+(instancetype)timePeriodWithAllTime;
#pragma mark - Time Period Information
-(BOOL)hasStartDate;
-(BOOL)hasEndDate;
-(BOOL)isMoment;
-(double)durationInYears;
-(double)durationInWeeks;
-(double)durationInDays;
-(double)durationInHours;
-(double)durationInMinutes;
-(double)durationInSeconds;
#pragma mark - Time Period Relationship
-(BOOL)isEqualToPeriod:(DTTimePeriod *)period;
-(BOOL)isInside:(DTTimePeriod *)period;
-(BOOL)contains:(DTTimePeriod *)period;
-(BOOL)overlapsWith:(DTTimePeriod *)period;
-(BOOL)intersects:(DTTimePeriod *)period;
-(DTTimePeriodRelation)relationToPeriod:(DTTimePeriod *)period;
-(NSTimeInterval)gapBetween:(DTTimePeriod *)period;
#pragma mark - Date Relationships
-(BOOL)containsDate:(NSDate *)date interval:(DTTimePeriodInterval)interval;
#pragma mark - Period Manipulation
#pragma mark Shifts
-(void)shiftEarlierWithSize:(DTTimePeriodSize)size;
-(void)shiftEarlierWithSize:(DTTimePeriodSize)size amount:(NSInteger)amount;
-(void)shiftLaterWithSize:(DTTimePeriodSize)size;
-(void)shiftLaterWithSize:(DTTimePeriodSize)size amount:(NSInteger)amount;
#pragma mark Lengthen / Shorten
-(void)lengthenWithAnchorDate:(DTTimePeriodAnchor)anchor size:(DTTimePeriodSize)size;
-(void)lengthenWithAnchorDate:(DTTimePeriodAnchor)anchor size:(DTTimePeriodSize)size amount:(NSInteger)amount;
-(void)shortenWithAnchorDate:(DTTimePeriodAnchor)anchor size:(DTTimePeriodSize)size;
-(void)shortenWithAnchorDate:(DTTimePeriodAnchor)anchor size:(DTTimePeriodSize)size amount:(NSInteger)amount;
#pragma mark - Helper Methods
-(DTTimePeriod *)copy;
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DTTimePeriod.m
================================================
// Copyright (C) 2014 by Matthew York
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and
// associated documentation files (the "Software"), to
// deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall
// be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "DTTimePeriod.h"
#import "NSDate+DateTools.h"
@interface DTTimePeriod ()
@end
@implementation DTTimePeriod
#pragma mark - Custom Init / Factory Methods
/**
* Initializes an instance of DTTimePeriod from a given start and end date
*
* @param startDate NSDate - Desired start date
* @param endDate NSDate - Desired end date
*
* @return DTTimePeriod - new instance
*/
-(instancetype)initWithStartDate:(NSDate *)startDate endDate:(NSDate *)endDate{
if (self = [super init]) {
self.StartDate = startDate;
self.EndDate = endDate;
}
return self;
}
/**
* Returns a new instance of DTTimePeriod from a given start and end date
*
* @param startDate NSDate - Desired start date
* @param endDate NSDate - Desired end date
*
* @return DTTimePeriod - new instance
*/
+(instancetype)timePeriodWithStartDate:(NSDate *)startDate endDate:(NSDate *)endDate{
return [[DTTimePeriod alloc] initWithStartDate:startDate endDate:endDate];
}
/**
* Returns a new instance of DTTimePeriod that starts on the provided start date
* and is of the size provided
*
* @param size DTTimePeriodSize - Desired size of the new time period
* @param date NSDate - Desired start date of the new time period
*
* @return DTTimePeriod - new instance
*/
+(instancetype)timePeriodWithSize:(DTTimePeriodSize)size startingAt:(NSDate *)date{
return [[DTTimePeriod alloc] initWithStartDate:date endDate:[DTTimePeriod dateWithAddedTime:size amount:1 baseDate:date]];
}
/**
* Returns a new instance of DTTimePeriod that starts on the provided start date
* and is of the size provided. The amount represents a multipler to the size (e.g. "2 weeks" or "4 years")
*
* @param size DTTimePeriodSize - Desired size of the new time period
* @param amount NSInteger - Desired multiplier of the size provided
* @param date NSDate - Desired start date of the new time period
*
* @return DTTimePeriod - new instance
*/
+(instancetype)timePeriodWithSize:(DTTimePeriodSize)size amount:(NSInteger)amount startingAt:(NSDate *)date{
return [[DTTimePeriod alloc] initWithStartDate:date endDate:[DTTimePeriod dateWithAddedTime:size amount:amount baseDate:date]];
}
/**
* Returns a new instance of DTTimePeriod that ends on the provided end date
* and is of the size provided
*
* @param size DTTimePeriodSize - Desired size of the new time period
* @param date NSDate - Desired end date of the new time period
*
* @return DTTimePeriod - new instance
*/
+(instancetype)timePeriodWithSize:(DTTimePeriodSize)size endingAt:(NSDate *)date{
return [[DTTimePeriod alloc] initWithStartDate:[DTTimePeriod dateWithSubtractedTime:size amount:1 baseDate:date] endDate:date];
}
/**
* Returns a new instance of DTTimePeriod that ends on the provided end date
* and is of the size provided. The amount represents a multipler to the size (e.g. "2 weeks" or "4 years")
*
* @param size DTTimePeriodSize - Desired size of the new time period
* @param amount NSInteger - Desired multiplier of the size provided
* @param date NSDate - Desired end date of the new time period
*
* @return DTTimePeriod - new instance
*/
+(instancetype)timePeriodWithSize:(DTTimePeriodSize)size amount:(NSInteger)amount endingAt:(NSDate *)date{
return [[DTTimePeriod alloc] initWithStartDate:[DTTimePeriod dateWithSubtractedTime:size amount:amount baseDate:date] endDate:date];
}
/**
* Returns a new instance of DTTimePeriod that represents the largest time period available.
* The start date is in the distant past and the end date is in the distant future.
*
* @return DTTimePeriod - new instance
*/
+(instancetype)timePeriodWithAllTime{
return [[DTTimePeriod alloc] initWithStartDate:[NSDate distantPast] endDate:[NSDate distantFuture]];
}
/**
* Method serving the various factory methods as well as a few others.
* Returns a date with time added to a given base date. Includes multiplier amount.
*
* @param size DTTimePeriodSize - Desired size of the new time period
* @param amount NSInteger - Desired multiplier of the size provided
* @param date NSDate - Desired end date of the new time period
*
* @return NSDate - new instance
*/
+(NSDate *)dateWithAddedTime:(DTTimePeriodSize)size amount:(NSInteger)amount baseDate:(NSDate *)date{
switch (size) {
case DTTimePeriodSizeSecond:
return [date dateByAddingSeconds:amount];
break;
case DTTimePeriodSizeMinute:
return [date dateByAddingMinutes:amount];
break;
case DTTimePeriodSizeHour:
return [date dateByAddingHours:amount];
break;
case DTTimePeriodSizeDay:
return [date dateByAddingDays:amount];
break;
case DTTimePeriodSizeWeek:
return [date dateByAddingWeeks:amount];
break;
case DTTimePeriodSizeMonth:
return [date dateByAddingMonths:amount];
break;
case DTTimePeriodSizeYear:
return [date dateByAddingYears:amount];
break;
default:
break;
}
return date;
}
/**
* Method serving the various factory methods as well as a few others.
* Returns a date with time subtracted from a given base date. Includes multiplier amount.
*
* @param size DTTimePeriodSize - Desired size of the new time period
* @param amount NSInteger - Desired multiplier of the size provided
* @param date NSDate - Desired end date of the new time period
*
* @return NSDate - new instance
*/
+(NSDate *)dateWithSubtractedTime:(DTTimePeriodSize)size amount:(NSInteger)amount baseDate:(NSDate *)date{
switch (size) {
case DTTimePeriodSizeSecond:
return [date dateBySubtractingSeconds:amount];
break;
case DTTimePeriodSizeMinute:
return [date dateBySubtractingMinutes:amount];
break;
case DTTimePeriodSizeHour:
return [date dateBySubtractingHours:amount];
break;
case DTTimePeriodSizeDay:
return [date dateBySubtractingDays:amount];
break;
case DTTimePeriodSizeWeek:
return [date dateBySubtractingWeeks:amount];
break;
case DTTimePeriodSizeMonth:
return [date dateBySubtractingMonths:amount];
break;
case DTTimePeriodSizeYear:
return [date dateBySubtractingYears:amount];
break;
default:
break;
}
return date;
}
#pragma mark - Time Period Information
/**
* Returns a boolean representing whether the receiver's StartDate exists
* Returns YES if StartDate is not nil, otherwise NO
*
* @return BOOL
*/
-(BOOL)hasStartDate {
return (self.StartDate)? YES:NO;
}
/**
* Returns a boolean representing whether the receiver's EndDate exists
* Returns YES if EndDate is not nil, otherwise NO
*
* @return BOOL
*/
-(BOOL)hasEndDate {
return (self.EndDate)? YES:NO;
}
/**
* Returns a boolean representing whether the receiver is a "moment", that is the start and end dates are the same.
* Returns YES if receiver is a moment, otherwise NO
*
* @return BOOL
*/
-(BOOL)isMoment{
if (self.StartDate && self.EndDate) {
if ([self.StartDate isEqualToDate:self.EndDate]) {
return YES;
}
}
return NO;
}
/**
* Returns the duration of the receiver in years
*
* @return NSInteger
*/
-(double)durationInYears {
if (self.StartDate && self.EndDate) {
return [self.StartDate yearsEarlierThan:self.EndDate];
}
return 0;
}
/**
* Returns the duration of the receiver in weeks
*
* @return double
*/
-(double)durationInWeeks {
if (self.StartDate && self.EndDate) {
return [self.StartDate weeksEarlierThan:self.EndDate];
}
return 0;
}
/**
* Returns the duration of the receiver in days
*
* @return double
*/
-(double)durationInDays {
if (self.StartDate && self.EndDate) {
return [self.StartDate daysEarlierThan:self.EndDate];
}
return 0;
}
/**
* Returns the duration of the receiver in hours
*
* @return double
*/
-(double)durationInHours {
if (self.StartDate && self.EndDate) {
return [self.StartDate hoursEarlierThan:self.EndDate];
}
return 0;
}
/**
* Returns the duration of the receiver in minutes
*
* @return double
*/
-(double)durationInMinutes {
if (self.StartDate && self.EndDate) {
return [self.StartDate minutesEarlierThan:self.EndDate];
}
return 0;
}
/**
* Returns the duration of the receiver in seconds
*
* @return double
*/
-(double)durationInSeconds {
if (self.StartDate && self.EndDate) {
return [self.StartDate secondsEarlierThan:self.EndDate];
}
return 0;
}
#pragma mark - Time Period Relationship
/**
* Returns a BOOL representing whether the receiver's start and end dates exatcly match a given time period
* Returns YES if the two periods are the same, otherwise NO
*
* @param period DTTimePeriod - Time period to compare to receiver
*
* @return BOOL
*/
-(BOOL)isEqualToPeriod:(DTTimePeriod *)period{
if ([self.StartDate isEqualToDate:period.StartDate] && [self.EndDate isEqualToDate:period.EndDate]) {
return YES;
}
return NO;
}
/**
* Returns a BOOL representing whether the receiver's start and end dates exatcly match a given time period or is contained within them
* Returns YES if the receiver is inside the given time period, otherwise NO
*
* @param period DTTimePeriod - Time period to compare to receiver
*
* @return BOOL
*/
-(BOOL)isInside:(DTTimePeriod *)period{
if ([period.StartDate isEarlierThanOrEqualTo:self.StartDate] && [period.EndDate isLaterThanOrEqualTo:self.EndDate]) {
return YES;
}
return NO;
}
/**
* Returns a BOOL representing whether the given time period's start and end dates exatcly match the receivers' or is contained within them
* Returns YES if the receiver is inside the given time period, otherwise NO
*
* @param period DTTimePeriod - Time period to compare to receiver
*
* @return BOOL
*/
-(BOOL)contains:(DTTimePeriod *)period{
if ([self.StartDate isEarlierThanOrEqualTo:period.StartDate] && [self.EndDate isLaterThanOrEqualTo:period.EndDate]) {
return YES;
}
return NO;
}
/**
* Returns a BOOL representing whether the receiver and the given time period overlap.
* This covers all space they share, minus instantaneous space (i.e. one's start date equals another's end date)
* Returns YES if they overlap, otherwise NO
*
* @param period DTTimePeriod - Time period to compare to receiver
*
* @return BOOL
*/
-(BOOL)overlapsWith:(DTTimePeriod *)period{
//Outside -> Inside
if ([period.StartDate isEarlierThan:self.StartDate] && [period.EndDate isLaterThan:self.StartDate]) {
return YES;
}
//Enclosing
else if ([period.StartDate isLaterThanOrEqualTo:self.StartDate] && [period.EndDate isEarlierThanOrEqualTo:self.EndDate]){
return YES;
}
//Inside -> Out
else if([period.StartDate isEarlierThan:self.EndDate] && [period.EndDate isLaterThan:self.EndDate]){
return YES;
}
return NO;
}
/**
* Returns a BOOL representing whether the receiver and the given time period overlap.
* This covers all space they share, including instantaneous space (i.e. one's start date equals another's end date)
* Returns YES if they overlap, otherwise NO
*
* @param period DTTimePeriod - Time period to compare to receiver
*
* @return BOOL
*/
-(BOOL)intersects:(DTTimePeriod *)period{
//Outside -> Inside
if ([period.StartDate isEarlierThan:self.StartDate] && [period.EndDate isLaterThanOrEqualTo:self.StartDate]) {
return YES;
}
//Enclosing
else if ([period.StartDate isLaterThanOrEqualTo:self.StartDate] && [period.EndDate isEarlierThanOrEqualTo:self.EndDate]){
return YES;
}
//Inside -> Out
else if([period.StartDate isEarlierThanOrEqualTo:self.EndDate] && [period.EndDate isLaterThan:self.EndDate]){
return YES;
}
return NO;
}
/**
* Returns the relationship of the receiver to a given time period
*
* @param period DTTimePeriod - Time period to compare to receiver
*
* @return DTTimePeriodRelation
*/
-(DTTimePeriodRelation)relationToPeriod:(DTTimePeriod *)period{
//Make sure that all start and end points exist for comparison
if (self.StartDate && self.EndDate && period.StartDate && period.EndDate) {
//Make sure time periods are of positive durations
if ([self.StartDate isEarlierThan:self.EndDate] && [period.StartDate isEarlierThan:period.EndDate]) {
//Make comparisons
if ([period.EndDate isEarlierThan:self.StartDate]) {
return DTTimePeriodRelationAfter;
}
else if ([period.EndDate isEqualToDate:self.StartDate]){
return DTTimePeriodRelationStartTouching;
}
else if ([period.StartDate isEarlierThan:self.StartDate] && [period.EndDate isEarlierThan:self.EndDate]){
return DTTimePeriodRelationStartInside;
}
else if ([period.StartDate isEqualToDate:self.StartDate] && [period.EndDate isLaterThan:self.EndDate]){
return DTTimePeriodRelationInsideStartTouching;
}
else if ([period.StartDate isEqualToDate:self.StartDate] && [period.EndDate isEarlierThan:self.EndDate]){
return DTTimePeriodRelationEnclosingStartTouching;
}
else if ([period.StartDate isLaterThan:self.StartDate] && [period.EndDate isEarlierThan:self.EndDate]){
return DTTimePeriodRelationEnclosing;
}
else if ([period.StartDate isLaterThan:self.StartDate] && [period.EndDate isEqualToDate:self.EndDate]){
return DTTimePeriodRelationEnclosingEndTouching;
}
else if ([period.StartDate isEqualToDate:self.StartDate] && [period.EndDate isEqualToDate:self.EndDate]){
return DTTimePeriodRelationExactMatch;
}
else if ([period.StartDate isEarlierThan:self.StartDate] && [period.EndDate isLaterThan:self.EndDate]){
return DTTimePeriodRelationInside;
}
else if ([period.StartDate isEarlierThan:self.StartDate] && [period.EndDate isEqualToDate:self.EndDate]){
return DTTimePeriodRelationInsideEndTouching;
}
else if ([period.StartDate isEarlierThan:self.EndDate] && [period.EndDate isLaterThan:self.EndDate]){
return DTTimePeriodRelationEndInside;
}
else if ([period.StartDate isEqualToDate:self.EndDate] && [period.EndDate isLaterThan:self.EndDate]){
return DTTimePeriodRelationEndTouching;
}
else if ([period.StartDate isLaterThan:self.EndDate]){
return DTTimePeriodRelationBefore;
}
}
}
return DTTimePeriodRelationNone;
}
/**
* Returns the gap in seconds between the receiver and provided time period
* Returns 0 if the time periods intersect, otherwise returns the gap between.
*
* @param period <#period description#>
*
* @return <#return value description#>
*/
-(NSTimeInterval)gapBetween:(DTTimePeriod *)period{
if ([self.EndDate isEarlierThan:period.StartDate]) {
return ABS([self.EndDate timeIntervalSinceDate:period.StartDate]);
}
else if ([period.EndDate isEarlierThan:self.StartDate]){
return ABS([period.EndDate timeIntervalSinceDate:self.StartDate]);
}
return 0;
}
#pragma mark - Date Relationships
/**
* Returns a BOOL representing whether the provided date is contained in the receiver.
*
* @param date NSDate - Date to evaluate
* @param interval DTTimePeriodInterval representing evaluation type (Closed includes StartDate and EndDate in evaluation, Open does not)
*
* @return <#return value description#>
*/
-(BOOL)containsDate:(NSDate *)date interval:(DTTimePeriodInterval)interval{
if (interval == DTTimePeriodIntervalOpen) {
if ([self.StartDate isEarlierThan:date] && [self.EndDate isLaterThan:date]) {
return YES;
}
else {
return NO;
}
}
else if (interval == DTTimePeriodIntervalClosed){
if ([self.StartDate isEarlierThanOrEqualTo:date] && [self.EndDate isLaterThanOrEqualTo:date]) {
return YES;
}
else {
return NO;
}
}
return NO;
}
#pragma mark - Period Manipulation
/**
* Shifts the StartDate and EndDate earlier by a given size amount
*
* @param size DTTimePeriodSize - Desired shift size
*/
-(void)shiftEarlierWithSize:(DTTimePeriodSize)size{
[self shiftEarlierWithSize:size amount:1];
}
/**
* Shifts the StartDate and EndDate earlier by a given size amount. Amount multiplies size.
*
* @param size DTTimePeriodSize - Desired shift size
* @param amount NSInteger - Multiplier of size (i.e. "2 weeks" or "4 years")
*/
-(void)shiftEarlierWithSize:(DTTimePeriodSize)size amount:(NSInteger)amount{
self.StartDate = [DTTimePeriod dateWithSubtractedTime:size amount:amount baseDate:self.StartDate];
self.EndDate = [DTTimePeriod dateWithSubtractedTime:size amount:amount baseDate:self.EndDate];
}
/**
* Shifts the StartDate and EndDate later by a given size amount
*
* @param size DTTimePeriodSize - Desired shift size
*/
-(void)shiftLaterWithSize:(DTTimePeriodSize)size{
[self shiftLaterWithSize:size amount:1];
}
/**
* Shifts the StartDate and EndDate later by a given size amount. Amount multiplies size.
*
* @param size DTTimePeriodSize - Desired shift size
* @param amount NSInteger - Multiplier of size (i.e. "2 weeks" or "4 years")
*/
-(void)shiftLaterWithSize:(DTTimePeriodSize)size amount:(NSInteger)amount{
self.StartDate = [DTTimePeriod dateWithAddedTime:size amount:amount baseDate:self.StartDate];
self.EndDate = [DTTimePeriod dateWithAddedTime:size amount:amount baseDate:self.EndDate];
}
#pragma mark Lengthen / Shorten
/**
* Lengthens the receiver by a given amount, anchored by a provided point
*
* @param anchor DTTimePeriodAnchor - Anchor point for the lengthen (the date that stays the same)
* @param size DTTimePeriodSize - Desired lenghtening size
*/
-(void)lengthenWithAnchorDate:(DTTimePeriodAnchor)anchor size:(DTTimePeriodSize)size{
[self lengthenWithAnchorDate:anchor size:size amount:1];
}
/**
* Lengthens the receiver by a given amount, anchored by a provided point. Amount multiplies size.
*
* @param anchor DTTimePeriodAnchor - Anchor point for the lengthen (the date that stays the same)
* @param size DTTimePeriodSize - Desired lenghtening size
* @param amount NSInteger - Multiplier of size (i.e. "2 weeks" or "4 years")
*/
-(void)lengthenWithAnchorDate:(DTTimePeriodAnchor)anchor size:(DTTimePeriodSize)size amount:(NSInteger)amount{
switch (anchor) {
case DTTimePeriodAnchorStart:
self.EndDate = [DTTimePeriod dateWithAddedTime:size amount:amount baseDate:self.EndDate];
break;
case DTTimePeriodAnchorCenter:
self.StartDate = [DTTimePeriod dateWithSubtractedTime:size amount:amount/2 baseDate:self.StartDate];
self.EndDate = [DTTimePeriod dateWithAddedTime:size amount:amount/2 baseDate:self.EndDate];
break;
case DTTimePeriodAnchorEnd:
self.StartDate = [DTTimePeriod dateWithSubtractedTime:size amount:amount baseDate:self.StartDate];
break;
default:
break;
}
}
/**
* Shortens the receiver by a given amount, anchored by a provided point
*
* @param anchor DTTimePeriodAnchor - Anchor point for the shorten (the date that stays the same)
* @param size DTTimePeriodSize - Desired shortening size
*/
-(void)shortenWithAnchorDate:(DTTimePeriodAnchor)anchor size:(DTTimePeriodSize)size{
[self shortenWithAnchorDate:anchor size:size amount:1];
}
/**
* Shortens the receiver by a given amount, anchored by a provided point. Amount multiplies size.
*
* @param anchor DTTimePeriodAnchor - Anchor point for the shorten (the date that stays the same)
* @param size DTTimePeriodSize - Desired shortening size
* @param amount NSInteger - Multiplier of size (i.e. "2 weeks" or "4 years")
*/
-(void)shortenWithAnchorDate:(DTTimePeriodAnchor)anchor size:(DTTimePeriodSize)size amount:(NSInteger)amount{
switch (anchor) {
case DTTimePeriodAnchorStart:
self.EndDate = [DTTimePeriod dateWithSubtractedTime:size amount:amount baseDate:self.EndDate];
break;
case DTTimePeriodAnchorCenter:
self.StartDate = [DTTimePeriod dateWithAddedTime:size amount:amount/2 baseDate:self.StartDate];
self.EndDate = [DTTimePeriod dateWithSubtractedTime:size amount:amount/2 baseDate:self.EndDate];
break;
case DTTimePeriodAnchorEnd:
self.StartDate = [DTTimePeriod dateWithAddedTime:size amount:amount baseDate:self.StartDate];
break;
default:
break;
}
}
#pragma mark - Helper Methods
-(DTTimePeriod *)copy{
DTTimePeriod *period = [DTTimePeriod timePeriodWithStartDate:[NSDate dateWithTimeIntervalSince1970:self.StartDate.timeIntervalSince1970] endDate:[NSDate dateWithTimeIntervalSince1970:self.EndDate.timeIntervalSince1970]];
return period;
}
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DTTimePeriodChain.h
================================================
// Copyright (C) 2014 by Matthew York
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and
// associated documentation files (the "Software"), to
// deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall
// be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import
#import "DTTimePeriodGroup.h"
@interface DTTimePeriodChain : DTTimePeriodGroup {
DTTimePeriod *First;
DTTimePeriod *Last;
}
@property (nonatomic, readonly) DTTimePeriod *First;
@property (nonatomic, readonly) DTTimePeriod *Last;
#pragma mark - Custom Init / Factory Chain
+(DTTimePeriodChain *)chain;
#pragma mark - Chain Existence Manipulation
-(void)addTimePeriod:(DTTimePeriod *)period;
-(void)insertTimePeriod:(DTTimePeriod *)period atInedx:(NSInteger)index;
-(void)removeTimePeriodAtIndex:(NSInteger)index;
-(void)removeLatestTimePeriod;
-(void)removeEarliestTimePeriod;
#pragma mark - Chain Relationship
-(BOOL)isEqualToChain:(DTTimePeriodChain *)chain;
#pragma mark - Updates
-(void)updateVariables;
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DTTimePeriodChain.m
================================================
// Copyright (C) 2014 by Matthew York
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and
// associated documentation files (the "Software"), to
// deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall
// be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "DTTimePeriodChain.h"
#import "DTError.h"
@interface DTTimePeriodChain ()
@end
@implementation DTTimePeriodChain
#pragma mark - Custom Init / Factory Chain
+(DTTimePeriodChain *)chain{
return [[DTTimePeriodChain alloc] init];
}
#pragma mark - Chain Existence Manipulation
-(void)addTimePeriod:(DTTimePeriod *)period{
if ([period class] != [DTTimePeriod class]) {
[DTError throwBadTypeException:period expectedClass:[DTTimePeriod class]];
return;
}
if (periods) {
if (periods.count > 0) {
//Create a modified period to be added based on size of passed in period
DTTimePeriod *modifiedPeriod = [DTTimePeriod timePeriodWithSize:DTTimePeriodSizeSecond amount:period.durationInSeconds startingAt:[periods[periods.count - 1] EndDate]];
//Add object to periods array
[periods addObject:modifiedPeriod];
}
else {
//Add object to periods array
[periods addObject:period];
}
}
else {
//Create new periods array
periods = [NSMutableArray array];
//Add object to periods array
[periods addObject:period];
}
//Set object's variables with updated array values
[self updateVariables];
}
-(void)insertTimePeriod:(DTTimePeriod *)period atInedx:(NSInteger)index{
if ([period class] != [DTTimePeriod class]) {
[DTError throwBadTypeException:period expectedClass:[DTTimePeriod class]];
return;
}
//Make sure the index is within the operable bounds of the periods array
if (index == 0) {
//Update bounds of period to make it fit in chain
DTTimePeriod *modifiedPeriod = [DTTimePeriod timePeriodWithSize:DTTimePeriodSizeSecond amount:period.durationInSeconds endingAt:[periods[0] EndDate]];
//Insert the updated object at the beginning of the periods array
[periods insertObject:modifiedPeriod atIndex:0];
}
else if (index > 0 && index < periods.count) {
//Shift time periods later if they fall after new period
[periods enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
//Shift later
if (idx >= index) {
[((DTTimePeriod *) obj) shiftLaterWithSize:DTTimePeriodSizeSecond amount:period.durationInSeconds];
}
}];
//Update bounds of period to make it fit in chain
DTTimePeriod *modifiedPeriod = [DTTimePeriod timePeriodWithSize:DTTimePeriodSizeSecond amount:period.durationInSeconds startingAt:[periods[index - 1] EndDate]];
//Insert the updated object at the beginning of the periods array
[periods insertObject:modifiedPeriod atIndex:index];
//Set object's variables with updated array values
[self updateVariables];
}
else {
[DTError throwInsertOutOfBoundsException:index array:periods];
}
}
-(void)removeTimePeriodAtIndex:(NSInteger)index{
//Make sure the index is within the operable bounds of the periods array
if (index >= 0 && index < periods.count) {
DTTimePeriod *period = periods[index];
//Shift time periods later if they fall after new period
[periods enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
//Shift earlier
if (idx > index) {
[((DTTimePeriod *) obj) shiftEarlierWithSize:DTTimePeriodSizeSecond amount:period.durationInSeconds];
}
}];
//Remove object
[periods removeObjectAtIndex:index];
//Set object's variables with updated array values
[self updateVariables];
}
else {
[DTError throwRemoveOutOfBoundsException:index array:periods];
}
}
-(void)removeLatestTimePeriod{
if (periods.count > 0) {
[periods removeLastObject];
//Update the object variables
if (periods.count > 0) {
//Set object's variables with updated array values
[self updateVariables];
}
else {
[self setVariablesNil];
}
}
}
-(void)removeEarliestTimePeriod{
if (periods > 0) {
//Shift time periods earlier
[periods enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
//Shift earlier to account for removal of first element in periods array
[((DTTimePeriod *) obj) shiftEarlierWithSize:DTTimePeriodSizeSecond amount:[periods[0] durationInSeconds]];
}];
//Remove first period
[periods removeObjectAtIndex:0];
//Update the object variables
if (periods.count > 0) {
//Set object's variables with updated array values
[self updateVariables];
}
else {
[self setVariablesNil];
}
}
}
#pragma mark - Chain Relationship
-(BOOL)isEqualToChain:(DTTimePeriodChain *)chain{
//Check class
if ([chain class] != [DTTimePeriodChain class]) {
[DTError throwBadTypeException:chain expectedClass:[DTTimePeriodChain class]];
return NO;
}
//Check group level characteristics for speed
if (![self hasSameCharacteristicsAs:chain]) {
return NO;
}
//Check whole chain
__block BOOL isEqual = YES;
[periods enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if (![chain[idx] isEqualToPeriod:obj]) {
isEqual = NO;
*stop = YES;
}
}];
return isEqual;
}
#pragma mark - Getters
-(DTTimePeriod *)First{
return First;
}
-(DTTimePeriod *)Last{
return Last;
}
#pragma mark - Helper Methods
-(void)updateVariables{
//Set helper variables
StartDate = [periods[0] StartDate];
EndDate = [periods[periods.count - 1] EndDate];
First = periods[0];
Last = periods[periods.count -1];
}
-(void)setVariablesNil{
//Set helper variables
StartDate = nil;
EndDate = nil;
First = nil;
Last = nil;
}
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DTTimePeriodCollection.h
================================================
// Copyright (C) 2014 by Matthew York
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and
// associated documentation files (the "Software"), to
// deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall
// be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import
#import "DTTimePeriodGroup.h"
@interface DTTimePeriodCollection : DTTimePeriodGroup
#pragma mark - Custom Init / Factory Methods
+(DTTimePeriodCollection *)collection;
#pragma mark - Collection Manipulation
-(void)addTimePeriod:(DTTimePeriod *)period;
-(void)insertTimePeriod:(DTTimePeriod *)period atIndex:(NSInteger)index;
-(void)removeTimePeriodAtIndex:(NSInteger)index;
#pragma mark - Sorting
-(void)sortByStartAscending;
-(void)sortByStartDescending;
-(void)sortByEndAscending;
-(void)sortByEndDescending;
-(void)sortByDurationAscending;
-(void)sortByDurationDescending;
#pragma mark - Collection Relationship
-(DTTimePeriodCollection *)periodsInside:(DTTimePeriod *)period;
-(DTTimePeriodCollection *)periodsIntersectedByDate:(NSDate *)date;
-(DTTimePeriodCollection *)periodsIntersectedByPeriod:(DTTimePeriod *)period;
-(DTTimePeriodCollection *)periodsOverlappedByPeriod:(DTTimePeriod *)period;
-(BOOL)isEqualToCollection:(DTTimePeriodCollection *)collection considerOrder:(BOOL)considerOrder;
#pragma mark - Helper Methods
-(DTTimePeriodCollection *)copy;
#pragma mark - Updates
-(void)updateVariables;
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DTTimePeriodCollection.m
================================================
// Copyright (C) 2014 by Matthew York
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and
// associated documentation files (the "Software"), to
// deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall
// be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "DTTimePeriodCollection.h"
#import "DTError.h"
#import "NSDate+DateTools.h"
@implementation DTTimePeriodCollection
#pragma mark - Custom Init / Factory Methods
/**
* Initializes a new instance of DTTimePeriodCollection
*
* @return DTTimePeriodCollection
*/
+(DTTimePeriodCollection *)collection{
return [[DTTimePeriodCollection alloc] init];
}
#pragma mark - Collection Manipulation
/**
* Adds a time period to the reciever.
*
* @param period DTTimePeriod - The time period to add to the collection
*/
-(void)addTimePeriod:(DTTimePeriod *)period{
if ([period isKindOfClass:[DTTimePeriod class]]) {
[periods addObject:period];
//Set object's variables with updated array values
[self updateVariables];
}
else {
[DTError throwBadTypeException:period expectedClass:[DTTimePeriod class]];
}
}
/**
* Inserts a time period to the receiver at a given index.
*
* @param period DTTimePeriod - The time period to insert into the collection
* @param index NSInteger - The index in the collection the time period is to be added at
*/
-(void)insertTimePeriod:(DTTimePeriod *)period atIndex:(NSInteger)index{
if ([period class] != [DTTimePeriod class]) {
[DTError throwBadTypeException:period expectedClass:[DTTimePeriod class]];
return;
}
if (index >= 0 && index < periods.count) {
[periods insertObject:period atIndex:index];
//Set object's variables with updated array values
[self updateVariables];
}
else {
[DTError throwInsertOutOfBoundsException:index array:periods];
}
}
/**
* Removes the time period at a given index from the collection
*
* @param index NSInteger - The index in the collection the time period is to be removed from
*/
-(void)removeTimePeriodAtIndex:(NSInteger)index{
if (index >= 0 && index < periods.count) {
[periods removeObjectAtIndex:index];
//Update the object variables
if (periods.count > 0) {
//Set object's variables with updated array values
[self updateVariables];
}
else {
[self setVariablesNil];
}
}
else {
[DTError throwRemoveOutOfBoundsException:index array:periods];
}
}
#pragma mark - Sorting
/**
* Sorts the time periods in the collection by earliest start date to latest start date.
*/
-(void)sortByStartAscending{
[periods sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [((DTTimePeriod *) obj1).StartDate compare:((DTTimePeriod *) obj2).StartDate];
}];
}
/**
* Sorts the time periods in the collection by latest start date to earliest start date.
*/
-(void)sortByStartDescending{
[periods sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [((DTTimePeriod *) obj2).StartDate compare:((DTTimePeriod *) obj1).StartDate];
}];
}
/**
* Sorts the time periods in the collection by earliest end date to latest end date.
*/
-(void)sortByEndAscending{
[periods sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [((DTTimePeriod *) obj1).EndDate compare:((DTTimePeriod *) obj2).EndDate];
}];
}
/**
* Sorts the time periods in the collection by latest end date to earliest end date.
*/
-(void)sortByEndDescending{
[periods sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [((DTTimePeriod *) obj2).EndDate compare:((DTTimePeriod *) obj1).EndDate];
}];
}
/**
* Sorts the time periods in the collection by how much time they span. Sorts smallest durations to longest.
*/
-(void)sortByDurationAscending{
[periods sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
if (((DTTimePeriod *) obj1).durationInSeconds < ((DTTimePeriod *) obj2).durationInSeconds) {
return NSOrderedAscending;
}
else {
return NSOrderedDescending;
}
return NSOrderedSame;
}];
}
/**
* Sorts the time periods in the collection by how much time they span. Sorts longest durations to smallest.
*/
-(void)sortByDurationDescending{
[periods sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
if (((DTTimePeriod *) obj1).durationInSeconds > ((DTTimePeriod *) obj2).durationInSeconds) {
return NSOrderedAscending;
}
else {
return NSOrderedDescending;
}
return NSOrderedSame;
}];
}
#pragma mark - Collection Relationship
/**
* Returns an instance of DTTimePeriodCollection with all the time periods in the receiver that fall inside a given time period.
* Time periods of the receiver must have a start date and end date within the closed interval of the period provided to be included.
*
* @param period DTTimePeriod - The time period to check against the receiver's time periods.
*
* @return DTTimePeriodCollection
*/
-(DTTimePeriodCollection *)periodsInside:(DTTimePeriod *)period{
DTTimePeriodCollection *collection = [[DTTimePeriodCollection alloc] init];
if ([period isKindOfClass:[DTTimePeriod class]]) {
[periods enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([((DTTimePeriod *) obj) isInside:period]) {
[collection addTimePeriod:obj];
}
}];
}
else {
[DTError throwBadTypeException:period expectedClass:[DTTimePeriod class]];
}
return collection;
}
/**
* Returns an instance of DTTimePeriodCollection with all the time periods in the receiver that intersect a given date.
* Time periods of the receiver must have a start date earlier than or equal to the comparison date and an end date later than or equal to the comparison date to be included
*
* @param date NSDate - The date to check against the receiver's time periods
*
* @return DTTimePeriodCollection
*/
-(DTTimePeriodCollection *)periodsIntersectedByDate:(NSDate *)date{
DTTimePeriodCollection *collection = [[DTTimePeriodCollection alloc] init];
if ([date isKindOfClass:[NSDate class]]) {
[periods enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([((DTTimePeriod *) obj) containsDate:date interval:DTTimePeriodIntervalClosed]) {
[collection addTimePeriod:obj];
}
}];
}
else {
[DTError throwBadTypeException:date expectedClass:[NSDate class]];
}
return collection;
}
/**
* Returns an instance of DTTimePeriodCollection with all the time periods in the receiver that intersect a given time period.
* Intersection with the given time period includes other time periods that simply touch it. (i.e. one's start date is equal to another's end date)
*
* @param period DTTimePeriod - The time period to check against the receiver's time periods.
*
* @return DTTimePeriodCollection
*/
-(DTTimePeriodCollection *)periodsIntersectedByPeriod:(DTTimePeriod *)period{
DTTimePeriodCollection *collection = [[DTTimePeriodCollection alloc] init];
if ([period isKindOfClass:[DTTimePeriod class]]) {
[periods enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([((DTTimePeriod *) obj) intersects:period]) {
[collection addTimePeriod:obj];
}
}];
}
else {
[DTError throwBadTypeException:period expectedClass:[DTTimePeriod class]];
}
return collection;
}
/**
* Returns an instance of DTTimePeriodCollection with all the time periods in the receiver that overlap a given time period.
* Overlap with the given time period does NOT include other time periods that simply touch it. (i.e. one's start date is equal to another's end date)
*
* @param period DTTimePeriod - The time period to check against the receiver's time periods.
*
* @return DTTimePeriodCollection
*/
-(DTTimePeriodCollection *)periodsOverlappedByPeriod:(DTTimePeriod *)period{
DTTimePeriodCollection *collection = [[DTTimePeriodCollection alloc] init];
[periods enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([((DTTimePeriod *) obj) overlapsWith:period]) {
[collection addTimePeriod:obj];
}
}];
return collection;
}
/**
* Returns a BOOL representing whether the receiver is equal to a given DTTimePeriodCollection. Equality requires the start and end dates to be the same, and all time periods to be the same.
*
* If you would like to take the order of the time periods in two collections into consideration, you may do so with the considerOrder BOOL
*
* @param collection DTTimePeriodCollection - The collection to compare with the receiver
* @param considerOrder BOOL - Option for whether to account for the time periods order in the test for equality. YES considers order, NO does not.
*
* @return BOOL
*/
-(BOOL)isEqualToCollection:(DTTimePeriodCollection *)collection considerOrder:(BOOL)considerOrder{
//Check class
if ([collection class] != [DTTimePeriodCollection class]) {
[DTError throwBadTypeException:collection expectedClass:[DTTimePeriodCollection class]];
return NO;
}
//Check group level characteristics for speed
if (![self hasSameCharacteristicsAs:collection]) {
return NO;
}
//Default to equality and look for inequality
__block BOOL isEqual = YES;
if (considerOrder) {
[periods enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if (![collection[idx] isEqualToPeriod:obj]) {
isEqual = NO;
*stop = YES;
}
}];
}
else {
__block DTTimePeriodCollection *collectionCopy = [collection copy];
[periods enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
__block BOOL innerMatch = NO;
__block NSInteger matchIndex = 0; //We will remove matches to account for duplicates and to help speed
for (int ii = 0; ii < collectionCopy.count; ii++) {
if ([obj isEqualToPeriod:collectionCopy[ii]]) {
innerMatch = YES;
matchIndex = ii;
break;
}
}
//If there was a match found, stop
if (!innerMatch) {
isEqual = NO;
*stop = YES;
}
else {
[collectionCopy removeTimePeriodAtIndex:matchIndex];
}
}];
}
return isEqual;
}
#pragma mark - Helper Methods
-(void)updateVariables{
//Set helper variables
__block NSDate *startDate = [NSDate distantFuture];
__block NSDate *endDate = [NSDate distantPast];
[periods enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([((DTTimePeriod *) obj).StartDate isEarlierThan:startDate]) {
startDate = ((DTTimePeriod *) obj).StartDate;
}
if ([((DTTimePeriod *) obj).EndDate isLaterThan:endDate]) {
endDate = ((DTTimePeriod *) obj).EndDate;
}
}];
//Make assignments after evaluation
StartDate = startDate;
EndDate = endDate;
}
-(void)setVariablesNil{
//Set helper variables
StartDate = nil;
EndDate = nil;
}
/**
* Returns a new instance of DTTimePeriodCollection that is an exact copy of the receiver, but with differnt memory references, etc.
*
* @return DTTimePeriodCollection
*/
-(DTTimePeriodCollection *)copy{
DTTimePeriodCollection *collection = [DTTimePeriodCollection collection];
[periods enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[collection addTimePeriod:[obj copy]];
}];
return collection;
}
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DTTimePeriodGroup.h
================================================
// Copyright (C) 2014 by Matthew York
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and
// associated documentation files (the "Software"), to
// deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall
// be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import
#import "DTTimePeriod.h"
@interface DTTimePeriodGroup : NSObject {
@protected
NSMutableArray *periods;
NSDate *StartDate;
NSDate *EndDate;
}
@property (nonatomic, readonly) NSDate *StartDate;
@property (nonatomic, readonly) NSDate *EndDate;
//Here we will use object subscripting to help create the illusion of an array
- (id)objectAtIndexedSubscript:(NSUInteger)index; //getter
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)index; //setter
#pragma mark - Group Info
-(double)durationInYears;
-(double)durationInWeeks;
-(double)durationInDays;
-(double)durationInHours;
-(double)durationInMinutes;
-(double)durationInSeconds;
-(NSDate *)StartDate;
-(NSDate *)EndDate;
-(NSInteger)count;
#pragma mark - Chain Time Manipulation
-(void)shiftEarlierWithSize:(DTTimePeriodSize)size;
-(void)shiftEarlierWithSize:(DTTimePeriodSize)size amount:(NSInteger)amount;
-(void)shiftLaterWithSize:(DTTimePeriodSize)size;
-(void)shiftLaterWithSize:(DTTimePeriodSize)size amount:(NSInteger)amount;
#pragma mark - Comparison
-(BOOL)hasSameCharacteristicsAs:(DTTimePeriodGroup *)group;
#pragma mark - Updates
-(void)updateVariables;
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DTTimePeriodGroup.m
================================================
// Copyright (C) 2014 by Matthew York
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and
// associated documentation files (the "Software"), to
// deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall
// be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "DTTimePeriodGroup.h"
#import "NSDate+DateTools.h"
@interface DTTimePeriodGroup ()
@end
@implementation DTTimePeriodGroup
-(id) init
{
if (self = [super init]) {
periods = [[NSMutableArray alloc] init];
}
return self;
}
- (id)objectAtIndexedSubscript:(NSUInteger)index
{
return periods[index];
}
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)index {
periods[index] = obj;
}
#pragma mark - Group Info
/**
* Returns the duration of the receiver in years
*
* @return NSInteger
*/
-(double)durationInYears {
if (self.StartDate && self.EndDate) {
return [self.StartDate yearsEarlierThan:self.EndDate];
}
return 0;
}
/**
* Returns the duration of the receiver in weeks
*
* @return double
*/
-(double)durationInWeeks {
if (self.StartDate && self.EndDate) {
return [self.StartDate weeksEarlierThan:self.EndDate];
}
return 0;
}
/**
* Returns the duration of the receiver in days
*
* @return double
*/
-(double)durationInDays {
if (self.StartDate && self.EndDate) {
return [self.StartDate daysEarlierThan:self.EndDate];
}
return 0;
}
/**
* Returns the duration of the receiver in hours
*
* @return double
*/
-(double)durationInHours {
if (self.StartDate && self.EndDate) {
return [self.StartDate hoursEarlierThan:self.EndDate];
}
return 0;
}
/**
* Returns the duration of the receiver in minutes
*
* @return double
*/
-(double)durationInMinutes {
if (self.StartDate && self.EndDate) {
return [self.StartDate minutesEarlierThan:self.EndDate];
}
return 0;
}
/**
* Returns the duration of the receiver in seconds
*
* @return double
*/
-(double)durationInSeconds {
if (self.StartDate && self.EndDate) {
return [self.StartDate secondsEarlierThan:self.EndDate];
}
return 0;
}
/**
* Returns the NSDate representing the earliest date in the DTTimePeriodGroup (or subclass)
*
* @return NSDate
*/
-(NSDate *)StartDate{
return StartDate;
}
/**
* Returns the NSDate representing the latest date in the DTTimePeriodGroup (or subclass)
*
* @return NSDate
*/
-(NSDate *)EndDate{
return EndDate;
}
/**
* The total number of DTTimePeriods in the group
*
* @return NSInteger
*/
-(NSInteger)count{
return periods.count;
}
/**
* Returns a BOOL if the receiver and the comparison group have the same metadata (i.e. number of periods, start & end date, etc.)
* Returns YES if they share the same characteristics, otherwise NO
*
* @param group The group to compare with the receiver
*
* @return BOOL
*/
-(BOOL)hasSameCharacteristicsAs:(DTTimePeriodGroup *)group{
//Check characteristics first for speed
if (group.count != self.count) {
return NO;
}
else if (!group.StartDate && !group.EndDate && !self.StartDate && !self.EndDate){
return YES;
}
else if (![group.StartDate isEqualToDate:self.StartDate] || ![group.EndDate isEqualToDate:self.EndDate]){
return NO;
}
return YES;
}
#pragma mark - Chain Time Manipulation
/**
* Shifts all the time periods in the collection to an earlier date by the given size
*
* @param size DTTimePeriodSize - The desired size of the shift
*/
-(void)shiftEarlierWithSize:(DTTimePeriodSize)size{
[self shiftEarlierWithSize:size amount:1];
}
/**
* Shifts all the time periods in the collection to an earlier date by the given size and amount.
* The amount acts as a multiplier to the size (i.e. "2 weeks" or "4 years")
*
* @param size DTTimePeriodSize - The desired size of the shift
* @param amount NSInteger - Multiplier for the size
*/
-(void)shiftEarlierWithSize:(DTTimePeriodSize)size amount:(NSInteger)amount{
if (periods) {
[periods enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[((DTTimePeriod *)obj) shiftEarlierWithSize:size amount:amount];
}];
[self updateVariables];
}
}
/**
* Shifts all the time periods in the collection to a later date by the given size
*
* @param size DTTimePeriodSize - The desired size of the shift
*/
-(void)shiftLaterWithSize:(DTTimePeriodSize)size{
[self shiftLaterWithSize:size amount:1];
}
/**
* Shifts all the time periods in the collection to an later date by the given size and amount.
* The amount acts as a multiplier to the size (i.e. "2 weeks" or "4 years")
*
* @param size DTTimePeriodSize - The desired size of the shift
* @param amount NSInteger - Multiplier for the size
*/
-(void)shiftLaterWithSize:(DTTimePeriodSize)size amount:(NSInteger)amount{
if (periods) {
[periods enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[((DTTimePeriod *)obj) shiftLaterWithSize:size amount:amount];
}];
[self updateVariables];
}
}
#pragma mark - Updates
-(void)updateVariables{}
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/bg.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "преди %d дена";
/* No comment provided by engineer. */
"%d hours ago" = "преди %d часа";
/* No comment provided by engineer. */
"%d minutes ago" = "преди %d минути";
/* No comment provided by engineer. */
"%d months ago" = "преди %d месеца";
/* No comment provided by engineer. */
"%d seconds ago" = "преди %d секунди";
/* No comment provided by engineer. */
"%d weeks ago" = "преди %d седмици";
/* No comment provided by engineer. */
"%d years ago" = "преди %d години";
/* No comment provided by engineer. */
"A minute ago" = "преди минута";
/* No comment provided by engineer. */
"An hour ago" = "преди час";
/* No comment provided by engineer. */
"Just now" = "току що";
/* No comment provided by engineer. */
"Last month" = "през последния месец";
/* No comment provided by engineer. */
"Last week" = "през последната седмица";
/* No comment provided by engineer. */
"Last year" = "през последната година";
/* No comment provided by engineer. */
"Yesterday" = "вчера";
/* No comment provided by engineer. */
"1 year ago" = "преди 1 година";
/* No comment provided by engineer. */
"1 month ago" = "преди 1 месец";
/* No comment provided by engineer. */
"1 week ago" = "преди 1 седмица";
/* No comment provided by engineer. */
"1 day ago" = "преди 1 ден";
/* No comment provided by engineer. */
"This morning" = "тази сутрин";
/* No comment provided by engineer. */
"This afternoon" = "тази вечер";
/* No comment provided by engineer. */
"Today" = "днес";
/* No comment provided by engineer. */
"This week" = "тази седмица";
/* No comment provided by engineer. */
"This month" = "този месец";
/* No comment provided by engineer. */
"This year" = "тази година";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/ca.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "Fa %d dies";
/* No comment provided by engineer. */
"%d hours ago" = "Fa %d hores";
/* No comment provided by engineer. */
"%d minutes ago" = "Fa %d minuts";
/* No comment provided by engineer. */
"%d months ago" = "Fa %d mesos";
/* No comment provided by engineer. */
"%d seconds ago" = "Fa %d segons";
/* No comment provided by engineer. */
"%d weeks ago" = "Fa %d setmanes";
/* No comment provided by engineer. */
"%d years ago" = "Fa %d anys";
/* No comment provided by engineer. */
"A minute ago" = "Fa un minut";
/* No comment provided by engineer. */
"An hour ago" = "Fa una hora";
/* No comment provided by engineer. */
"Just now" = "Fa un moment";
/* No comment provided by engineer. */
"Last month" = "El mes passat";
/* No comment provided by engineer. */
"Last week" = "La setmana passada";
/* No comment provided by engineer. */
"Last year" = "L'any passat";
/* No comment provided by engineer. */
"Yesterday" = "Ahir";
/* No comment provided by engineer. */
"1 year ago" = "Fa un any";
/* No comment provided by engineer. */
"1 month ago" = "Fa un mes";
/* No comment provided by engineer. */
"1 week ago" = "Fa una setmana";
/* No comment provided by engineer. */
"1 day ago" = "Fa un dia";
/* No comment provided by engineer. */
"This morning" = "Aquest matí";
/* No comment provided by engineer. */
"This afternoon" = "Aquesta tarda";
/* No comment provided by engineer. */
"Today" = "Avui";
/* No comment provided by engineer. */
"This week" = "Aquesta setmana";
/* No comment provided by engineer. */
"This month" = "Aquest mes";
/* No comment provided by engineer. */
"This year" = "Aquest any";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/cs.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "Před %d dny";
/* No comment provided by engineer. */
"%d hours ago" = "Před %d hodinami";
/* No comment provided by engineer. */
"%d minutes ago" = "Před %d minutami";
/* No comment provided by engineer. */
"%d months ago" = "Před %d měsíci";
/* No comment provided by engineer. */
"%d seconds ago" = "Před %d sekundami";
/* No comment provided by engineer. */
"%d weeks ago" = "Před %d týdny";
/* No comment provided by engineer. */
"%d years ago" = "Před %d lety";
/* No comment provided by engineer. */
"A minute ago" = "Před minutou";
/* No comment provided by engineer. */
"An hour ago" = "Před hodinou";
/* No comment provided by engineer. */
"Just now" = "Právě teď";
/* No comment provided by engineer. */
"Last month" = "Minulý měsíc";
/* No comment provided by engineer. */
"Last week" = "Minulý týden";
/* No comment provided by engineer. */
"Last year" = "Minulý rok";
/* No comment provided by engineer. */
"Yesterday" = "Včera";
/* No comment provided by engineer. */
"1 year ago" = "Před rokem";
/* No comment provided by engineer. */
"1 month ago" = "Před měsícem";
/* No comment provided by engineer. */
"1 week ago" = "Před týdnem";
/* No comment provided by engineer. */
"1 day ago" = "Předevčírem";
/* No comment provided by engineer. */
"This morning" = "Dnes dopoledne";
/* No comment provided by engineer. */
"This afternoon" = "Dnes odpoledne";
/* No comment provided by engineer. */
"Today" = "Dnes";
/* No comment provided by engineer. */
"This week" = "Tento týden";
/* No comment provided by engineer. */
"This month" = "Tento měsíc";
/* No comment provided by engineer. */
"This year" = "Letos";
/* Short format for */
"%dy" = "%dr"; // year
"%dM" = "%dM"; // month
"%dw" = "%dt"; // week
"%dd" = "%dd"; // day
"%dh" = "%dh"; // hour
"%dm" = "%dm"; // minute
"%ds" = "%ds"; // second
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/cy.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d diwrnod yn ôl";
/* No comment provided by engineer. */
"%d hours ago" = "%d awr yn ôl";
/* No comment provided by engineer. */
"%d minutes ago" = "%d munud yn ôl";
/* No comment provided by engineer. */
"%d months ago" = "%d mis yn ôl";
/* No comment provided by engineer. */
"%d seconds ago" = "%d eiliad yn ôl";
/* No comment provided by engineer. */
"%d weeks ago" = "%d wythnos yn ôl";
/* No comment provided by engineer. */
"%d years ago" = "%d mlynydd yn ôl";
/* No comment provided by engineer. */
"A minute ago" = "Un munud yn ôl";
/* No comment provided by engineer. */
"An hour ago" = "Un awr yn ôl";
/* No comment provided by engineer. */
"Just now" = "Nawr";
/* No comment provided by engineer. */
"Last month" = "Mis diwethaf";
/* No comment provided by engineer. */
"Last week" = "Wythnos diwethaf";
/* No comment provided by engineer. */
"Last year" = "Llynedd";
/* No comment provided by engineer. */
"Yesterday" = "Ddoe";
/* No comment provided by engineer. */
"1 year ago" = "1 flynydd yn ôl";
/* No comment provided by engineer. */
"1 month ago" = "1 mis yn ôl";
/* No comment provided by engineer. */
"1 week ago" = "1 wythnos yn ôl";
/* No comment provided by engineer. */
"1 day ago" = "1 diwrnod yn ôl";
/* No comment provided by engineer. */
"This morning" = "Y bore ma";
/* No comment provided by engineer. */
"This afternoon" = "Y penwythnos hon";
/* No comment provided by engineer. */
"Today" = "Heddiw";
/* No comment provided by engineer. */
"This week" = "Yr wythnos hon";
/* No comment provided by engineer. */
"This month" = "Y mis hon";
/* No comment provided by engineer. */
"This year" = "Eleni";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/da.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d dage siden";
/* No comment provided by engineer. */
"%d hours ago" = "%d timer siden";
/* No comment provided by engineer. */
"%d minutes ago" = "%d minutter siden";
/* No comment provided by engineer. */
"%d months ago" = "%d måneder siden";
/* No comment provided by engineer. */
"%d seconds ago" = "%d sekunder siden";
/* No comment provided by engineer. */
"%d weeks ago" = "%d uger siden";
/* No comment provided by engineer. */
"%d years ago" = "%d år siden";
/* No comment provided by engineer. */
"A minute ago" = "Et minut siden";
/* No comment provided by engineer. */
"An hour ago" = "En time siden";
/* No comment provided by engineer. */
"Just now" = "Lige nu";
/* No comment provided by engineer. */
"Last month" = "Sidste måned";
/* No comment provided by engineer. */
"Last week" = "Sidste uge";
/* No comment provided by engineer. */
"Last year" = "Sidste år";
/* No comment provided by engineer. */
"Yesterday" = "I går";
/* No comment provided by engineer. */
"1 year ago" = "1 år siden";
/* No comment provided by engineer. */
"1 month ago" = "1 måned siden";
/* No comment provided by engineer. */
"1 week ago" = "1 uge siden";
/* No comment provided by engineer. */
"1 day ago" = "1 dag siden";
/* No comment provided by engineer. */
"This morning" = "Her til morgen";
/* No comment provided by engineer. */
"This afternoon" = "Her til eftermiddag";
/* No comment provided by engineer. */
"Today" = "I dag";
/* No comment provided by engineer. */
"This week" = "Denne uge";
/* No comment provided by engineer. */
"This month" = "Denne måned";
/* No comment provided by engineer. */
"This year" = "Dette år";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/de.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "Vor %d Tagen";
/* No comment provided by engineer. */
"%d hours ago" = "Vor %d Stunden";
/* No comment provided by engineer. */
"%d minutes ago" = "Vor %d Minuten";
/* No comment provided by engineer. */
"%d months ago" = "Vor %d Monaten";
/* No comment provided by engineer. */
"%d seconds ago" = "Vor %d Sekunden";
/* No comment provided by engineer. */
"%d weeks ago" = "Vor %d Wochen";
/* No comment provided by engineer. */
"%d years ago" = "Vor %d Jahren";
/* No comment provided by engineer. */
"A minute ago" = "Vor einer Minute";
/* No comment provided by engineer. */
"An hour ago" = "Vor einer Stunde";
/* No comment provided by engineer. */
"Just now" = "Gerade eben";
/* No comment provided by engineer. */
"Last month" = "Letzten Monat";
/* No comment provided by engineer. */
"Last week" = "Letzte Woche";
/* No comment provided by engineer. */
"Last year" = "Letztes Jahr";
/* No comment provided by engineer. */
"Yesterday" = "Gestern";
/* No comment provided by engineer. */
"1 year ago" = "Vor 1 Jahr";
/* No comment provided by engineer. */
"1 month ago" = "Vor 1 Monat";
/* No comment provided by engineer. */
"1 week ago" = "Vor 1 Woche";
/* No comment provided by engineer. */
"1 day ago" = "Vor 1 Tag";
/* No comment provided by engineer. */
"This morning" = "Heute Morgen";
/* No comment provided by engineer. */
"This afternoon" = "Heute Nachmittag";
/* No comment provided by engineer. */
"Today" = "Heute";
/* No comment provided by engineer. */
"This week" = "Diese Woche";
/* No comment provided by engineer. */
"This month" = "Diesen Monat";
/* No comment provided by engineer. */
"This year" = "Dieses Jahr";
/* Short format for */
"%dy" = "%dJ"; // year
"%dM" = "%dM"; // month
"%dw" = "%dW"; // week
"%dd" = "%dT"; // day
"%dh" = "%dh"; // hour
"%dm" = "%dm"; // minute
"%ds" = "%ds"; // second
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/en.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d days ago";
/* No comment provided by engineer. */
"%d hours ago" = "%d hours ago";
/* No comment provided by engineer. */
"%d minutes ago" = "%d minutes ago";
/* No comment provided by engineer. */
"%d months ago" = "%d months ago";
/* No comment provided by engineer. */
"%d seconds ago" = "%d seconds ago";
/* No comment provided by engineer. */
"%d weeks ago" = "%d weeks ago";
/* No comment provided by engineer. */
"%d years ago" = "%d years ago";
/* No comment provided by engineer. */
"A minute ago" = "A minute ago";
/* No comment provided by engineer. */
"An hour ago" = "An hour ago";
/* No comment provided by engineer. */
"Just now" = "Just now";
/* No comment provided by engineer. */
"Last month" = "Last month";
/* No comment provided by engineer. */
"Last week" = "Last week";
/* No comment provided by engineer. */
"Last year" = "Last year";
/* No comment provided by engineer. */
"Yesterday" = "Yesterday";
/* No comment provided by engineer. */
"1 year ago" = "1 year ago";
/* No comment provided by engineer. */
"1 month ago" = "1 month ago";
/* No comment provided by engineer. */
"1 week ago" = "1 week ago";
/* No comment provided by engineer. */
"1 day ago" = "1 day ago";
/* No comment provided by engineer. */
"1 hour ago" = "1 hour ago";
/* No comment provided by engineer. */
"1 minute ago" = "1 minute ago";
/* No comment provided by engineer. */
"1 second ago" = "1 second ago";
/* No comment provided by engineer. */
"This morning" = "This morning";
/* No comment provided by engineer. */
"This afternoon" = "This afternoon";
/* No comment provided by engineer. */
"Today" = "Today";
/* No comment provided by engineer. */
"This week" = "This week";
/* No comment provided by engineer. */
"This month" = "This month";
/* No comment provided by engineer. */
"This year" = "This year";
/* Short format for */
"%dy" = "%dy"; // year
"%dM" = "%dM"; // month
"%dw" = "%dw"; // week
"%dd" = "%dd"; // day
"%dh" = "%dh"; // hour
"%dm" = "%dm"; // minute
"%ds" = "%ds"; // second
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/es.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "Hace %d días";
/* No comment provided by engineer. */
"%d hours ago" = "Hace %d horas";
/* No comment provided by engineer. */
"%d minutes ago" = "Hace %d minutos";
/* No comment provided by engineer. */
"%d months ago" = "Hace %d meses";
/* No comment provided by engineer. */
"%d seconds ago" = "Hace %d segundos";
/* No comment provided by engineer. */
"%d weeks ago" = "Hace %d semanas";
/* No comment provided by engineer. */
"%d years ago" = "Hace %d años";
/* No comment provided by engineer. */
"A minute ago" = "Hace un minuto";
/* No comment provided by engineer. */
"An hour ago" = "Hace una hora";
/* No comment provided by engineer. */
"Just now" = "Ahora mismo";
/* No comment provided by engineer. */
"Last month" = "El mes pasado";
/* No comment provided by engineer. */
"Last week" = "La semana pasada";
/* No comment provided by engineer. */
"Last year" = "El año pasado";
/* No comment provided by engineer. */
"Yesterday" = "Ayer";
/* No comment provided by engineer. */
"1 year ago" = "Hace un año";
/* No comment provided by engineer. */
"1 month ago" = "Hace un mes";
/* No comment provided by engineer. */
"1 week ago" = "Hace una semana";
/* No comment provided by engineer. */
"1 day ago" = "Hace un día";
/* No comment provided by engineer. */
"This morning" = "Esta mañana";
/* No comment provided by engineer. */
"This afternoon" = "Esta tarde";
/* No comment provided by engineer. */
"Today" = "Hoy";
/* No comment provided by engineer. */
"This week" = "Esta semana";
/* No comment provided by engineer. */
"This month" = "Este mes";
/* No comment provided by engineer. */
"This year" = "Este año";
/* Short format for */
"%dy" = "%da"; // year
"%dM" = "%dM"; // month
"%dw" = "%dS"; // week
"%dd" = "%dd"; // day
"%dh" = "%dh"; // hour
"%dm" = "%dm"; // minute
"%ds" = "%ds"; // second
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/eu.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "Orain dela %d egun";
/* No comment provided by engineer. */
"%d hours ago" = "Orain dela %d ordu";
/* No comment provided by engineer. */
"%d minutes ago" = "Orain dela %d minutu";
/* No comment provided by engineer. */
"%d months ago" = "Orain dela %d hile";
/* No comment provided by engineer. */
"%d seconds ago" = "Orain dela %d segundu";
/* No comment provided by engineer. */
"%d weeks ago" = "Orain dela %d aste";
/* No comment provided by engineer. */
"%d years ago" = "Orain dela %d urte";
/* No comment provided by engineer. */
"A minute ago" = "Orain dela minutu bat";
/* No comment provided by engineer. */
"An hour ago" = "Orain dela ordu bat";
/* No comment provided by engineer. */
"Just now" = "Oraintxe bertan";
/* No comment provided by engineer. */
"Last month" = "Pasa den hilean";
/* No comment provided by engineer. */
"Last week" = "Pasa den astean";
/* No comment provided by engineer. */
"Last year" = "Pasa den urtean";
/* No comment provided by engineer. */
"Yesterday" = "Atzo";
/* No comment provided by engineer. */
"1 year ago" = "Orain dela urte bat";
/* No comment provided by engineer. */
"1 month ago" = "Orain dela hile bat";
/* No comment provided by engineer. */
"1 week ago" = "Orain dela aste bat";
/* No comment provided by engineer. */
"1 day ago" = "Orain dela egun bat";
/* No comment provided by engineer. */
"This morning" = "Gaur goizean";
/* No comment provided by engineer. */
"This afternoon" = "Gaur arratsaldean";
/* No comment provided by engineer. */
"Today" = "Gaur";
/* No comment provided by engineer. */
"This week" = "Aste honetan";
/* No comment provided by engineer. */
"This month" = "Hile honetan";
/* No comment provided by engineer. */
"This year" = "Urte honetan";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/fi.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d päivää sitten";
/* No comment provided by engineer. */
"%d hours ago" = "%d tuntia sitten";
/* No comment provided by engineer. */
"%d minutes ago" = "%d minuuttia sitten";
/* No comment provided by engineer. */
"%d months ago" = "%d kuukautta sitten";
/* No comment provided by engineer. */
"%d seconds ago" = "%d sekuntia sitten";
/* No comment provided by engineer. */
"%d weeks ago" = "%d viikkoa sitten";
/* No comment provided by engineer. */
"%d years ago" = "%d vuotta sitten";
/* No comment provided by engineer. */
"A minute ago" = "Minuutti sitten";
/* No comment provided by engineer. */
"An hour ago" = "Tunti sitten";
/* No comment provided by engineer. */
"Just now" = "Juuri äsken";
/* No comment provided by engineer. */
"Last month" = "Viime kuussa";
/* No comment provided by engineer. */
"Last week" = "Viime viikolla";
/* No comment provided by engineer. */
"Last year" = "Viime vuonna";
/* No comment provided by engineer. */
"Yesterday" = "Eilen";
/* No comment provided by engineer. */
"1 year ago" = "Vuosi sitten";
/* No comment provided by engineer. */
"1 month ago" = "Kuukausi sitten";
/* No comment provided by engineer. */
"1 week ago" = "Viikko sitten";
/* No comment provided by engineer. */
"1 day ago" = "Vuorokausi sitten";
/* No comment provided by engineer. */
"This morning" = "Tänä aamuna";
/* No comment provided by engineer. */
"This afternoon" = "Tänä iltapäivänä";
/* No comment provided by engineer. */
"Today" = "Tänään";
/* No comment provided by engineer. */
"This week" = "Tällä viikolla";
/* No comment provided by engineer. */
"This month" = "Tässä kuussa";
/* No comment provided by engineer. */
"This year" = "Tänä vuonna";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/fr.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "Il y a %d jours";
/* No comment provided by engineer. */
"%d hours ago" = "Il y a %d heures";
/* No comment provided by engineer. */
"%d minutes ago" = "Il y a %d minutes";
/* No comment provided by engineer. */
"%d months ago" = "Il y a %d mois";
/* No comment provided by engineer. */
"%d seconds ago" = "Il y a %d secondes";
/* No comment provided by engineer. */
"%d weeks ago" = "Il y a %d semaines";
/* No comment provided by engineer. */
"%d years ago" = "Il y a %d ans";
/* No comment provided by engineer. */
"A minute ago" = "Il y a une minute";
/* No comment provided by engineer. */
"An hour ago" = "Il y a une heure";
/* No comment provided by engineer. */
"Just now" = "A l'instant";
/* No comment provided by engineer. */
"Last month" = "Le mois dernier";
/* No comment provided by engineer. */
"Last week" = "La semaine dernière";
/* No comment provided by engineer. */
"Last year" = "L'année dernière";
/* No comment provided by engineer. */
"Yesterday" = "Hier";
/* No comment provided by engineer. */
"1 year ago" = "Il y a 1 an";
/* No comment provided by engineer. */
"1 month ago" = "Il y a 1 mois";
/* No comment provided by engineer. */
"1 week ago" = "Il y a 1 semaine";
/* No comment provided by engineer. */
"1 day ago" = "Il y a 1 jour";
/* No comment provided by engineer. */
"This morning" = "Ce matin";
/* No comment provided by engineer. */
"This afternoon" = "Cet après-midi";
/* No comment provided by engineer. */
"Today" = "Aujourd'hui";
/* No comment provided by engineer. */
"This week" = "Cette semaine";
/* No comment provided by engineer. */
"This month" = "Ce mois-ci";
/* No comment provided by engineer. */
"This year" = "Cette année";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/gu.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d દિવસ પહેલા";
/* No comment provided by engineer. */
"%d hours ago" = "%d કલાક પહેલા";
/* No comment provided by engineer. */
"%d minutes ago" = "%d મિનિટ પહેલા";
/* No comment provided by engineer. */
"%d months ago" = "%d મહિના પહેલા";
/* No comment provided by engineer. */
"%d seconds ago" = "%d સેકન્ડ પહેલા";
/* No comment provided by engineer. */
"%d weeks ago" = "%d અઠવાડિયા પહેલા";
/* No comment provided by engineer. */
"%d years ago" = "%d વર્ષ પહેલા";
/* No comment provided by engineer. */
"A minute ago" = "એક મિનિટ પહેલા";
/* No comment provided by engineer. */
"An hour ago" = "એક કલાક પહેલા";
/* No comment provided by engineer. */
"Just now" = "હમણાં";
/* No comment provided by engineer. */
"Last month" = "ગયા મહિને";
/* No comment provided by engineer. */
"Last week" = "ગયા અઠવાડિયે";
/* No comment provided by engineer. */
"Last year" = "ગયા વર્ષે";
/* No comment provided by engineer. */
"Yesterday" = "ગઈ કાલે";
/* No comment provided by engineer. */
"1 year ago" = "1 વર્ષ પહેલાં";
/* No comment provided by engineer. */
"1 month ago" = "1 મહિનો પહેલા";
/* No comment provided by engineer. */
"1 week ago" = "1 અઠવાડિયું પહેલા";
/* No comment provided by engineer. */
"1 day ago" = "1 દિવસ પહેલાં";
/* No comment provided by engineer. */
"1 hour ago" = "1 કલાક પહેલા";
/* No comment provided by engineer. */
"1 minute ago" = "1 મિનિટ પહેલા";
/* No comment provided by engineer. */
"1 second ago" = "1 સેકન્ડ પહેલા";
/* No comment provided by engineer. */
"This morning" = "આ સવારે";
/* No comment provided by engineer. */
"This afternoon" = "આજે બપોરે";
/* No comment provided by engineer. */
"Today" = "આજે";
/* No comment provided by engineer. */
"This week" = "આ અઠવાડિયેું";
/* No comment provided by engineer. */
"This month" = "આ મહિને";
/* No comment provided by engineer. */
"This year" = "આ વર્ષે";
/* Short format for */
"%dy" = "%dy"; // year
"%dM" = "%dM"; // month
"%dw" = "%dw"; // week
"%dd" = "%dd"; // day
"%dh" = "%dh"; // hour
"%dm" = "%dm"; // minute
"%ds" = "%ds"; // second
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/he.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "לפני %d ימים";
/* No comment provided by engineer. */
"%d hours ago" = "לפני %d שעות";
/* No comment provided by engineer. */
"%d minutes ago" = "לפני %d דקות";
/* No comment provided by engineer. */
"%d months ago" = "לפני %d חודשים";
/* No comment provided by engineer. */
"%d seconds ago" = "לפני %d שניות";
/* No comment provided by engineer. */
"%d weeks ago" = "לפני %d שבועות";
/* No comment provided by engineer. */
"%d years ago" = "לפני %d שנים";
/* No comment provided by engineer. */
"A minute ago" = "לפני דקה";
/* No comment provided by engineer. */
"An hour ago" = "לפני שעה";
/* No comment provided by engineer. */
"Just now" = "ממש עכשיו";
/* No comment provided by engineer. */
"Last month" = "בחודש שעבר";
/* No comment provided by engineer. */
"Last week" = "בשבוע שעבר";
/* No comment provided by engineer. */
"Last year" = "בשנה שעברה";
/* No comment provided by engineer. */
"Yesterday" = "אתמול";
/* No comment provided by engineer. */
"1 year ago" = "לפני שנה";
/* No comment provided by engineer. */
"1 month ago" = "לפני חודש";
/* No comment provided by engineer. */
"1 week ago" = "לפני שבוע";
/* No comment provided by engineer. */
"1 day ago" = "לפני יום";
/* No comment provided by engineer. */
"This morning" = "הבוקר";
/* No comment provided by engineer. */
"This afternoon" = "בצהריים";
/* No comment provided by engineer. */
"Today" = "היום";
/* No comment provided by engineer. */
"This week" = "השבוע";
/* No comment provided by engineer. */
"This month" = "החודש";
/* No comment provided by engineer. */
"This year" = "השנה";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/hi.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d दिन पहले";
/* No comment provided by engineer. */
"%d hours ago" = "%d घंटे पहले";
/* No comment provided by engineer. */
"%d minutes ago" = "%d मिनट पहले";
/* No comment provided by engineer. */
"%d months ago" = "%d महीन पहले";
/* No comment provided by engineer. */
"%d seconds ago" = "%d सेकंड पहले";
/* No comment provided by engineer. */
"%d weeks ago" = "%d हफ्ते पहले";
/* No comment provided by engineer. */
"%d years ago" = "%d साल पहले";
/* No comment provided by engineer. */
"A minute ago" = "एक मिनट पहले";
/* No comment provided by engineer. */
"An hour ago" = "एक घंटे पहले";
/* No comment provided by engineer. */
"Just now" = "बस अभी";
/* No comment provided by engineer. */
"Last month" = "पिछले महीने";
/* No comment provided by engineer. */
"Last week" = "पिछले हफ्ते";
/* No comment provided by engineer. */
"Last year" = "पिछले साल";
/* No comment provided by engineer. */
"Yesterday" = "कल";
/* No comment provided by engineer. */
"1 year ago" = "1 साल पहले";
/* No comment provided by engineer. */
"1 month ago" = "1 महीने पहले";
/* No comment provided by engineer. */
"1 week ago" = "1 हफ्ते पहले";
/* No comment provided by engineer. */
"1 day ago" = "1 दिन पहले";
/* No comment provided by engineer. */
"1 hour ago" = "1 घंटे पहले";
/* No comment provided by engineer. */
"1 minute ago" = "1 मिनट पहले";
/* No comment provided by engineer. */
"1 second ago" = "1 सेकंड पहले";
/* No comment provided by engineer. */
"This morning" = "आज सुबह";
/* No comment provided by engineer. */
"This afternoon" = "यह दोपहर";
/* No comment provided by engineer. */
"Today" = "आज";
/* No comment provided by engineer. */
"This week" = "इस सप्ताह";
/* No comment provided by engineer. */
"This month" = "इस महीने";
/* No comment provided by engineer. */
"This year" = "इस साल";
/* Short format for */
"%dy" = "%dy"; // year
"%dM" = "%dM"; // month
"%dw" = "%dw"; // week
"%dd" = "%dd"; // day
"%dh" = "%dh"; // hour
"%dm" = "%dm"; // minute
"%ds" = "%ds"; // second
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/hr.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d dana";
/* No comment provided by engineer. */
"%d hours ago" = "%d prime sati";
/* No comment provided by engineer. */
"%d minutes ago" = "%d prije minuta";
/* No comment provided by engineer. */
"%d months ago" = "%d prije nekoliko mjeseci";
/* No comment provided by engineer. */
"%d seconds ago" = "%d sekunde prije";
/* No comment provided by engineer. */
"%d weeks ago" = "%d prije nekoliko tjedana";
/* No comment provided by engineer. */
"%d years ago" = "%d prije nekoliko godina";
/* No comment provided by engineer. */
"A minute ago" = "prije minute";
/* No comment provided by engineer. */
"An hour ago" = "prije sat vremena";
/* No comment provided by engineer. */
"Just now" = "upravo sada";
/* No comment provided by engineer. */
"Last month" = "prosli mjesec";
/* No comment provided by engineer. */
"Last week" = "prosli tjedan";
/* No comment provided by engineer. */
"Last year" = "prosle godine";
/* No comment provided by engineer. */
"Yesterday" = "jucer";
/* No comment provided by engineer. */
"1 year ago" = "Prije 1 godina";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/hu.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d napja";
/* No comment provided by engineer. */
"%d hours ago" = "%d órája";
/* No comment provided by engineer. */
"%d minutes ago" = "%d perce";
/* No comment provided by engineer. */
"%d months ago" = "%d hónapja";
/* No comment provided by engineer. */
"%d seconds ago" = "%d másodperce";
/* No comment provided by engineer. */
"%d weeks ago" = "%d hete";
/* No comment provided by engineer. */
"%d years ago" = "%d éve";
/* No comment provided by engineer. */
"A minute ago" = "Egy perccel ezelőtt";
/* No comment provided by engineer. */
"An hour ago" = "Egy órával ezelőtt";
/* No comment provided by engineer. */
"Just now" = "Az imént";
/* No comment provided by engineer. */
"Last month" = "Az előző hónapban";
/* No comment provided by engineer. */
"Last week" = "Az előző héten";
/* No comment provided by engineer. */
"Last year" = "Tavaly";
/* No comment provided by engineer. */
"Yesterday" = "Tegnap";
/* No comment provided by engineer. */
"1 year ago" = "Tavaly";
/* No comment provided by engineer. */
"1 month ago" = "Egy hónapja";
/* No comment provided by engineer. */
"1 week ago" = "Egy hete";
/* No comment provided by engineer. */
"1 day ago" = "Tegnap";
/* No comment provided by engineer. */
"This morning" = "Ma reggel";
/* No comment provided by engineer. */
"This afternoon" = "Ma délután";
/* No comment provided by engineer. */
"Today" = "Ma";
/* No comment provided by engineer. */
"This week" = "Ezen a héten";
/* No comment provided by engineer. */
"This month" = "Ebben a hónapban";
/* No comment provided by engineer. */
"This year" = "Idén";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/id.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d hari yang lalu";
/* No comment provided by engineer. */
"%d hours ago" = "%d jam yang lalu";
/* No comment provided by engineer. */
"%d minutes ago" = "%d menit yang lalu";
/* No comment provided by engineer. */
"%d months ago" = "%d bulan yang lalu";
/* No comment provided by engineer. */
"%d seconds ago" = "%d detik yang lalu";
/* No comment provided by engineer. */
"%d weeks ago" = "%d minggu yang lalu";
/* No comment provided by engineer. */
"%d years ago" = "%d tahun yang lalu";
/* No comment provided by engineer. */
"A minute ago" = "Semenit yang lalu";
/* No comment provided by engineer. */
"An hour ago" = "Sejam yang lalu";
/* No comment provided by engineer. */
"Just now" = "Sekarang";
/* No comment provided by engineer. */
"Last month" = "Bulan lalu";
/* No comment provided by engineer. */
"Last week" = "Minggu lalu";
/* No comment provided by engineer. */
"Last year" = "Tahun lalu";
/* No comment provided by engineer. */
"Yesterday" = "Kemarin";
/* No comment provided by engineer. */
"1 year ago" = "1 tahun yang lalu";
/* No comment provided by engineer. */
"1 month ago" = "1 bulan yang lalu";
/* No comment provided by engineer. */
"1 week ago" = "1 minggu yang lalu";
/* No comment provided by engineer. */
"1 day ago" = "1 hari yang lalu";
/* No comment provided by engineer. */
"This morning" = "Pagi ini";
/* No comment provided by engineer. */
"This afternoon" = "Sore ini";
/* No comment provided by engineer. */
"Today" = "Hari ini";
/* No comment provided by engineer. */
"This week" = "Minggu ini";
/* No comment provided by engineer. */
"This month" = "Bulan ini";
/* No comment provided by engineer. */
"This year" = "Tahun ini";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/is.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d dögum síðan";
/* No comment provided by engineer. */
"%d hours ago" = "%d klst. síðan";
/* No comment provided by engineer. */
"%d minutes ago" = "%d mínútum síðan";
/* No comment provided by engineer. */
"%d months ago" = "%d mánuðum síðan";
/* No comment provided by engineer. */
"%d seconds ago" = "%d sekúndum síðan";
/* No comment provided by engineer. */
"%d weeks ago" = "%d vikum síðan";
/* No comment provided by engineer. */
"%d years ago" = "%d árum síðan";
/* No comment provided by engineer. */
"A minute ago" = "Einni mínútu síðan";
/* No comment provided by engineer. */
"An hour ago" = "Einni klst. síðan";
/* No comment provided by engineer. */
"Just now" = "Rétt í þessu";
/* No comment provided by engineer. */
"Last month" = "Í síðasta mánuði";
/* No comment provided by engineer. */
"Last week" = "Í síðustu viku";
/* No comment provided by engineer. */
"Last year" = "Á síðasta ári";
/* No comment provided by engineer. */
"Yesterday" = "Í gær";
/* No comment provided by engineer. */
"1 year ago" = "1 ári síðan";
/* No comment provided by engineer. */
"1 month ago" = "1 mánuði síðan";
/* No comment provided by engineer. */
"1 week ago" = "1 viku síðan";
/* No comment provided by engineer. */
"1 day ago" = "1 degi síðan";
/* No comment provided by engineer. */
"This morning" = "Í morgun";
/* No comment provided by engineer. */
"This afternoon" = "Síðdegis";
/* No comment provided by engineer. */
"Today" = "Í dag";
/* No comment provided by engineer. */
"This week" = "Í þessari viku";
/* No comment provided by engineer. */
"This month" = "Í þessum mánuði";
/* No comment provided by engineer. */
"This year" = "Á þessu ári";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/it.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d giorni fa";
/* No comment provided by engineer. */
"%d hours ago" = "%d ore fa";
/* No comment provided by engineer. */
"%d minutes ago" = "%d minuti fa";
/* No comment provided by engineer. */
"%d months ago" = "%d mesi fa";
/* No comment provided by engineer. */
"%d seconds ago" = "%d secondi fa";
/* No comment provided by engineer. */
"%d weeks ago" = "%d settimane fa";
/* No comment provided by engineer. */
"%d years ago" = "%d anni fa";
/* No comment provided by engineer. */
"A minute ago" = "Un minuto fa";
/* No comment provided by engineer. */
"An hour ago" = "Un'ora fa";
/* No comment provided by engineer. */
"Just now" = "Ora";
/* No comment provided by engineer. */
"Last month" = "Il mese scorso";
/* No comment provided by engineer. */
"Last week" = "La settimana scorsa";
/* No comment provided by engineer. */
"Last year" = "L'anno scorso";
/* No comment provided by engineer. */
"Yesterday" = "Ieri";
/* No comment provided by engineer. */
"1 year ago" = "Un anno fa";
/* No comment provided by engineer. */
"1 month ago" = "Un mese fa";
/* No comment provided by engineer. */
"1 week ago" = "Una settimana fa";
/* No comment provided by engineer. */
"1 day ago" = "Un giorno fa";
/* No comment provided by engineer. */
"This morning" = "Questa mattina";
/* No comment provided by engineer. */
"This afternoon" = "Questo pomeriggio";
/* No comment provided by engineer. */
"Today" = "Oggi";
/* No comment provided by engineer. */
"This week" = "Questa settimana";
/* No comment provided by engineer. */
"This month" = "Questo mese";
/* No comment provided by engineer. */
"This year" = "Quest'anno";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/ja.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d日前";
/* No comment provided by engineer. */
"%d hours ago" = "%d時間前";
/* No comment provided by engineer. */
"%d minutes ago" = "%d分前";
/* No comment provided by engineer. */
"%d months ago" = "%dヶ月前";
/* No comment provided by engineer. */
"%d seconds ago" = "%d秒前";
/* No comment provided by engineer. */
"%d weeks ago" = "%d週間前";
/* No comment provided by engineer. */
"%d years ago" = "%d年前";
/* No comment provided by engineer. */
"A minute ago" = "1分前";
/* No comment provided by engineer. */
"An hour ago" = "1時間前";
/* No comment provided by engineer. */
"Just now" = "たった今";
/* No comment provided by engineer. */
"Last month" = "先月";
/* No comment provided by engineer. */
"Last week" = "先週";
/* No comment provided by engineer. */
"Last year" = "去年";
/* No comment provided by engineer. */
"Yesterday" = "昨日";
/* No comment provided by engineer. */
"1 year ago" = "1年前";
/* No comment provided by engineer. */
"1 month ago" = "1ヶ月前";
/* No comment provided by engineer. */
"1 week ago" = "1週間前";
/* No comment provided by engineer. */
"1 day ago" = "1日前";
/* No comment provided by engineer. */
"1 hour ago" = "1時間前";
/* No comment provided by engineer. */
"1 minute ago" = "1分前";
/* No comment provided by engineer. */
"1 second ago" = "1秒前";
/* No comment provided by engineer. */
"This morning" = "午前";
/* No comment provided by engineer. */
"This afternoon" = "午後";
/* No comment provided by engineer. */
"Today" = "今日";
/* No comment provided by engineer. */
"This week" = "今週";
/* No comment provided by engineer. */
"This month" = "今月";
/* No comment provided by engineer. */
"This year" = "今年";
/* Short format for */
"%dy" = "%d年"; // year
"%dM" = "%d月"; // month
"%dw" = "%d週"; // week
"%dd" = "%d日"; // day
"%dh" = "%d時間"; // hour
"%dm" = "%d分"; // minute
"%ds" = "%d秒"; // second
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/ko.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d일전";
/* No comment provided by engineer. */
"%d hours ago" = "%d시간전";
/* No comment provided by engineer. */
"%d minutes ago" = "%d분전";
/* No comment provided by engineer. */
"%d months ago" = "%d개월전";
/* No comment provided by engineer. */
"%d seconds ago" = "%d초전";
/* No comment provided by engineer. */
"%d weeks ago" = "%d주전";
/* No comment provided by engineer. */
"%d years ago" = "%d년전";
/* No comment provided by engineer. */
"A minute ago" = "1분전";
/* No comment provided by engineer. */
"An hour ago" = "1시간전";
/* No comment provided by engineer. */
"Just now" = "방금전";
/* No comment provided by engineer. */
"Last month" = "지난달";
/* No comment provided by engineer. */
"Last week" = "지난주";
/* No comment provided by engineer. */
"Last year" = "지난해";
/* No comment provided by engineer. */
"Yesterday" = "어제";
/* No comment provided by engineer. */
"1 year ago" = "1년전";
/* No comment provided by engineer. */
"1 month ago" = "1개월전";
/* No comment provided by engineer. */
"1 week ago" = "1주전";
/* No comment provided by engineer. */
"1 day ago" = "1일전";
/* No comment provided by engineer. */
"This morning" = "오늘 아침";
/* No comment provided by engineer. */
"This afternoon" = "오늘 오후";
/* No comment provided by engineer. */
"Today" = "오늘";
/* No comment provided by engineer. */
"This week" = "이번주";
/* No comment provided by engineer. */
"This month" = "이번달";
/* No comment provided by engineer. */
"This year" = "올해";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/lv.lproj/DateTools.strings
================================================
"1 year ago" = "Pirms gada";
"1 month ago" = "Pirms mēneša";
"1 week ago" = "Pirms nedēļas";
"1 day ago" = "Pirms dienas";
"A minute ago" = "Pirms minūtes";
"An hour ago" = "Pirms stundas";
"Last month" = "Pagājušajā mēnesī";
"Last week" = "Pagājušajā nedēļā";
"Last year" = "Pagājušajā gadā";
"Just now" = "Tikko";
"Today" = "Šodien";
"Yesterday" = "Vakar";
"This morning" = "Šorīt";
"This afternoon" = "Pēcpusdienā";
"This week" = "Šonedēļ";
"This month" = "Šomēnes";
"This year" = "Šogad";
"%d seconds ago" = "Pirms %d sekundēm";
"%d minutes ago" = "Pirms %d minūtēm";
"%d hours ago" = "Pirms %d stundām";
"%d days ago" = "Pirms %d dienām";
"%d weeks ago" = "Pirms %d nedēļām";
"%d months ago" = "Pirms %d mēnešiem";
"%d years ago" = "Pirms %d gadiem";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/ms.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d hari yang lepas";
/* No comment provided by engineer. */
"%d hours ago" = "%d jam yang lepas";
/* No comment provided by engineer. */
"%d minutes ago" = "%d minit yang lepas";
/* No comment provided by engineer. */
"%d months ago" = "%d bulan yang lepas";
/* No comment provided by engineer. */
"%d seconds ago" = "%d saat yang lepas";
/* No comment provided by engineer. */
"%d weeks ago" = "%d minggu yang lepas";
/* No comment provided by engineer. */
"%d years ago" = "%d tahun yang lepas";
/* No comment provided by engineer. */
"A minute ago" = "Seminit yang lepas";
/* No comment provided by engineer. */
"An hour ago" = "Sejam yang lepas";
/* No comment provided by engineer. */
"Just now" = "Sebentar tadi";
/* No comment provided by engineer. */
"Last month" = "Bulan lepas";
/* No comment provided by engineer. */
"Last week" = "Minggu lepas";
/* No comment provided by engineer. */
"Last year" = "Tahun lepas";
/* No comment provided by engineer. */
"Yesterday" = "Semalam";
/* No comment provided by engineer. */
"1 year ago" = "1 tahun lepas";
/* No comment provided by engineer. */
"1 month ago" = "1 bulan lepas";
/* No comment provided by engineer. */
"1 week ago" = "1 minggu lepas";
/* No comment provided by engineer. */
"1 day ago" = "1 hari lepas";
/* No comment provided by engineer. */
"1 hour ago" = "1 jam lepas";
/* No comment provided by engineer. */
"1 minute ago" = "1 minit lepas";
/* No comment provided by engineer. */
"1 second ago" = "1 saat lepas";
/* No comment provided by engineer. */
"This morning" = "Pagi ini";
/* No comment provided by engineer. */
"This afternoon" = "Petang ini";
/* No comment provided by engineer. */
"Today" = "Hari ini";
/* No comment provided by engineer. */
"This week" = "Minggu ini";
/* No comment provided by engineer. */
"This month" = "Bulan ini";
/* No comment provided by engineer. */
"This year" = "Tahun ini";
/* Short format for */
"%dy" = "%dy"; // year
"%dM" = "%dM"; // month
"%dw" = "%dw"; // week
"%dd" = "%dd"; // day
"%dh" = "%dh"; // hour
"%dm" = "%dm"; // minute
"%ds" = "%ds"; // second
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/nb.lproj/DateTools.strings
================================================
/*
RULES:
Assume value for (seconds, hours, minutes, days, weeks, months or years) is XXXY, Y is last digit, XY is last two digits;
*/
/* Y ==0 OR Y > 4 OR XY == 11; */
"%d days ago" = "%d dager siden";
/* If Y != 1 AND Y < 5; */
"%d _days ago" = "%d dager siden";
/* If Y == 1; */
"%d __days ago" = "%d dag siden";
/* Y ==0 OR Y > 4 OR XY == 11; */
"%d hours ago" = "%d timer siden";
/* If Y != 1 AND Y < 5; */
"%d _hours ago" = "%d timer siden";
/* If Y == 1; */
"%d __hours ago" = "%d time siden";
/* Y ==0 OR Y > 4 OR XY == 11; */
"%d minutes ago" = "%d minutter siden";
/* If Y != 1 AND Y < 5; */
"%d _minutes ago" = "%d minutter siden";
/* If Y == 1; */
"%d __minutes ago" = "%d minutt siden";
/* Y ==0 OR Y > 4 OR XY == 11; */
"%d months ago" = "%d måneder siden";
/* If Y != 1 AND Y < 5; */
"%d _months ago" = "%d måneder siden";
/* If Y == 1; */
"%d __months ago" = "%d måned siden";
/* Y ==0 OR Y > 4 OR XY == 11; */
"%d seconds ago" = "%d sekunder siden";
/* If Y != 1 AND Y < 5; */
"%d _seconds ago" = "%d sekunder siden";
/* If Y == 1; */
"%d __seconds ago" = "%d sekund siden";
/* Y ==0 OR Y > 4 OR XY == 11; */
"%d weeks ago" = "%d uker siden";
/* If Y != 1 AND Y < 5; */
"%d _weeks ago" = "%d uker siden";
/* If Y == 1; */
"%d __weeks ago" = "%d uke siden";
/* Y ==0 OR Y > 4 OR XY == 11; */
"%d years ago" = "%d år siden";
/* If Y != 1 AND Y < 5; */
"%d _years ago" = "%d år siden";
/* If Y == 1; */
"%d __years ago" = "%d år siden";
/* No comment provided by engineer. */
"A minute ago" = "Et minutt siden";
/* No comment provided by engineer. */
"An hour ago" = "En time siden";
/* No comment provided by engineer. */
"Just now" = "Nå";
/* No comment provided by engineer. */
"Last month" = "For en måned siden";
/* No comment provided by engineer. */
"Last week" = "For en uke siden";
/* No comment provided by engineer. */
"Last year" = "For et år siden";
/* No comment provided by engineer. */
"Yesterday" = "I går";
/* No comment provided by engineer. */
"1 year ago" = "1 år siden";
/* No comment provided by engineer. */
"1 month ago" = "1 måned siden";
/* No comment provided by engineer. */
"1 week ago" = "1 uke siden";
/* No comment provided by engineer. */
"1 day ago" = "1 dag siden";
/* No comment provided by engineer. */
"This morning" = "Denne morgenen";
/* No comment provided by engineer. */
"This afternoon" = "I ettermiddag";
/* No comment provided by engineer. */
"Today" = "I dag";
/* No comment provided by engineer. */
"This week" = "Denne uken";
/* No comment provided by engineer. */
"This month" = "Denne måneden";
/* No comment provided by engineer. */
"This year" = "Dette året";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/nl.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d dagen geleden";
/* No comment provided by engineer. */
"%d hours ago" = "%d uur geleden";
/* No comment provided by engineer. */
"%d minutes ago" = "%d minuten geleden";
/* No comment provided by engineer. */
"%d months ago" = "%d maanden geleden";
/* No comment provided by engineer. */
"%d seconds ago" = "%d seconden geleden";
/* No comment provided by engineer. */
"%d weeks ago" = "%d weken geleden";
/* No comment provided by engineer. */
"%d years ago" = "%d jaar geleden";
/* No comment provided by engineer. */
"A minute ago" = "Een minuut geleden";
/* No comment provided by engineer. */
"An hour ago" = "Een uur geleden";
/* No comment provided by engineer. */
"Just now" = "Zojuist";
/* No comment provided by engineer. */
"Last month" = "Vorige maand";
/* No comment provided by engineer. */
"Last week" = "Vorige week";
/* No comment provided by engineer. */
"Last year" = "Vorig jaar";
/* No comment provided by engineer. */
"Yesterday" = "Gisteren";
/* No comment provided by engineer. */
"1 year ago" = "1 jaar geleden";
/* No comment provided by engineer. */
"1 month ago" = "1 maand geleden";
/* No comment provided by engineer. */
"1 week ago" = "1 week geleden";
/* No comment provided by engineer. */
"1 day ago" = "1 dag geleden";
/* No comment provided by engineer. */
"This morning" = "Vanmorgen";
/* No comment provided by engineer. */
"This afternoon" = "Vanmiddag";
/* No comment provided by engineer. */
"Today" = "Vandaag";
/* No comment provided by engineer. */
"This week" = "Deze week";
/* No comment provided by engineer. */
"This month" = "Deze maand";
/* No comment provided by engineer. */
"This year" = "Dit jaar";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/pl.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d dni temu";
/* No comment provided by engineer. */
"%d hours ago" = "%d godzin(y) temu";
/* No comment provided by engineer. */
"%d minutes ago" = "%d minut(y) temu";
/* No comment provided by engineer. */
"%d months ago" = "%d miesiące/-y temu";
/* No comment provided by engineer. */
"%d seconds ago" = "%d sekund(y) temu";
/* No comment provided by engineer. */
"%d weeks ago" = "%d tygodni(e) temu";
/* No comment provided by engineer. */
"%d years ago" = "%d lat(a) temu";
/* No comment provided by engineer. */
"A minute ago" = "Minutę temu";
/* No comment provided by engineer. */
"An hour ago" = "Godzinę temu";
/* No comment provided by engineer. */
"Just now" = "W tej chwili";
/* No comment provided by engineer. */
"Last month" = "W zeszłym miesiącu";
/* No comment provided by engineer. */
"Last week" = "W zeszłym tygodniu";
/* No comment provided by engineer. */
"Last year" = "W zeszłym roku";
/* No comment provided by engineer. */
"Yesterday" = "Wczoraj";
/* No comment provided by engineer. */
"1 year ago" = "1 rok temu";
/* No comment provided by engineer. */
"1 month ago" = "1 miesiąc temu";
/* No comment provided by engineer. */
"1 week ago" = "1 tydzień temu";
/* No comment provided by engineer. */
"1 day ago" = "1 dzień temu";
/* No comment provided by engineer. */
"This morning" = "Dziś rano";
/* No comment provided by engineer. */
"This afternoon" = "Dziś po południu";
/* No comment provided by engineer. */
"Today" = "Dzisiaj";
/* No comment provided by engineer. */
"This week" = "W tym tygodniu";
/* No comment provided by engineer. */
"This month" = "W tym miesiącu";
/* No comment provided by engineer. */
"This year" = "W tym roku";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/pt-PT.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d dias atrás";
/* No comment provided by engineer. */
"%d hours ago" = "%d horas atrás";
/* No comment provided by engineer. */
"%d minutes ago" = "%d minutos atrás";
/* No comment provided by engineer. */
"%d months ago" = "%d meses atrás";
/* No comment provided by engineer. */
"%d seconds ago" = "%d segundos atrás";
/* No comment provided by engineer. */
"%d weeks ago" = "%d semanas atrás";
/* No comment provided by engineer. */
"%d years ago" = "%d anos atrás";
/* No comment provided by engineer. */
"A minute ago" = "Um minuto atrás";
/* No comment provided by engineer. */
"An hour ago" = "Uma hora atrás";
/* No comment provided by engineer. */
"Just now" = "Agora mesmo";
/* No comment provided by engineer. */
"Last month" = "Mês passado";
/* No comment provided by engineer. */
"Last week" = "Semana passada";
/* No comment provided by engineer. */
"Last year" = "Ano passado";
/* No comment provided by engineer. */
"Yesterday" = "Ontem";
/* No comment provided by engineer. */
"1 year ago" = "1 ano passado";
/* No comment provided by engineer. */
"1 month ago" = "1 mês atrás";
/* No comment provided by engineer. */
"1 week ago" = "1 semana atrás";
/* No comment provided by engineer. */
"1 day ago" = "1 dia atrás";
/* No comment provided by engineer. */
"This morning" = "Esta manhã";
/* No comment provided by engineer. */
"This afternoon" = "Esta tarde";
/* No comment provided by engineer. */
"Today" = "Hoje";
/* No comment provided by engineer. */
"This week" = "Esta semana";
/* No comment provided by engineer. */
"This month" = "Este mês";
/* No comment provided by engineer. */
"This year" = "Este ano";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/pt.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d dias atrás";
/* No comment provided by engineer. */
"%d hours ago" = "%d horas atrás";
/* No comment provided by engineer. */
"%d minutes ago" = "%d minutos atrás";
/* No comment provided by engineer. */
"%d months ago" = "%d meses atrás";
/* No comment provided by engineer. */
"%d seconds ago" = "%d segundos atrás";
/* No comment provided by engineer. */
"%d weeks ago" = "%d semanas atrás";
/* No comment provided by engineer. */
"%d years ago" = "%d anos atrás";
/* No comment provided by engineer. */
"A minute ago" = "Há um minuto";
/* No comment provided by engineer. */
"An hour ago" = "Há uma hora";
/* No comment provided by engineer. */
"Just now" = "Agora";
/* No comment provided by engineer. */
"Last month" = "Mês passado";
/* No comment provided by engineer. */
"Last week" = "Semana passada";
/* No comment provided by engineer. */
"Last year" = "Ano passado";
/* No comment provided by engineer. */
"Yesterday" = "Ontem";
/* No comment provided by engineer. */
"1 year ago" = "1 ano atrás";
/* No comment provided by engineer. */
"1 month ago" = "1 mês atrás";
/* No comment provided by engineer. */
"1 week ago" = "1 semana atrás";
/* No comment provided by engineer. */
"1 day ago" = "1 dia atrás";
/* No comment provided by engineer. */
"This morning" = "Esta manhã";
/* No comment provided by engineer. */
"This afternoon" = "Esta tarde";
/* No comment provided by engineer. */
"Today" = "Hoje";
/* No comment provided by engineer. */
"This week" = "Esta semana";
/* No comment provided by engineer. */
"This month" = "Este mês";
/* No comment provided by engineer. */
"This year" = "Este ano";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/ro.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "În urmă cu %d zile";
/* No comment provided by engineer. */
"%d hours ago" = "În urmă cu %d ore";
/* No comment provided by engineer. */
"%d minutes ago" = "În urmă cu %d minute";
/* No comment provided by engineer. */
"%d months ago" = "În urmă cu %d luni";
/* No comment provided by engineer. */
"%d seconds ago" = "În urmă cu %d secunde";
/* No comment provided by engineer. */
"%d weeks ago" = "În urmă cu %d săptămâni";
/* No comment provided by engineer. */
"%d years ago" = "În urmă cu %d ani";
/* No comment provided by engineer. */
"A minute ago" = "În urmă cu 1 minut";
/* No comment provided by engineer. */
"An hour ago" = "În urmă cu 1 oră";
/* No comment provided by engineer. */
"Just now" = "Acum câteva momente";
/* No comment provided by engineer. */
"Last month" = "Luna trecută";
/* No comment provided by engineer. */
"Last week" = "Săptămâna trecută";
/* No comment provided by engineer. */
"Last year" = "Anul trecut";
/* No comment provided by engineer. */
"Yesterday" = "Ieri";
/* No comment provided by engineer. */
"1 year ago" = "În urmă cu 1 an";
/* No comment provided by engineer. */
"1 month ago" = "În urmă cu 1 lună";
/* No comment provided by engineer. */
"1 week ago" = "În urmă cu 1 săptămână";
/* No comment provided by engineer. */
"1 day ago" = "În urmă cu 1 zi";
/* No comment provided by engineer. */
"This morning" = "Azi dimineață";
/* No comment provided by engineer. */
"This afternoon" = "În această seară";
/* No comment provided by engineer. */
"Today" = "Astăzi";
/* No comment provided by engineer. */
"This week" = "Săptămâna aceasta";
/* No comment provided by engineer. */
"This month" = "Luna aceasta";
/* No comment provided by engineer. */
"This year" = "Anul acesta";
/* Short format for */
"%dy" = "%da"; // year (an)
"%dM" = "%dl"; // month (luna)
"%dw" = "%dS"; // week (saptamana)
"%dd" = "%dz"; // day (ziua)
"%dh" = "%do"; // hour (ora)
"%dm" = "%dm"; // minute (minut)
"%ds" = "%ds"; // second (secunda)
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/ru.lproj/DateTools.strings
================================================
/*
RULES:
Assume value for (seconds, hours, minutes, days, weeks, months or years) is XXXY, Y is last digit, XY is last two digits;
*/
/* Y == 0 OR Y > 4 OR (XY > 10 AND XY < 15); */
"%d days ago" = "%d дней назад";
/* Y > 1 AND Y < 5 AND (XY < 10 OR XY > 20); */
"%d _days ago" = "%d дня назад";
/* Y == 1 AND XY != 11; */
"%d __days ago" = "%d день назад";
/* Y == 0 OR Y > 4 OR (XY > 10 AND XY < 15); */
"%d hours ago" = "%d часов назад";
/* Y > 1 AND Y < 5 AND (XY < 10 OR XY > 20); */
"%d _hours ago" = "%d часа назад";
/* Y == 1 AND XY != 11; */
"%d __hours ago" = "%d час назад";
/* Y == 0 OR Y > 4 OR (XY > 10 AND XY < 15); */
"%d minutes ago" = "%d минут назад";
/* Y > 1 AND Y < 5 AND (XY < 10 OR XY > 20); */
"%d _minutes ago" = "%d минуты назад";
/* Y == 1 AND XY != 11; */
"%d __minutes ago" = "%d минуту назад";
/* Y == 0 OR Y > 4 OR (XY > 10 AND XY < 15); */
"%d months ago" = "%d месяцев назад";
/* Y > 1 AND Y < 5 AND (XY < 10 OR XY > 20); */
"%d _months ago" = "%d месяца назад";
/* Y == 1 AND XY != 11; */
"%d __months ago" = "%d месяц назад";
/* Y == 0 OR Y > 4 OR (XY > 10 AND XY < 15); */
"%d seconds ago" = "%d секунд назад";
/* Y > 1 AND Y < 5 AND (XY < 10 OR XY > 20); */
"%d _seconds ago" = "%d секунды назад";
/* Y == 1 AND XY != 11; */
"%d __seconds ago" = "%d секунду назад";
/* Y == 0 OR Y > 4 OR (XY > 10 AND XY < 15); */
"%d weeks ago" = "%d недель назад";
/* Y > 1 AND Y < 5 AND (XY < 10 OR XY > 20); */
"%d _weeks ago" = "%d недели назад";
/* Y == 1 AND XY != 11; */
"%d __weeks ago" = "%d неделю назад";
/* Y == 0 OR Y > 4 OR (XY > 10 AND XY < 15); */
"%d years ago" = "%d лет назад";
/* Y > 1 AND Y < 5 AND (XY < 10 OR XY > 20); */
"%d _years ago" = "%d года назад";
/* Y == 1 AND XY != 11; */
"%d __years ago" = "%d год назад";
/* No comment provided by engineer. */
"A minute ago" = "Минуту назад";
/* No comment provided by engineer. */
"An hour ago" = "Час назад";
/* No comment provided by engineer. */
"Just now" = "Только что";
/* No comment provided by engineer. */
"Last month" = "Месяц назад";
/* No comment provided by engineer. */
"Last week" = "Неделю назад";
/* No comment provided by engineer. */
"Last year" = "Год назад";
/* No comment provided by engineer. */
"Yesterday" = "Вчера";
/* No comment provided by engineer. */
"1 year ago" = "1 год назад";
/* No comment provided by engineer. */
"1 month ago" = "1 месяц назад";
/* No comment provided by engineer. */
"1 week ago" = "1 неделю назад";
/* No comment provided by engineer. */
"1 day ago" = "1 день назад";
/* No comment provided by engineer. */
"This morning" = "Этим утром";
/* No comment provided by engineer. */
"This afternoon" = "Этим днём";
/* No comment provided by engineer. */
"Today" = "Сегодня";
/* No comment provided by engineer. */
"This week" = "На этой неделе";
/* No comment provided by engineer. */
"This month" = "В этом месяце";
/* No comment provided by engineer. */
"This year" = "В этом году";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/sl.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "pred %d dnevi";
/* No comment provided by engineer. */
"%d hours ago" = "pred %d urami";
/* No comment provided by engineer. */
"%d minutes ago" = "pred %d minutami";
/* No comment provided by engineer. */
"%d months ago" = "pred %d meseci";
/* No comment provided by engineer. */
"%d seconds ago" = "pred %d sekundami";
/* No comment provided by engineer. */
"%d weeks ago" = "pred %d tedni";
/* No comment provided by engineer. */
"%d years ago" = "pred %d leti";
/* No comment provided by engineer. */
"A minute ago" = "pred eno minuto";
/* No comment provided by engineer. */
"An hour ago" = "pred eno uro";
/* No comment provided by engineer. */
"Just now" = "ravnokar";
/* No comment provided by engineer. */
"Last month" = "prejšnji mesec";
/* No comment provided by engineer. */
"Last week" = "prejšnji teden";
/* No comment provided by engineer. */
"Last year" = "prejšnje leto";
/* No comment provided by engineer. */
"Yesterday" = "včeraj";
/* No comment provided by engineer. */
"1 year ago" = "pred 1 letom";
/* No comment provided by engineer. */
"1 month ago" = "pred 1 mesecem";
/* No comment provided by engineer. */
"1 week ago" = "pred 1 tednom";
/* No comment provided by engineer. */
"1 day ago" = "pred 1 dnevom";
/* No comment provided by engineer. */
"1 hour ago" = "pred 1 uro";
/* No comment provided by engineer. */
"1 minute ago" = "pred 1 minuto";
/* No comment provided by engineer. */
"1 second ago" = "pred 1 sekundo";
/* No comment provided by engineer. */
"This morning" = "zjutraj";
/* No comment provided by engineer. */
"This afternoon" = "zvečer";
/* No comment provided by engineer. */
"Today" = "danes";
/* No comment provided by engineer. */
"This week" = "ta teden";
/* No comment provided by engineer. */
"This month" = "ta mesec";
/* No comment provided by engineer. */
"This year" = "to leto";
/* Short format for */
"%dy" = "%dl"; // year
"%dM" = "%dM"; // month
"%dw" = "%dt"; // week
"%dd" = "%dd"; // day
"%dh" = "%du"; // hour
"%dm" = "%dm"; // minute
"%ds" = "%ds"; // second
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/tr.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d gün önce";
/* No comment provided by engineer. */
"%d hours ago" = "%d saat önce";
/* No comment provided by engineer. */
"%d minutes ago" = "%d dakika önce";
/* No comment provided by engineer. */
"%d months ago" = "%d ay önce";
/* No comment provided by engineer. */
"%d seconds ago" = "%d saniye önce";
/* No comment provided by engineer. */
"%d weeks ago" = "%d hafta önce";
/* No comment provided by engineer. */
"%d years ago" = "%d yıl önce";
/* No comment provided by engineer. */
"A minute ago" = "Bir dakika önce";
/* No comment provided by engineer. */
"An hour ago" = "Bir saat önce";
/* No comment provided by engineer. */
"Just now" = "Şimdi";
/* No comment provided by engineer. */
"Last month" = "Geçen ay";
/* No comment provided by engineer. */
"Last week" = "Geçen hafta";
/* No comment provided by engineer. */
"Last year" = "Geçen yıl";
/* No comment provided by engineer. */
"Yesterday" = "Dün";
/* No comment provided by engineer. */
"1 year ago" = "1 yıl önce";
/* No comment provided by engineer. */
"1 month ago" = "1 ay önce";
/* No comment provided by engineer. */
"1 week ago" = "1 hafta önce";
/* No comment provided by engineer. */
"1 day ago" = "1 gün önce";
/* No comment provided by engineer. */
"This morning" = "Bu sabah";
/* No comment provided by engineer. */
"This afternoon" = "Öğleden sonra";
/* No comment provided by engineer. */
"Today" = "Bugün";
/* No comment provided by engineer. */
"This week" = "Bu hafta";
/* No comment provided by engineer. */
"This month" = "Bu ay";
/* No comment provided by engineer. */
"This year" = "Bu yıl";
/* Short format for */
"%dy" = "%dy"; // year
"%dM" = "%day"; // month
"%dw" = "%dh"; // week
"%dd" = "%dg"; // day
"%dh" = "%dsa"; // hour
"%dm" = "%ddk"; // minute
"%ds" = "%dsn"; // second
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/uk.lproj/DateTools.strings
================================================
/*
RULES:
Assume value for (seconds, hours, minutes, days, weeks, months or years) is XXXY, Y is last digit, XY is last two digits;
*/
/* Y == 0 OR Y > 4 OR (XY > 10 AND XY < 15); */
"%d days ago" = "%d днів тому";
/* Y > 1 AND Y < 5 AND (XY < 10 OR XY > 20); */
"%d _days ago" = "%d дні тому";
/* Y == 1 AND XY != 11; */
"%d __days ago" = "%d день тому";
/* Y == 0 OR Y > 4 OR (XY > 10 AND XY < 15); */
"%d hours ago" = "%d годин тому";
/* Y > 1 AND Y < 5 AND (XY < 10 OR XY > 20); */
"%d _hours ago" = "%d години тому";
/* Y == 1 AND XY != 11; */
"%d __hours ago" = "%d годину тому";
/* Y == 0 OR Y > 4 OR (XY > 10 AND XY < 15); */
"%d minutes ago" = "%d хвилин тому";
/* Y > 1 AND Y < 5 AND (XY < 10 OR XY > 20); */
"%d _minutes ago" = "%d хвилини тому";
/* Y == 1 AND XY != 11; */
"%d __minutes ago" = "%d хвилину тому";
/* Y == 0 OR Y > 4 OR (XY > 10 AND XY < 15); */
"%d months ago" = "%d місяців тому";
/* Y > 1 AND Y < 5 AND (XY < 10 OR XY > 20); */
"%d _months ago" = "%d місяці тому";
/* Y == 1 AND XY != 11; */
"%d __months ago" = "%d місяць тому";
/* Y == 0 OR Y > 4 OR (XY > 10 AND XY < 15); */
"%d seconds ago" = "%d секунд тому";
/* Y > 1 AND Y < 5 AND (XY < 10 OR XY > 20); */
"%d _seconds ago" = "%d секунди тому";
/* Y == 1 AND XY != 11; */
"%d __seconds ago" = "%d секунду тому";
/* Y == 0 OR Y > 4 OR (XY > 10 AND XY < 15); */
"%d weeks ago" = "%d тижнів тому";
/* Y > 1 AND Y < 5 AND (XY < 10 OR XY > 20); */
"%d _weeks ago" = "%d тижні тому";
/* Y == 1 AND XY != 11; */
"%d __weeks ago" = "%d тиждень тому";
/* Y == 0 OR Y > 4 OR (XY > 10 AND XY < 15); */
"%d years ago" = "%d років тому";
/* Y > 1 AND Y < 5 AND (XY < 10 OR XY > 20); */
"%d _years ago" = "%d роки тому";
/* Y == 1 AND XY != 11; */
"%d __years ago" = "%d рік тому";
/* No comment provided by engineer. */
"A minute ago" = "Хвилину тому";
/* No comment provided by engineer. */
"An hour ago" = "Годину тому";
/* No comment provided by engineer. */
"Just now" = "Щойно";
/* No comment provided by engineer. */
"Last month" = "Місяць тому";
/* No comment provided by engineer. */
"Last week" = "Тиждень тому";
/* No comment provided by engineer. */
"Last year" = "Рік тому";
/* No comment provided by engineer. */
"Yesterday" = "Вчора";
/* No comment provided by engineer. */
"1 year ago" = "1 рік тому";
/* No comment provided by engineer. */
"1 month ago" = "1 місяць тому";
/* No comment provided by engineer. */
"1 week ago" = "1 тиждень тому";
/* No comment provided by engineer. */
"1 day ago" = "1 день тому";
/* No comment provided by engineer. */
"This morning" = "Цього ранку";
/* No comment provided by engineer. */
"This afternoon" = "Сьогодні вдень";
/* No comment provided by engineer. */
"Today" = "Сьогодні";
/* No comment provided by engineer. */
"This week" = "Цього тижня";
/* No comment provided by engineer. */
"This month" = "Цього місяця";
/* No comment provided by engineer. */
"This year" = "Цього року";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/vi.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d ngày trước";
/* No comment provided by engineer. */
"%d hours ago" = "%d giờ trước";
/* No comment provided by engineer. */
"%d minutes ago" = "%d phút trước";
/* No comment provided by engineer. */
"%d months ago" = "%d tháng trước";
/* No comment provided by engineer. */
"%d seconds ago" = "%d giây trước";
/* No comment provided by engineer. */
"%d weeks ago" = "%d tuần trước";
/* No comment provided by engineer. */
"%d years ago" = "%d năm trước";
/* No comment provided by engineer. */
"A minute ago" = "Một phút trước";
/* No comment provided by engineer. */
"An hour ago" = "Một giờ trước";
/* No comment provided by engineer. */
"Just now" = "Vừa mới đây";
/* No comment provided by engineer. */
"Last month" = "Tháng trước";
/* No comment provided by engineer. */
"Last week" = "Tuần trước";
/* No comment provided by engineer. */
"Last year" = "Năm vừa rồi";
/* No comment provided by engineer. */
"Yesterday" = "Hôm qua";
/* No comment provided by engineer. */
"1 year ago" = "1 năm trước";
/* No comment provided by engineer. */
"1 month ago" = "1 tháng trước";
/* No comment provided by engineer. */
"1 week ago" = "1 tuần trước";
/* No comment provided by engineer. */
"1 day ago" = "1 ngày trước";
/* No comment provided by engineer. */
"This morning" = "Sáng nay";
/* No comment provided by engineer. */
"This afternoon" = "Trưa nay";
/* No comment provided by engineer. */
"Today" = "Hôm nay";
/* No comment provided by engineer. */
"This week" = "Tuần này";
/* No comment provided by engineer. */
"This month" = "Tháng này";
/* No comment provided by engineer. */
"This year" = "Năm nay";
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/zh-Hans.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d天前";
/* No comment provided by engineer. */
"%d hours ago" = "%d小时前";
/* No comment provided by engineer. */
"%d minutes ago" = "%d分钟前";
/* No comment provided by engineer. */
"%d months ago" = "%d个月前";
/* No comment provided by engineer. */
"%d seconds ago" = "%d秒钟前";
/* No comment provided by engineer. */
"%d weeks ago" = "%d星期前";
/* No comment provided by engineer. */
"%d years ago" = "%d年前";
/* No comment provided by engineer. */
"A minute ago" = "1分钟前";
/* No comment provided by engineer. */
"An hour ago" = "1小时前";
/* No comment provided by engineer. */
"Just now" = "刚刚";
/* No comment provided by engineer. */
"Last month" = "上个月";
/* No comment provided by engineer. */
"Last week" = "上星期";
/* No comment provided by engineer. */
"Last year" = "去年";
/* No comment provided by engineer. */
"Yesterday" = "昨天";
/* You can add a space between the number and the characters. */
"1 year ago" = "1年前";
/* You can add a space between the number and the characters. */
"1 month ago" = "1个月前";
/* You can add a space between the number and the characters. */
"1 week ago" = "1星期前";
/* You can add a space between the number and the characters. */
"1 day ago" = "1天前";
/* No comment provided by engineer. */
"This morning" = "今天上午";
/* No comment provided by engineer. */
"This afternoon" = "今天下午";
/* No comment provided by engineer. */
"Today" = "今天";
/* No comment provided by engineer. */
"This week" = "本周";
/* No comment provided by engineer. */
"This month" = "本月";
/* No comment provided by engineer. */
"This year" = "今年";
/* Short format for */
"%dy" = "%d年"; // year
"%dM" = "%d月"; // month
"%dw" = "%d周"; // week
"%dd" = "%d天"; // day
"%dh" = "%d小时"; // hour
"%dm" = "%d分"; // minute
"%ds" = "%d秒"; // second
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.bundle/zh-Hant.lproj/DateTools.strings
================================================
/* No comment provided by engineer. */
"%d days ago" = "%d天前";
/* No comment provided by engineer. */
"%d hours ago" = "%d小時前";
/* No comment provided by engineer. */
"%d minutes ago" = "%d分鐘前";
/* No comment provided by engineer. */
"%d months ago" = "%d個月前";
/* No comment provided by engineer. */
"%d seconds ago" = "%d秒鐘前";
/* No comment provided by engineer. */
"%d weeks ago" = "%d星期前";
/* No comment provided by engineer. */
"%d years ago" = "%d年前";
/* No comment provided by engineer. */
"A minute ago" = "1分鐘前";
/* No comment provided by engineer. */
"An hour ago" = "1小時前";
/* No comment provided by engineer. */
"Just now" = "剛剛";
/* No comment provided by engineer. */
"Last month" = "上個月";
/* No comment provided by engineer. */
"Last week" = "上星期";
/* No comment provided by engineer. */
"Last year" = "去年";
/* No comment provided by engineer. */
"Yesterday" = "昨天";
/* No comment provided by engineer. */
"1 year ago" = "1年前";
/* No comment provided by engineer. */
"1 month ago" = "1個月前";
/* No comment provided by engineer. */
"1 week ago" = "1星期前";
/* No comment provided by engineer. */
"1 day ago" = "1天前";
/* No comment provided by engineer. */
"This morning" = "今天上午";
/* No comment provided by engineer. */
"This afternoon" = "今天下午";
/* No comment provided by engineer. */
"Today" = "今天";
/* No comment provided by engineer. */
"This week" = "本周";
/* No comment provided by engineer. */
"This month" = "本月";
/* No comment provided by engineer. */
"This year" = "今年";
/* Short format for */
"%dy" = "%d年"; // year
"%dM" = "%d月"; // month
"%dw" = "%d週"; // week
"%dd" = "%d天"; // day
"%dh" = "%d小時"; // hour
"%dm" = "%d分"; // minute
"%ds" = "%d秒"; // second
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/DateTools.h
================================================
// Copyright (C) 2014 by Matthew York
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and
// associated documentation files (the "Software"), to
// deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall
// be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "DTConstants.h"
#import "DTError.h"
#import "NSDate+DateTools.h"
#import "DTTimePeriod.h"
#import "DTTimePeriodGroup.h"
#import "DTTimePeriodCollection.h"
#import "DTTimePeriodChain.h"
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/NSDate+DateTools.h
================================================
// Copyright (C) 2014 by Matthew York
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and
// associated documentation files (the "Software"), to
// deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall
// be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef DateToolsLocalizedStrings
#define DateToolsLocalizedStrings(key) \
NSLocalizedStringFromTableInBundle(key, @"DateTools", [NSBundle bundleWithPath:[[[NSBundle bundleForClass:[DTError class]] resourcePath] stringByAppendingPathComponent:@"DateTools.bundle"]], nil)
#endif
#import
#import "DTConstants.h"
@interface NSDate (DateTools)
#pragma mark - Time Ago
+ (NSString*)timeAgoSinceDate:(NSDate*)date;
+ (NSString*)shortTimeAgoSinceDate:(NSDate*)date;
- (NSString*)timeAgoSinceNow;
- (NSString *)shortTimeAgoSinceNow;
- (NSString *)timeAgoSinceDate:(NSDate *)date;
- (NSString *)timeAgoSinceDate:(NSDate *)date numericDates:(BOOL)useNumericDates;
- (NSString *)timeAgoSinceDate:(NSDate *)date numericDates:(BOOL)useNumericDates numericTimes:(BOOL)useNumericTimes;
- (NSString *)shortTimeAgoSinceDate:(NSDate *)date;
#pragma mark - Date Components Without Calendar
- (NSInteger)era;
- (NSInteger)year;
- (NSInteger)month;
- (NSInteger)day;
- (NSInteger)hour;
- (NSInteger)minute;
- (NSInteger)second;
- (NSInteger)weekday;
- (NSInteger)weekdayOrdinal;
- (NSInteger)quarter;
- (NSInteger)weekOfMonth;
- (NSInteger)weekOfYear;
- (NSInteger)yearForWeekOfYear;
- (NSInteger)daysInMonth;
- (NSInteger)dayOfYear;
-(NSInteger)daysInYear;
-(BOOL)isInLeapYear;
- (BOOL)isToday;
- (BOOL)isTomorrow;
-(BOOL)isYesterday;
- (BOOL)isWeekend;
-(BOOL)isSameDay:(NSDate *)date;
+ (BOOL)isSameDay:(NSDate *)date asDate:(NSDate *)compareDate;
#pragma mark - Date Components With Calendar
- (NSInteger)eraWithCalendar:(NSCalendar *)calendar;
- (NSInteger)yearWithCalendar:(NSCalendar *)calendar;
- (NSInteger)monthWithCalendar:(NSCalendar *)calendar;
- (NSInteger)dayWithCalendar:(NSCalendar *)calendar;
- (NSInteger)hourWithCalendar:(NSCalendar *)calendar;
- (NSInteger)minuteWithCalendar:(NSCalendar *)calendar;
- (NSInteger)secondWithCalendar:(NSCalendar *)calendar;
- (NSInteger)weekdayWithCalendar:(NSCalendar *)calendar;
- (NSInteger)weekdayOrdinalWithCalendar:(NSCalendar *)calendar;
- (NSInteger)quarterWithCalendar:(NSCalendar *)calendar;
- (NSInteger)weekOfMonthWithCalendar:(NSCalendar *)calendar;
- (NSInteger)weekOfYearWithCalendar:(NSCalendar *)calendar;
- (NSInteger)yearForWeekOfYearWithCalendar:(NSCalendar *)calendar;
#pragma mark - Date Creating
+ (NSDate *)dateWithYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day;
+ (NSDate *)dateWithYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day hour:(NSInteger)hour minute:(NSInteger)minute second:(NSInteger)second;
+ (NSDate *)dateWithString:(NSString *)dateString formatString:(NSString *)formatString;
+ (NSDate *)dateWithString:(NSString *)dateString formatString:(NSString *)formatString timeZone:(NSTimeZone *)timeZone;
#pragma mark - Date Editing
#pragma mark Date By Adding
- (NSDate *)dateByAddingYears:(NSInteger)years;
- (NSDate *)dateByAddingMonths:(NSInteger)months;
- (NSDate *)dateByAddingWeeks:(NSInteger)weeks;
- (NSDate *)dateByAddingDays:(NSInteger)days;
- (NSDate *)dateByAddingHours:(NSInteger)hours;
- (NSDate *)dateByAddingMinutes:(NSInteger)minutes;
- (NSDate *)dateByAddingSeconds:(NSInteger)seconds;
#pragma mark Date By Subtracting
- (NSDate *)dateBySubtractingYears:(NSInteger)years;
- (NSDate *)dateBySubtractingMonths:(NSInteger)months;
- (NSDate *)dateBySubtractingWeeks:(NSInteger)weeks;
- (NSDate *)dateBySubtractingDays:(NSInteger)days;
- (NSDate *)dateBySubtractingHours:(NSInteger)hours;
- (NSDate *)dateBySubtractingMinutes:(NSInteger)minutes;
- (NSDate *)dateBySubtractingSeconds:(NSInteger)seconds;
#pragma mark - Date Comparison
#pragma mark Time From
-(NSInteger)yearsFrom:(NSDate *)date;
-(NSInteger)monthsFrom:(NSDate *)date;
-(NSInteger)weeksFrom:(NSDate *)date;
-(NSInteger)daysFrom:(NSDate *)date;
-(double)hoursFrom:(NSDate *)date;
-(double)minutesFrom:(NSDate *)date;
-(double)secondsFrom:(NSDate *)date;
#pragma mark Time From With Calendar
-(NSInteger)yearsFrom:(NSDate *)date calendar:(NSCalendar *)calendar;
-(NSInteger)monthsFrom:(NSDate *)date calendar:(NSCalendar *)calendar;
-(NSInteger)weeksFrom:(NSDate *)date calendar:(NSCalendar *)calendar;
-(NSInteger)daysFrom:(NSDate *)date calendar:(NSCalendar *)calendar;
#pragma mark Time Until
-(NSInteger)yearsUntil;
-(NSInteger)monthsUntil;
-(NSInteger)weeksUntil;
-(NSInteger)daysUntil;
-(double)hoursUntil;
-(double)minutesUntil;
-(double)secondsUntil;
#pragma mark Time Ago
-(NSInteger)yearsAgo;
-(NSInteger)monthsAgo;
-(NSInteger)weeksAgo;
-(NSInteger)daysAgo;
-(double)hoursAgo;
-(double)minutesAgo;
-(double)secondsAgo;
#pragma mark Earlier Than
-(NSInteger)yearsEarlierThan:(NSDate *)date;
-(NSInteger)monthsEarlierThan:(NSDate *)date;
-(NSInteger)weeksEarlierThan:(NSDate *)date;
-(NSInteger)daysEarlierThan:(NSDate *)date;
-(double)hoursEarlierThan:(NSDate *)date;
-(double)minutesEarlierThan:(NSDate *)date;
-(double)secondsEarlierThan:(NSDate *)date;
#pragma mark Later Than
-(NSInteger)yearsLaterThan:(NSDate *)date;
-(NSInteger)monthsLaterThan:(NSDate *)date;
-(NSInteger)weeksLaterThan:(NSDate *)date;
-(NSInteger)daysLaterThan:(NSDate *)date;
-(double)hoursLaterThan:(NSDate *)date;
-(double)minutesLaterThan:(NSDate *)date;
-(double)secondsLaterThan:(NSDate *)date;
#pragma mark Comparators
-(BOOL)isEarlierThan:(NSDate *)date;
-(BOOL)isLaterThan:(NSDate *)date;
-(BOOL)isEarlierThanOrEqualTo:(NSDate *)date;
-(BOOL)isLaterThanOrEqualTo:(NSDate *)date;
#pragma mark - Formatted Dates
#pragma mark Formatted With Style
-(NSString *)formattedDateWithStyle:(NSDateFormatterStyle)style;
-(NSString *)formattedDateWithStyle:(NSDateFormatterStyle)style timeZone:(NSTimeZone *)timeZone;
-(NSString *)formattedDateWithStyle:(NSDateFormatterStyle)style locale:(NSLocale *)locale;
-(NSString *)formattedDateWithStyle:(NSDateFormatterStyle)style timeZone:(NSTimeZone *)timeZone locale:(NSLocale *)locale;
#pragma mark Formatted With Format
-(NSString *)formattedDateWithFormat:(NSString *)format;
-(NSString *)formattedDateWithFormat:(NSString *)format timeZone:(NSTimeZone *)timeZone;
-(NSString *)formattedDateWithFormat:(NSString *)format locale:(NSLocale *)locale;
-(NSString *)formattedDateWithFormat:(NSString *)format timeZone:(NSTimeZone *)timeZone locale:(NSLocale *)locale;
#pragma mark - Helpers
+(NSString *)defaultCalendarIdentifier;
+ (void)setDefaultCalendarIdentifier:(NSString *)identifier;
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools/NSDate+DateTools.m
================================================
// Copyright (C) 2014 by Matthew York
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and
// associated documentation files (the "Software"), to
// deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall
// be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "NSDate+DateTools.h"
typedef NS_ENUM(NSUInteger, DTDateComponent){
DTDateComponentEra,
DTDateComponentYear,
DTDateComponentMonth,
DTDateComponentDay,
DTDateComponentHour,
DTDateComponentMinute,
DTDateComponentSecond,
DTDateComponentWeekday,
DTDateComponentWeekdayOrdinal,
DTDateComponentQuarter,
DTDateComponentWeekOfMonth,
DTDateComponentWeekOfYear,
DTDateComponentYearForWeekOfYear,
DTDateComponentDayOfYear
};
typedef NS_ENUM(NSUInteger, DateAgoFormat){
DateAgoLong,
DateAgoLongUsingNumericDatesAndTimes,
DateAgoLongUsingNumericDates,
DateAgoLongUsingNumericTimes,
DateAgoShort
};
typedef NS_ENUM(NSUInteger, DateAgoValues){
YearsAgo,
MonthsAgo,
WeeksAgo,
DaysAgo,
HoursAgo,
MinutesAgo,
SecondsAgo
};
static const unsigned int allCalendarUnitFlags = NSCalendarUnitYear | NSCalendarUnitQuarter | NSCalendarUnitMonth | NSCalendarUnitWeekOfYear | NSCalendarUnitWeekOfMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond | NSCalendarUnitEra | NSCalendarUnitWeekday | NSCalendarUnitWeekdayOrdinal | NSCalendarUnitWeekOfYear;
static NSString *defaultCalendarIdentifier = nil;
static NSCalendar *implicitCalendar = nil;
@implementation NSDate (DateTools)
+ (void)load {
[self setDefaultCalendarIdentifier:NSCalendarIdentifierGregorian];
}
#pragma mark - Time Ago
/**
* Takes in a date and returns a string with the most convenient unit of time representing
* how far in the past that date is from now.
*
* @param NSDate - Date to be measured from now
*
* @return NSString - Formatted return string
*/
+ (NSString*)timeAgoSinceDate:(NSDate*)date{
return [date timeAgoSinceDate:[NSDate date]];
}
/**
* Takes in a date and returns a shortened string with the most convenient unit of time representing
* how far in the past that date is from now.
*
* @param NSDate - Date to be measured from now
*
* @return NSString - Formatted return string
*/
+ (NSString*)shortTimeAgoSinceDate:(NSDate*)date{
return [date shortTimeAgoSinceDate:[NSDate date]];
}
/**
* Returns a string with the most convenient unit of time representing
* how far in the past that date is from now.
*
* @return NSString - Formatted return string
*/
- (NSString*)timeAgoSinceNow{
return [self timeAgoSinceDate:[NSDate date]];
}
/**
* Returns a shortened string with the most convenient unit of time representing
* how far in the past that date is from now.
*
* @return NSString - Formatted return string
*/
- (NSString *)shortTimeAgoSinceNow{
return [self shortTimeAgoSinceDate:[NSDate date]];
}
- (NSString *)timeAgoSinceDate:(NSDate *)date{
return [self timeAgoSinceDate:date numericDates:NO];
}
- (NSString *)timeAgoSinceDate:(NSDate *)date numericDates:(BOOL)useNumericDates{
return [self timeAgoSinceDate:date numericDates:useNumericDates numericTimes:NO];
}
- (NSString *)timeAgoSinceDate:(NSDate *)date numericDates:(BOOL)useNumericDates numericTimes:(BOOL)useNumericTimes{
if (useNumericDates && useNumericTimes) {
return [self timeAgoSinceDate:date format:DateAgoLongUsingNumericDatesAndTimes];
} else if (useNumericDates) {
return [self timeAgoSinceDate:date format:DateAgoLongUsingNumericDates];
} else if (useNumericTimes) {
return [self timeAgoSinceDate:date format:DateAgoLongUsingNumericDates];
} else {
return [self timeAgoSinceDate:date format:DateAgoLong];
}
}
- (NSString *)shortTimeAgoSinceDate:(NSDate *)date{
return [self timeAgoSinceDate:date format:DateAgoShort];
}
- (NSString *)timeAgoSinceDate:(NSDate *)date format:(DateAgoFormat)format {
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *earliest = [self earlierDate:date];
NSDate *latest = (earliest == self) ? date : self;
// if timeAgo < 24h => compare DateTime else compare Date only
NSUInteger upToHours = NSCalendarUnitSecond | NSCalendarUnitMinute | NSCalendarUnitHour;
NSDateComponents *difference = [calendar components:upToHours fromDate:earliest toDate:latest options:0];
if (difference.hour < 24) {
if (difference.hour >= 1) {
return [self localizedStringFor:format valueType:HoursAgo value:difference.hour];
} else if (difference.minute >= 1) {
return [self localizedStringFor:format valueType:MinutesAgo value:difference.minute];
} else {
return [self localizedStringFor:format valueType:SecondsAgo value:difference.second];
}
} else {
NSUInteger bigUnits = NSCalendarUnitTimeZone | NSCalendarUnitDay | NSCalendarUnitWeekOfYear | NSCalendarUnitMonth | NSCalendarUnitYear;
NSDateComponents *components = [calendar components:bigUnits fromDate:earliest];
earliest = [calendar dateFromComponents:components];
components = [calendar components:bigUnits fromDate:latest];
latest = [calendar dateFromComponents:components];
difference = [calendar components:bigUnits fromDate:earliest toDate:latest options:0];
if (difference.year >= 1) {
return [self localizedStringFor:format valueType:YearsAgo value:difference.year];
} else if (difference.month >= 1) {
return [self localizedStringFor:format valueType:MonthsAgo value:difference.month];
} else if (difference.weekOfYear >= 1) {
return [self localizedStringFor:format valueType:WeeksAgo value:difference.weekOfYear];
} else {
return [self localizedStringFor:format valueType:DaysAgo value:difference.day];
}
}
}
- (NSString *)localizedStringFor:(DateAgoFormat)format valueType:(DateAgoValues)valueType value:(NSInteger)value {
BOOL isShort = format == DateAgoShort;
BOOL isNumericDate = format == DateAgoLongUsingNumericDates || format == DateAgoLongUsingNumericDatesAndTimes;
BOOL isNumericTime = format == DateAgoLongUsingNumericTimes || format == DateAgoLongUsingNumericDatesAndTimes;
switch (valueType) {
case YearsAgo:
if (isShort) {
return [self logicLocalizedStringFromFormat:@"%%d%@y" withValue:value];
} else if (value >= 2) {
return [self logicLocalizedStringFromFormat:@"%%d %@years ago" withValue:value];
} else if (isNumericDate) {
return DateToolsLocalizedStrings(@"1 year ago");
} else {
return DateToolsLocalizedStrings(@"Last year");
}
case MonthsAgo:
if (isShort) {
return [self logicLocalizedStringFromFormat:@"%%d%@M" withValue:value];
} else if (value >= 2) {
return [self logicLocalizedStringFromFormat:@"%%d %@months ago" withValue:value];
} else if (isNumericDate) {
return DateToolsLocalizedStrings(@"1 month ago");
} else {
return DateToolsLocalizedStrings(@"Last month");
}
case WeeksAgo:
if (isShort) {
return [self logicLocalizedStringFromFormat:@"%%d%@w" withValue:value];
} else if (value >= 2) {
return [self logicLocalizedStringFromFormat:@"%%d %@weeks ago" withValue:value];
} else if (isNumericDate) {
return DateToolsLocalizedStrings(@"1 week ago");
} else {
return DateToolsLocalizedStrings(@"Last week");
}
case DaysAgo:
if (isShort) {
return [self logicLocalizedStringFromFormat:@"%%d%@d" withValue:value];
} else if (value >= 2) {
return [self logicLocalizedStringFromFormat:@"%%d %@days ago" withValue:value];
} else if (isNumericDate) {
return DateToolsLocalizedStrings(@"1 day ago");
} else {
return DateToolsLocalizedStrings(@"Yesterday");
}
case HoursAgo:
if (isShort) {
return [self logicLocalizedStringFromFormat:@"%%d%@h" withValue:value];
} else if (value >= 2) {
return [self logicLocalizedStringFromFormat:@"%%d %@hours ago" withValue:value];
} else if (isNumericTime) {
return DateToolsLocalizedStrings(@"1 hour ago");
} else {
return DateToolsLocalizedStrings(@"An hour ago");
}
case MinutesAgo:
if (isShort) {
return [self logicLocalizedStringFromFormat:@"%%d%@m" withValue:value];
} else if (value >= 2) {
return [self logicLocalizedStringFromFormat:@"%%d %@minutes ago" withValue:value];
} else if (isNumericTime) {
return DateToolsLocalizedStrings(@"1 minute ago");
} else {
return DateToolsLocalizedStrings(@"A minute ago");
}
case SecondsAgo:
if (isShort) {
return [self logicLocalizedStringFromFormat:@"%%d%@s" withValue:value];
} else if (value >= 2) {
return [self logicLocalizedStringFromFormat:@"%%d %@seconds ago" withValue:value];
} else if (isNumericTime) {
return DateToolsLocalizedStrings(@"1 second ago");
} else {
return DateToolsLocalizedStrings(@"Just now");
}
}
return nil;
}
- (NSString *) logicLocalizedStringFromFormat:(NSString *)format withValue:(NSInteger)value{
NSString * localeFormat = [NSString stringWithFormat:format, [self getLocaleFormatUnderscoresWithValue:value]];
return [NSString stringWithFormat:DateToolsLocalizedStrings(localeFormat), value];
}
- (NSString *)getLocaleFormatUnderscoresWithValue:(double)value{
NSString *localeCode = [[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0];
// Russian (ru) and Ukrainian (uk)
if([localeCode isEqualToString:@"ru"] || [localeCode isEqualToString:@"uk"]) {
int XY = (int)floor(value) % 100;
int Y = (int)floor(value) % 10;
if(Y == 0 || Y > 4 || (XY > 10 && XY < 15)) {
return @"";
}
if(Y > 1 && Y < 5 && (XY < 10 || XY > 20)) {
return @"_";
}
if(Y == 1 && XY != 11) {
return @"__";
}
}
// Add more languages here, which are have specific translation rules...
return @"";
}
#pragma mark - Date Components Without Calendar
/**
* Returns the era of the receiver. (0 for BC, 1 for AD for Gregorian)
*
* @return NSInteger
*/
- (NSInteger)era{
return [self componentForDate:self type:DTDateComponentEra calendar:nil];
}
/**
* Returns the year of the receiver.
*
* @return NSInteger
*/
- (NSInteger)year{
return [self componentForDate:self type:DTDateComponentYear calendar:nil];
}
/**
* Returns the month of the year of the receiver.
*
* @return NSInteger
*/
- (NSInteger)month{
return [self componentForDate:self type:DTDateComponentMonth calendar:nil];
}
/**
* Returns the day of the month of the receiver.
*
* @return NSInteger
*/
- (NSInteger)day{
return [self componentForDate:self type:DTDateComponentDay calendar:nil];
}
/**
* Returns the hour of the day of the receiver. (0-24)
*
* @return NSInteger
*/
- (NSInteger)hour{
return [self componentForDate:self type:DTDateComponentHour calendar:nil];
}
/**
* Returns the minute of the receiver. (0-59)
*
* @return NSInteger
*/
- (NSInteger)minute{
return [self componentForDate:self type:DTDateComponentMinute calendar:nil];
}
/**
* Returns the second of the receiver. (0-59)
*
* @return NSInteger
*/
- (NSInteger)second{
return [self componentForDate:self type:DTDateComponentSecond calendar:nil];
}
/**
* Returns the day of the week of the receiver.
*
* @return NSInteger
*/
- (NSInteger)weekday{
return [self componentForDate:self type:DTDateComponentWeekday calendar:nil];
}
/**
* Returns the ordinal for the day of the week of the receiver.
*
* @return NSInteger
*/
- (NSInteger)weekdayOrdinal{
return [self componentForDate:self type:DTDateComponentWeekdayOrdinal calendar:nil];
}
/**
* Returns the quarter of the receiver.
*
* @return NSInteger
*/
- (NSInteger)quarter{
return [self componentForDate:self type:DTDateComponentQuarter calendar:nil];
}
/**
* Returns the week of the month of the receiver.
*
* @return NSInteger
*/
- (NSInteger)weekOfMonth{
return [self componentForDate:self type:DTDateComponentWeekOfMonth calendar:nil];
}
/**
* Returns the week of the year of the receiver.
*
* @return NSInteger
*/
- (NSInteger)weekOfYear{
return [self componentForDate:self type:DTDateComponentWeekOfYear calendar:nil];
}
/**
* I honestly don't know much about this value...
*
* @return NSInteger
*/
- (NSInteger)yearForWeekOfYear{
return [self componentForDate:self type:DTDateComponentYearForWeekOfYear calendar:nil];
}
/**
* Returns how many days are in the month of the receiver.
*
* @return NSInteger
*/
- (NSInteger)daysInMonth{
NSCalendar *calendar = [NSCalendar currentCalendar];
NSRange days = [calendar rangeOfUnit:NSCalendarUnitDay
inUnit:NSCalendarUnitMonth
forDate:self];
return days.length;
}
/**
* Returns the day of the year of the receiver. (1-365 or 1-366 for leap year)
*
* @return NSInteger
*/
- (NSInteger)dayOfYear{
return [self componentForDate:self type:DTDateComponentDayOfYear calendar:nil];
}
/**
* Returns how many days are in the year of the receiver.
*
* @return NSInteger
*/
-(NSInteger)daysInYear{
if (self.isInLeapYear) {
return 366;
}
return 365;
}
/**
* Returns whether the receiver falls in a leap year.
*
* @return NSInteger
*/
-(BOOL)isInLeapYear{
NSCalendar *calendar = [[self class] implicitCalendar];
NSDateComponents *dateComponents = [calendar components:allCalendarUnitFlags fromDate:self];
if (dateComponents.year%400 == 0){
return YES;
}
else if (dateComponents.year%100 == 0){
return NO;
}
else if (dateComponents.year%4 == 0){
return YES;
}
return NO;
}
- (BOOL)isToday {
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:(NSCalendarUnitEra|NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay) fromDate:[NSDate date]];
NSDate *today = [cal dateFromComponents:components];
components = [cal components:(NSCalendarUnitEra|NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay) fromDate:self];
NSDate *otherDate = [cal dateFromComponents:components];
return [today isEqualToDate:otherDate];
}
- (BOOL)isTomorrow {
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:(NSCalendarUnitEra|NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay) fromDate:[[NSDate date] dateByAddingDays:1]];
NSDate *tomorrow = [cal dateFromComponents:components];
components = [cal components:(NSCalendarUnitEra|NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay) fromDate:self];
NSDate *otherDate = [cal dateFromComponents:components];
return [tomorrow isEqualToDate:otherDate];
}
-(BOOL)isYesterday{
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:(NSCalendarUnitEra|NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay) fromDate:[[NSDate date] dateBySubtractingDays:1]];
NSDate *tomorrow = [cal dateFromComponents:components];
components = [cal components:(NSCalendarUnitEra|NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay) fromDate:self];
NSDate *otherDate = [cal dateFromComponents:components];
return [tomorrow isEqualToDate:otherDate];
}
- (BOOL)isWeekend {
NSCalendar *calendar = [NSCalendar currentCalendar];
NSRange weekdayRange = [calendar maximumRangeOfUnit:NSCalendarUnitWeekday];
NSDateComponents *components = [calendar components:NSCalendarUnitWeekday
fromDate:self];
NSUInteger weekdayOfSomeDate = [components weekday];
BOOL result = NO;
if (weekdayOfSomeDate == weekdayRange.location || weekdayOfSomeDate == weekdayRange.length)
result = YES;
return result;
}
/**
* Returns whether two dates fall on the same day.
*
* @param date NSDate - Date to compare with sender
* @return BOOL - YES if both paramter dates fall on the same day, NO otherwise
*/
-(BOOL)isSameDay:(NSDate *)date {
return [NSDate isSameDay:self asDate:date];
}
/**
* Returns whether two dates fall on the same day.
*
* @param date NSDate - First date to compare
* @param compareDate NSDate - Second date to compare
* @return BOOL - YES if both paramter dates fall on the same day, NO otherwise
*/
+ (BOOL)isSameDay:(NSDate *)date asDate:(NSDate *)compareDate
{
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:(NSCalendarUnitEra|NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay) fromDate:date];
NSDate *dateOne = [cal dateFromComponents:components];
components = [cal components:(NSCalendarUnitEra|NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay) fromDate:compareDate];
NSDate *dateTwo = [cal dateFromComponents:components];
return [dateOne isEqualToDate:dateTwo];
}
#pragma mark - Date Components With Calendar
/**
* Returns the era of the receiver from a given calendar
*
* @param calendar NSCalendar - The calendar to be used in the calculation
*
* @return NSInteger - represents the era (0 for BC, 1 for AD for Gregorian)
*/
- (NSInteger)eraWithCalendar:(NSCalendar *)calendar{
return [self componentForDate:self type:DTDateComponentEra calendar:calendar];
}
/**
* Returns the year of the receiver from a given calendar
*
* @param calendar NSCalendar - The calendar to be used in the calculation
*
* @return NSInteger - represents the year as an integer
*/
- (NSInteger)yearWithCalendar:(NSCalendar *)calendar{
return [self componentForDate:self type:DTDateComponentYear calendar:calendar];
}
/**
* Returns the month of the receiver from a given calendar
*
* @param calendar NSCalendar - The calendar to be used in the calculation
*
* @return NSInteger - represents the month as an integer
*/
- (NSInteger)monthWithCalendar:(NSCalendar *)calendar{
return [self componentForDate:self type:DTDateComponentMonth calendar:calendar];
}
/**
* Returns the day of the month of the receiver from a given calendar
*
* @param calendar NSCalendar - The calendar to be used in the calculation
*
* @return NSInteger - represents the day of the month as an integer
*/
- (NSInteger)dayWithCalendar:(NSCalendar *)calendar{
return [self componentForDate:self type:DTDateComponentDay calendar:calendar];
}
/**
* Returns the hour of the day of the receiver from a given calendar
*
* @param calendar NSCalendar - The calendar to be used in the calculation
*
* @return NSInteger - represents the hour of the day as an integer
*/
- (NSInteger)hourWithCalendar:(NSCalendar *)calendar{
return [self componentForDate:self type:DTDateComponentHour calendar:calendar];
}
/**
* Returns the minute of the hour of the receiver from a given calendar
*
* @param calendar NSCalendar - The calendar to be used in the calculation
*
* @return NSInteger - represents the minute of the hour as an integer
*/
- (NSInteger)minuteWithCalendar:(NSCalendar *)calendar{
return [self componentForDate:self type:DTDateComponentMinute calendar:calendar];
}
/**
* Returns the second of the receiver from a given calendar
*
* @param calendar NSCalendar - The calendar to be used in the calculation
*
* @return NSInteger - represents the second as an integer
*/
- (NSInteger)secondWithCalendar:(NSCalendar *)calendar{
return [self componentForDate:self type:DTDateComponentSecond calendar:calendar];
}
/**
* Returns the weekday of the receiver from a given calendar
*
* @param calendar NSCalendar - The calendar to be used in the calculation
*
* @return NSInteger - represents the weekday as an integer
*/
- (NSInteger)weekdayWithCalendar:(NSCalendar *)calendar{
return [self componentForDate:self type:DTDateComponentWeekday calendar:calendar];
}
/**
* Returns the weekday ordinal of the receiver from a given calendar
*
* @param calendar NSCalendar - The calendar to be used in the calculation
*
* @return NSInteger - represents the weekday ordinal as an integer
*/
- (NSInteger)weekdayOrdinalWithCalendar:(NSCalendar *)calendar{
return [self componentForDate:self type:DTDateComponentWeekdayOrdinal calendar:calendar];
}
/**
* Returns the quarter of the receiver from a given calendar
*
* @param calendar NSCalendar - The calendar to be used in the calculation
*
* @return NSInteger - represents the quarter as an integer
*/
- (NSInteger)quarterWithCalendar:(NSCalendar *)calendar{
return [self componentForDate:self type:DTDateComponentQuarter calendar:calendar];
}
/**
* Returns the week of the month of the receiver from a given calendar
*
* @param calendar NSCalendar - The calendar to be used in the calculation
*
* @return NSInteger - represents the week of the month as an integer
*/
- (NSInteger)weekOfMonthWithCalendar:(NSCalendar *)calendar{
return [self componentForDate:self type:DTDateComponentWeekOfMonth calendar:calendar];
}
/**
* Returns the week of the year of the receiver from a given calendar
*
* @param calendar NSCalendar - The calendar to be used in the calculation
*
* @return NSInteger - represents the week of the year as an integer
*/
- (NSInteger)weekOfYearWithCalendar:(NSCalendar *)calendar{
return [self componentForDate:self type:DTDateComponentWeekOfYear calendar:calendar];
}
/**
* Returns the year for week of the year (???) of the receiver from a given calendar
*
* @param calendar NSCalendar - The calendar to be used in the calculation
*
* @return NSInteger - represents the year for week of the year as an integer
*/
- (NSInteger)yearForWeekOfYearWithCalendar:(NSCalendar *)calendar{
return [self componentForDate:self type:DTDateComponentYearForWeekOfYear calendar:calendar];
}
/**
* Returns the day of the year of the receiver from a given calendar
*
* @param calendar NSCalendar - The calendar to be used in the calculation
*
* @return NSInteger - represents the day of the year as an integer
*/
- (NSInteger)dayOfYearWithCalendar:(NSCalendar *)calendar{
return [self componentForDate:self type:DTDateComponentDayOfYear calendar:calendar];
}
/**
* Takes in a date, calendar and desired date component and returns the desired NSInteger
* representation for that component
*
* @param date NSDate - The date to be be mined for a desired component
* @param component DTDateComponent - The desired component (i.e. year, day, week, etc)
* @param calendar NSCalendar - The calendar to be used in the processing (Defaults to Gregorian)
*
* @return NSInteger
*/
-(NSInteger)componentForDate:(NSDate *)date type:(DTDateComponent)component calendar:(NSCalendar *)calendar{
if (!calendar) {
calendar = [[self class] implicitCalendar];
}
unsigned int unitFlags = 0;
if (component == DTDateComponentYearForWeekOfYear) {
unitFlags = NSCalendarUnitYear | NSCalendarUnitQuarter | NSCalendarUnitMonth | NSCalendarUnitWeekOfYear | NSCalendarUnitWeekOfMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond | NSCalendarUnitEra | NSCalendarUnitWeekday | NSCalendarUnitWeekdayOrdinal | NSCalendarUnitWeekOfYear | NSCalendarUnitYearForWeekOfYear;
}
else {
unitFlags = allCalendarUnitFlags;
}
NSDateComponents *dateComponents = [calendar components:unitFlags fromDate:date];
switch (component) {
case DTDateComponentEra:
return [dateComponents era];
case DTDateComponentYear:
return [dateComponents year];
case DTDateComponentMonth:
return [dateComponents month];
case DTDateComponentDay:
return [dateComponents day];
case DTDateComponentHour:
return [dateComponents hour];
case DTDateComponentMinute:
return [dateComponents minute];
case DTDateComponentSecond:
return [dateComponents second];
case DTDateComponentWeekday:
return [dateComponents weekday];
case DTDateComponentWeekdayOrdinal:
return [dateComponents weekdayOrdinal];
case DTDateComponentQuarter:
return [dateComponents quarter];
case DTDateComponentWeekOfMonth:
return [dateComponents weekOfMonth];
case DTDateComponentWeekOfYear:
return [dateComponents weekOfYear];
case DTDateComponentYearForWeekOfYear:
return [dateComponents yearForWeekOfYear];
case DTDateComponentDayOfYear:
return [calendar ordinalityOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitYear forDate:date];
default:
break;
}
return 0;
}
#pragma mark - Date Creating
+ (NSDate *)dateWithYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day {
return [self dateWithYear:year month:month day:day hour:0 minute:0 second:0];
}
+ (NSDate *)dateWithYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day hour:(NSInteger)hour minute:(NSInteger)minute second:(NSInteger)second {
NSDate *nsDate = nil;
NSDateComponents *components = [[NSDateComponents alloc] init];
components.year = year;
components.month = month;
components.day = day;
components.hour = hour;
components.minute = minute;
components.second = second;
nsDate = [[[self class] implicitCalendar] dateFromComponents:components];
return nsDate;
}
+ (NSDate *)dateWithString:(NSString *)dateString formatString:(NSString *)formatString {
return [self dateWithString:dateString formatString:formatString timeZone:[NSTimeZone systemTimeZone]];
}
+ (NSDate *)dateWithString:(NSString *)dateString formatString:(NSString *)formatString timeZone:(NSTimeZone *)timeZone {
static NSDateFormatter *parser = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
parser = [[NSDateFormatter alloc] init];
});
parser.dateStyle = NSDateFormatterNoStyle;
parser.timeStyle = NSDateFormatterNoStyle;
parser.timeZone = timeZone;
parser.dateFormat = formatString;
return [parser dateFromString:dateString];
}
#pragma mark - Date Editing
#pragma mark Date By Adding
/**
* Returns a date representing the receivers date shifted later by the provided number of years.
*
* @param years NSInteger - Number of years to add
*
* @return NSDate - Date modified by the number of desired years
*/
- (NSDate *)dateByAddingYears:(NSInteger)years{
NSCalendar *calendar = [[self class] implicitCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setYear:years];
return [calendar dateByAddingComponents:components toDate:self options:0];
}
/**
* Returns a date representing the receivers date shifted later by the provided number of months.
*
* @param years NSInteger - Number of months to add
*
* @return NSDate - Date modified by the number of desired months
*/
- (NSDate *)dateByAddingMonths:(NSInteger)months{
NSCalendar *calendar = [[self class] implicitCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setMonth:months];
return [calendar dateByAddingComponents:components toDate:self options:0];
}
/**
* Returns a date representing the receivers date shifted later by the provided number of weeks.
*
* @param years NSInteger - Number of weeks to add
*
* @return NSDate - Date modified by the number of desired weeks
*/
- (NSDate *)dateByAddingWeeks:(NSInteger)weeks{
NSCalendar *calendar = [[self class] implicitCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setWeekOfYear:weeks];
return [calendar dateByAddingComponents:components toDate:self options:0];
}
/**
* Returns a date representing the receivers date shifted later by the provided number of days.
*
* @param years NSInteger - Number of days to add
*
* @return NSDate - Date modified by the number of desired days
*/
- (NSDate *)dateByAddingDays:(NSInteger)days{
NSCalendar *calendar = [[self class] implicitCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setDay:days];
return [calendar dateByAddingComponents:components toDate:self options:0];
}
/**
* Returns a date representing the receivers date shifted later by the provided number of hours.
*
* @param years NSInteger - Number of hours to add
*
* @return NSDate - Date modified by the number of desired hours
*/
- (NSDate *)dateByAddingHours:(NSInteger)hours{
NSCalendar *calendar = [[self class] implicitCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setHour:hours];
return [calendar dateByAddingComponents:components toDate:self options:0];
}
/**
* Returns a date representing the receivers date shifted later by the provided number of minutes.
*
* @param years NSInteger - Number of minutes to add
*
* @return NSDate - Date modified by the number of desired minutes
*/
- (NSDate *)dateByAddingMinutes:(NSInteger)minutes{
NSCalendar *calendar = [[self class] implicitCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setMinute:minutes];
return [calendar dateByAddingComponents:components toDate:self options:0];
}
/**
* Returns a date representing the receivers date shifted later by the provided number of seconds.
*
* @param years NSInteger - Number of seconds to add
*
* @return NSDate - Date modified by the number of desired seconds
*/
- (NSDate *)dateByAddingSeconds:(NSInteger)seconds{
NSCalendar *calendar = [[self class] implicitCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setSecond:seconds];
return [calendar dateByAddingComponents:components toDate:self options:0];
}
#pragma mark Date By Subtracting
/**
* Returns a date representing the receivers date shifted earlier by the provided number of years.
*
* @param years NSInteger - Number of years to subtract
*
* @return NSDate - Date modified by the number of desired years
*/
- (NSDate *)dateBySubtractingYears:(NSInteger)years{
NSCalendar *calendar = [[self class] implicitCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setYear:-1*years];
return [calendar dateByAddingComponents:components toDate:self options:0];
}
/**
* Returns a date representing the receivers date shifted earlier by the provided number of months.
*
* @param years NSInteger - Number of months to subtract
*
* @return NSDate - Date modified by the number of desired months
*/
- (NSDate *)dateBySubtractingMonths:(NSInteger)months{
NSCalendar *calendar = [[self class] implicitCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setMonth:-1*months];
return [calendar dateByAddingComponents:components toDate:self options:0];
}
/**
* Returns a date representing the receivers date shifted earlier by the provided number of weeks.
*
* @param years NSInteger - Number of weeks to subtract
*
* @return NSDate - Date modified by the number of desired weeks
*/
- (NSDate *)dateBySubtractingWeeks:(NSInteger)weeks{
NSCalendar *calendar = [[self class] implicitCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setWeekOfYear:-1*weeks];
return [calendar dateByAddingComponents:components toDate:self options:0];
}
/**
* Returns a date representing the receivers date shifted earlier by the provided number of days.
*
* @param years NSInteger - Number of days to subtract
*
* @return NSDate - Date modified by the number of desired days
*/
- (NSDate *)dateBySubtractingDays:(NSInteger)days{
NSCalendar *calendar = [[self class] implicitCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setDay:-1*days];
return [calendar dateByAddingComponents:components toDate:self options:0];
}
/**
* Returns a date representing the receivers date shifted earlier by the provided number of hours.
*
* @param years NSInteger - Number of hours to subtract
*
* @return NSDate - Date modified by the number of desired hours
*/
- (NSDate *)dateBySubtractingHours:(NSInteger)hours{
NSCalendar *calendar = [[self class] implicitCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setHour:-1*hours];
return [calendar dateByAddingComponents:components toDate:self options:0];
}
/**
* Returns a date representing the receivers date shifted earlier by the provided number of minutes.
*
* @param years NSInteger - Number of minutes to subtract
*
* @return NSDate - Date modified by the number of desired minutes
*/
- (NSDate *)dateBySubtractingMinutes:(NSInteger)minutes{
NSCalendar *calendar = [[self class] implicitCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setMinute:-1*minutes];
return [calendar dateByAddingComponents:components toDate:self options:0];
}
/**
* Returns a date representing the receivers date shifted earlier by the provided number of seconds.
*
* @param years NSInteger - Number of seconds to subtract
*
* @return NSDate - Date modified by the number of desired seconds
*/
- (NSDate *)dateBySubtractingSeconds:(NSInteger)seconds{
NSCalendar *calendar = [[self class] implicitCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setSecond:-1*seconds];
return [calendar dateByAddingComponents:components toDate:self options:0];
}
#pragma mark - Date Comparison
#pragma mark Time From
/**
* Returns an NSInteger representing the amount of time in years between the receiver and the provided date.
* If the receiver is earlier than the provided date, the returned value will be negative.
* Uses the default Gregorian calendar
*
* @param date NSDate - The provided date for comparison
*
* @return NSInteger - The NSInteger representation of the years between receiver and provided date
*/
-(NSInteger)yearsFrom:(NSDate *)date{
return [self yearsFrom:date calendar:nil];
}
/**
* Returns an NSInteger representing the amount of time in months between the receiver and the provided date.
* If the receiver is earlier than the provided date, the returned value will be negative.
* Uses the default Gregorian calendar
*
* @param date NSDate - The provided date for comparison
*
* @return NSInteger - The NSInteger representation of the years between receiver and provided date
*/
-(NSInteger)monthsFrom:(NSDate *)date{
return [self monthsFrom:date calendar:nil];
}
/**
* Returns an NSInteger representing the amount of time in weeks between the receiver and the provided date.
* If the receiver is earlier than the provided date, the returned value will be negative.
* Uses the default Gregorian calendar
*
* @param date NSDate - The provided date for comparison
*
* @return NSInteger - The double representation of the weeks between receiver and provided date
*/
-(NSInteger)weeksFrom:(NSDate *)date{
return [self weeksFrom:date calendar:nil];
}
/**
* Returns an NSInteger representing the amount of time in days between the receiver and the provided date.
* If the receiver is earlier than the provided date, the returned value will be negative.
* Uses the default Gregorian calendar
*
* @param date NSDate - The provided date for comparison
*
* @return NSInteger - The double representation of the days between receiver and provided date
*/
-(NSInteger)daysFrom:(NSDate *)date{
return [self daysFrom:date calendar:nil];
}
/**
* Returns an NSInteger representing the amount of time in hours between the receiver and the provided date.
* If the receiver is earlier than the provided date, the returned value will be negative.
*
* @param date NSDate - The provided date for comparison
*
* @return double - The double representation of the hours between receiver and provided date
*/
-(double)hoursFrom:(NSDate *)date{
return ([self timeIntervalSinceDate:date])/SECONDS_IN_HOUR;
}
/**
* Returns an NSInteger representing the amount of time in minutes between the receiver and the provided date.
* If the receiver is earlier than the provided date, the returned value will be negative.
*
* @param date NSDate - The provided date for comparison
*
* @return double - The double representation of the minutes between receiver and provided date
*/
-(double)minutesFrom:(NSDate *)date{
return ([self timeIntervalSinceDate:date])/SECONDS_IN_MINUTE;
}
/**
* Returns an NSInteger representing the amount of time in seconds between the receiver and the provided date.
* If the receiver is earlier than the provided date, the returned value will be negative.
*
* @param date NSDate - The provided date for comparison
*
* @return double - The double representation of the seconds between receiver and provided date
*/
-(double)secondsFrom:(NSDate *)date{
return [self timeIntervalSinceDate:date];
}
#pragma mark Time From With Calendar
/**
* Returns an NSInteger representing the amount of time in years between the receiver and the provided date.
* If the receiver is earlier than the provided date, the returned value will be negative.
*
* @param date NSDate - The provided date for comparison
* @param calendar NSCalendar - The calendar to be used in the calculation
*
* @return NSInteger - The double representation of the years between receiver and provided date
*/
-(NSInteger)yearsFrom:(NSDate *)date calendar:(NSCalendar *)calendar{
if (!calendar) {
calendar = [[self class] implicitCalendar];
}
NSDate *earliest = [self earlierDate:date];
NSDate *latest = (earliest == self) ? date : self;
NSInteger multiplier = (earliest == self) ? -1 : 1;
NSDateComponents *components = [calendar components:NSCalendarUnitYear fromDate:earliest toDate:latest options:0];
return multiplier*components.year;
}
/**
* Returns an NSInteger representing the amount of time in months between the receiver and the provided date.
* If the receiver is earlier than the provided date, the returned value will be negative.
*
* @param date NSDate - The provided date for comparison
* @param calendar NSCalendar - The calendar to be used in the calculation
*
* @return NSInteger - The double representation of the months between receiver and provided date
*/
-(NSInteger)monthsFrom:(NSDate *)date calendar:(NSCalendar *)calendar{
if (!calendar) {
calendar = [[self class] implicitCalendar];
}
NSDate *earliest = [self earlierDate:date];
NSDate *latest = (earliest == self) ? date : self;
NSInteger multiplier = (earliest == self) ? -1 : 1;
NSDateComponents *components = [calendar components:allCalendarUnitFlags fromDate:earliest toDate:latest options:0];
return multiplier*(components.month + 12*components.year);
}
/**
* Returns an NSInteger representing the amount of time in weeks between the receiver and the provided date.
* If the receiver is earlier than the provided date, the returned value will be negative.
*
* @param date NSDate - The provided date for comparison
* @param calendar NSCalendar - The calendar to be used in the calculation
*
* @return NSInteger - The double representation of the weeks between receiver and provided date
*/
-(NSInteger)weeksFrom:(NSDate *)date calendar:(NSCalendar *)calendar{
if (!calendar) {
calendar = [[self class] implicitCalendar];
}
NSDate *earliest = [self earlierDate:date];
NSDate *latest = (earliest == self) ? date : self;
NSInteger multiplier = (earliest == self) ? -1 : 1;
NSDateComponents *components = [calendar components:NSCalendarUnitWeekOfYear fromDate:earliest toDate:latest options:0];
return multiplier*components.weekOfYear;
}
/**
* Returns an NSInteger representing the amount of time in days between the receiver and the provided date.
* If the receiver is earlier than the provided date, the returned value will be negative.
*
* @param date NSDate - The provided date for comparison
* @param calendar NSCalendar - The calendar to be used in the calculation
*
* @return NSInteger - The double representation of the days between receiver and provided date
*/
-(NSInteger)daysFrom:(NSDate *)date calendar:(NSCalendar *)calendar{
if (!calendar) {
calendar = [[self class] implicitCalendar];
}
NSDate *earliest = [self earlierDate:date];
NSDate *latest = (earliest == self) ? date : self;
NSInteger multiplier = (earliest == self) ? -1 : 1;
NSDateComponents *components = [calendar components:NSCalendarUnitDay fromDate:earliest toDate:latest options:0];
return multiplier*components.day;
}
#pragma mark Time Until
/**
* Returns the number of years until the receiver's date. Returns 0 if the receiver is the same or earlier than now.
*
* @return NSInteger representiation of years
*/
-(NSInteger)yearsUntil{
return [self yearsLaterThan:[NSDate date]];
}
/**
* Returns the number of months until the receiver's date. Returns 0 if the receiver is the same or earlier than now.
*
* @return NSInteger representiation of months
*/
-(NSInteger)monthsUntil{
return [self monthsLaterThan:[NSDate date]];
}
/**
* Returns the number of weeks until the receiver's date. Returns 0 if the receiver is the same or earlier than now.
*
* @return NSInteger representiation of weeks
*/
-(NSInteger)weeksUntil{
return [self weeksLaterThan:[NSDate date]];
}
/**
* Returns the number of days until the receiver's date. Returns 0 if the receiver is the same or earlier than now.
*
* @return NSInteger representiation of days
*/
-(NSInteger)daysUntil{
return [self daysLaterThan:[NSDate date]];
}
/**
* Returns the number of hours until the receiver's date. Returns 0 if the receiver is the same or earlier than now.
*
* @return double representiation of hours
*/
-(double)hoursUntil{
return [self hoursLaterThan:[NSDate date]];
}
/**
* Returns the number of minutes until the receiver's date. Returns 0 if the receiver is the same or earlier than now.
*
* @return double representiation of minutes
*/
-(double)minutesUntil{
return [self minutesLaterThan:[NSDate date]];
}
/**
* Returns the number of seconds until the receiver's date. Returns 0 if the receiver is the same or earlier than now.
*
* @return double representiation of seconds
*/
-(double)secondsUntil{
return [self secondsLaterThan:[NSDate date]];
}
#pragma mark Time Ago
/**
* Returns the number of years the receiver's date is earlier than now. Returns 0 if the receiver is the same or later than now.
*
* @return NSInteger representiation of years
*/
-(NSInteger)yearsAgo{
return [self yearsEarlierThan:[NSDate date]];
}
/**
* Returns the number of months the receiver's date is earlier than now. Returns 0 if the receiver is the same or later than now.
*
* @return NSInteger representiation of months
*/
-(NSInteger)monthsAgo{
return [self monthsEarlierThan:[NSDate date]];
}
/**
* Returns the number of weeks the receiver's date is earlier than now. Returns 0 if the receiver is the same or later than now.
*
* @return NSInteger representiation of weeks
*/
-(NSInteger)weeksAgo{
return [self weeksEarlierThan:[NSDate date]];
}
/**
* Returns the number of days the receiver's date is earlier than now. Returns 0 if the receiver is the same or later than now.
*
* @return NSInteger representiation of days
*/
-(NSInteger)daysAgo{
return [self daysEarlierThan:[NSDate date]];
}
/**
* Returns the number of hours the receiver's date is earlier than now. Returns 0 if the receiver is the same or later than now.
*
* @return double representiation of hours
*/
-(double)hoursAgo{
return [self hoursEarlierThan:[NSDate date]];
}
/**
* Returns the number of minutes the receiver's date is earlier than now. Returns 0 if the receiver is the same or later than now.
*
* @return double representiation of minutes
*/
-(double)minutesAgo{
return [self minutesEarlierThan:[NSDate date]];
}
/**
* Returns the number of seconds the receiver's date is earlier than now. Returns 0 if the receiver is the same or later than now.
*
* @return double representiation of seconds
*/
-(double)secondsAgo{
return [self secondsEarlierThan:[NSDate date]];
}
#pragma mark Earlier Than
/**
* Returns the number of years the receiver's date is earlier than the provided comparison date.
* Returns 0 if the receiver's date is later than or equal to the provided comparison date.
*
* @param date NSDate - Provided date for comparison
*
* @return NSInteger representing the number of years
*/
-(NSInteger)yearsEarlierThan:(NSDate *)date{
return ABS(MIN([self yearsFrom:date], 0));
}
/**
* Returns the number of months the receiver's date is earlier than the provided comparison date.
* Returns 0 if the receiver's date is later than or equal to the provided comparison date.
*
* @param date NSDate - Provided date for comparison
*
* @return NSInteger representing the number of months
*/
-(NSInteger)monthsEarlierThan:(NSDate *)date{
return ABS(MIN([self monthsFrom:date], 0));
}
/**
* Returns the number of weeks the receiver's date is earlier than the provided comparison date.
* Returns 0 if the receiver's date is later than or equal to the provided comparison date.
*
* @param date NSDate - Provided date for comparison
*
* @return NSInteger representing the number of weeks
*/
-(NSInteger)weeksEarlierThan:(NSDate *)date{
return ABS(MIN([self weeksFrom:date], 0));
}
/**
* Returns the number of days the receiver's date is earlier than the provided comparison date.
* Returns 0 if the receiver's date is later than or equal to the provided comparison date.
*
* @param date NSDate - Provided date for comparison
*
* @return NSInteger representing the number of days
*/
-(NSInteger)daysEarlierThan:(NSDate *)date{
return ABS(MIN([self daysFrom:date], 0));
}
/**
* Returns the number of hours the receiver's date is earlier than the provided comparison date.
* Returns 0 if the receiver's date is later than or equal to the provided comparison date.
*
* @param date NSDate - Provided date for comparison
*
* @return double representing the number of hours
*/
-(double)hoursEarlierThan:(NSDate *)date{
return ABS(MIN([self hoursFrom:date], 0));
}
/**
* Returns the number of minutes the receiver's date is earlier than the provided comparison date.
* Returns 0 if the receiver's date is later than or equal to the provided comparison date.
*
* @param date NSDate - Provided date for comparison
*
* @return double representing the number of minutes
*/
-(double)minutesEarlierThan:(NSDate *)date{
return ABS(MIN([self minutesFrom:date], 0));
}
/**
* Returns the number of seconds the receiver's date is earlier than the provided comparison date.
* Returns 0 if the receiver's date is later than or equal to the provided comparison date.
*
* @param date NSDate - Provided date for comparison
*
* @return double representing the number of seconds
*/
-(double)secondsEarlierThan:(NSDate *)date{
return ABS(MIN([self secondsFrom:date], 0));
}
#pragma mark Later Than
/**
* Returns the number of years the receiver's date is later than the provided comparison date.
* Returns 0 if the receiver's date is earlier than or equal to the provided comparison date.
*
* @param date NSDate - Provided date for comparison
*
* @return NSInteger representing the number of years
*/
-(NSInteger)yearsLaterThan:(NSDate *)date{
return MAX([self yearsFrom:date], 0);
}
/**
* Returns the number of months the receiver's date is later than the provided comparison date.
* Returns 0 if the receiver's date is earlier than or equal to the provided comparison date.
*
* @param date NSDate - Provided date for comparison
*
* @return NSInteger representing the number of months
*/
-(NSInteger)monthsLaterThan:(NSDate *)date{
return MAX([self monthsFrom:date], 0);
}
/**
* Returns the number of weeks the receiver's date is later than the provided comparison date.
* Returns 0 if the receiver's date is earlier than or equal to the provided comparison date.
*
* @param date NSDate - Provided date for comparison
*
* @return NSInteger representing the number of weeks
*/
-(NSInteger)weeksLaterThan:(NSDate *)date{
return MAX([self weeksFrom:date], 0);
}
/**
* Returns the number of days the receiver's date is later than the provided comparison date.
* Returns 0 if the receiver's date is earlier than or equal to the provided comparison date.
*
* @param date NSDate - Provided date for comparison
*
* @return NSInteger representing the number of days
*/
-(NSInteger)daysLaterThan:(NSDate *)date{
return MAX([self daysFrom:date], 0);
}
/**
* Returns the number of hours the receiver's date is later than the provided comparison date.
* Returns 0 if the receiver's date is earlier than or equal to the provided comparison date.
*
* @param date NSDate - Provided date for comparison
*
* @return double representing the number of hours
*/
-(double)hoursLaterThan:(NSDate *)date{
return MAX([self hoursFrom:date], 0);
}
/**
* Returns the number of minutes the receiver's date is later than the provided comparison date.
* Returns 0 if the receiver's date is earlier than or equal to the provided comparison date.
*
* @param date NSDate - Provided date for comparison
*
* @return double representing the number of minutes
*/
-(double)minutesLaterThan:(NSDate *)date{
return MAX([self minutesFrom:date], 0);
}
/**
* Returns the number of seconds the receiver's date is later than the provided comparison date.
* Returns 0 if the receiver's date is earlier than or equal to the provided comparison date.
*
* @param date NSDate - Provided date for comparison
*
* @return double representing the number of seconds
*/
-(double)secondsLaterThan:(NSDate *)date{
return MAX([self secondsFrom:date], 0);
}
#pragma mark Comparators
/**
* Returns a YES if receiver is earlier than provided comparison date, otherwise returns NO
*
* @param date NSDate - Provided date for comparison
*
* @return BOOL representing comparison result
*/
-(BOOL)isEarlierThan:(NSDate *)date{
if (self.timeIntervalSince1970 < date.timeIntervalSince1970) {
return YES;
}
return NO;
}
/**
* Returns a YES if receiver is later than provided comparison date, otherwise returns NO
*
* @param date NSDate - Provided date for comparison
*
* @return BOOL representing comparison result
*/
-(BOOL)isLaterThan:(NSDate *)date{
if (self.timeIntervalSince1970 > date.timeIntervalSince1970) {
return YES;
}
return NO;
}
/**
* Returns a YES if receiver is earlier than or equal to the provided comparison date, otherwise returns NO
*
* @param date NSDate - Provided date for comparison
*
* @return BOOL representing comparison result
*/
-(BOOL)isEarlierThanOrEqualTo:(NSDate *)date{
if (self.timeIntervalSince1970 <= date.timeIntervalSince1970) {
return YES;
}
return NO;
}
/**
* Returns a YES if receiver is later than or equal to provided comparison date, otherwise returns NO
*
* @param date NSDate - Provided date for comparison
*
* @return BOOL representing comparison result
*/
-(BOOL)isLaterThanOrEqualTo:(NSDate *)date{
if (self.timeIntervalSince1970 >= date.timeIntervalSince1970) {
return YES;
}
return NO;
}
#pragma mark - Formatted Dates
#pragma mark Formatted With Style
/**
* Convenience method that returns a formatted string representing the receiver's date formatted to a given style
*
* @param style NSDateFormatterStyle - Desired date formatting style
*
* @return NSString representing the formatted date string
*/
-(NSString *)formattedDateWithStyle:(NSDateFormatterStyle)style{
return [self formattedDateWithStyle:style timeZone:[NSTimeZone systemTimeZone] locale:[NSLocale autoupdatingCurrentLocale]];
}
/**
* Convenience method that returns a formatted string representing the receiver's date formatted to a given style and time zone
*
* @param style NSDateFormatterStyle - Desired date formatting style
* @param timeZone NSTimeZone - Desired time zone
*
* @return NSString representing the formatted date string
*/
-(NSString *)formattedDateWithStyle:(NSDateFormatterStyle)style timeZone:(NSTimeZone *)timeZone{
return [self formattedDateWithStyle:style timeZone:timeZone locale:[NSLocale autoupdatingCurrentLocale]];
}
/**
* Convenience method that returns a formatted string representing the receiver's date formatted to a given style and locale
*
* @param style NSDateFormatterStyle - Desired date formatting style
* @param locale NSLocale - Desired locale
*
* @return NSString representing the formatted date string
*/
-(NSString *)formattedDateWithStyle:(NSDateFormatterStyle)style locale:(NSLocale *)locale{
return [self formattedDateWithStyle:style timeZone:[NSTimeZone systemTimeZone] locale:locale];
}
/**
* Convenience method that returns a formatted string representing the receiver's date formatted to a given style, time zone and locale
*
* @param style NSDateFormatterStyle - Desired date formatting style
* @param timeZone NSTimeZone - Desired time zone
* @param locale NSLocale - Desired locale
*
* @return NSString representing the formatted date string
*/
-(NSString *)formattedDateWithStyle:(NSDateFormatterStyle)style timeZone:(NSTimeZone *)timeZone locale:(NSLocale *)locale{
static NSDateFormatter *formatter = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
formatter = [[NSDateFormatter alloc] init];
});
[formatter setDateStyle:style];
[formatter setTimeZone:timeZone];
[formatter setLocale:locale];
return [formatter stringFromDate:self];
}
#pragma mark Formatted With Format
/**
* Convenience method that returns a formatted string representing the receiver's date formatted to a given date format
*
* @param format NSString - String representing the desired date format
*
* @return NSString representing the formatted date string
*/
-(NSString *)formattedDateWithFormat:(NSString *)format{
return [self formattedDateWithFormat:format timeZone:[NSTimeZone systemTimeZone] locale:[NSLocale autoupdatingCurrentLocale]];
}
/**
* Convenience method that returns a formatted string representing the receiver's date formatted to a given date format and time zone
*
* @param format NSString - String representing the desired date format
* @param timeZone NSTimeZone - Desired time zone
*
* @return NSString representing the formatted date string
*/
-(NSString *)formattedDateWithFormat:(NSString *)format timeZone:(NSTimeZone *)timeZone{
return [self formattedDateWithFormat:format timeZone:timeZone locale:[NSLocale autoupdatingCurrentLocale]];
}
/**
* Convenience method that returns a formatted string representing the receiver's date formatted to a given date format and locale
*
* @param format NSString - String representing the desired date format
* @param locale NSLocale - Desired locale
*
* @return NSString representing the formatted date string
*/
-(NSString *)formattedDateWithFormat:(NSString *)format locale:(NSLocale *)locale{
return [self formattedDateWithFormat:format timeZone:[NSTimeZone systemTimeZone] locale:locale];
}
/**
* Convenience method that returns a formatted string representing the receiver's date formatted to a given date format, time zone and locale
*
* @param format NSString - String representing the desired date format
* @param timeZone NSTimeZone - Desired time zone
* @param locale NSLocale - Desired locale
*
* @return NSString representing the formatted date string
*/
-(NSString *)formattedDateWithFormat:(NSString *)format timeZone:(NSTimeZone *)timeZone locale:(NSLocale *)locale{
static NSDateFormatter *formatter = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
formatter = [[NSDateFormatter alloc] init];
});
[formatter setDateFormat:format];
[formatter setTimeZone:timeZone];
[formatter setLocale:locale];
return [formatter stringFromDate:self];
}
#pragma mark - Helpers
/**
* Class method that returns whether the given year is a leap year for the Gregorian Calendar
* Returns YES if year is a leap year, otherwise returns NO
*
* @param year NSInteger - Year to evaluate
*
* @return BOOL evaluation of year
*/
+(BOOL)isLeapYear:(NSInteger)year{
if (year%400){
return YES;
}
else if (year%100){
return NO;
}
else if (year%4){
return YES;
}
return NO;
}
/**
* Retrieves the default calendar identifier used for all non-calendar-specified operations
*
* @return NSString - NSCalendarIdentifier
*/
+(NSString *)defaultCalendarIdentifier {
return defaultCalendarIdentifier;
}
/**
* Sets the default calendar identifier used for all non-calendar-specified operations
*
* @param identifier NSString - NSCalendarIdentifier
*/
+ (void)setDefaultCalendarIdentifier:(NSString *)identifier {
defaultCalendarIdentifier = [identifier copy];
implicitCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:defaultCalendarIdentifier ?: NSCalendarIdentifierGregorian];
}
/**
* Retrieves a default NSCalendar instance, based on the value of defaultCalendarSetting
*
* @return NSCalendar The current implicit calendar
*/
+ (NSCalendar *)implicitCalendar {
return implicitCalendar;
}
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/DateTools.podspec
================================================
Pod::Spec.new do |s|
s.name = 'DateTools'
s.version = '1.7.0'
s.summary = 'Dates and time made easy in Objective-C'
s.homepage = 'https://github.com/MatthewYork/DateTools'
s.description = 'DateTools was written to streamline date and time handling in Objective-C.'
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { "Matthew York" => "my3681@gmail.com" }
s.source = { :git => "https://github.com/MatthewYork/DateTools.git",
:tag => "v#{s.version.to_s}" }
s.ios.platform = :ios, '7.0'
s.osx.platform = :iox, '10.7'
s.requires_arc = true
s.source_files = 'DateTools'
s.resources = 'DateTools/DateTools.bundle'
end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateTools/Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
com.molabo.$(PRODUCT_NAME:rfc1034identifier)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
FMWK
CFBundleShortVersionString
1.0
CFBundleSignature
????
CFBundleVersion
$(CURRENT_PROJECT_VERSION)
NSPrincipalClass
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExample/AppDelegate.h
================================================
//
// AppDelegate.h
// DateToolsExample
//
// Created by Matthew York on 3/19/14.
//
//
#import
@interface AppDelegate : UIResponder
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) UITabBarController *tabBarController;
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExample/AppDelegate.m
================================================
//
// AppDelegate.m
// DateToolsExample
//
// Created by Matthew York on 3/19/14.
//
//
#import "AppDelegate.h"
#import "Colours.h"
#import "ExampleNavigationController.h"
#import "DateToolsViewController.h"
#import "TimePeriodsViewController.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
[self initializeTabBarController];
[self.window setRootViewController:self.tabBarController];
[self.window makeKeyAndVisible];
// Override point for customization after application launch.
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
-(void)initializeTabBarController{
ExampleNavigationController *dtVC = [[ExampleNavigationController alloc] initWithRootViewController:[[DateToolsViewController alloc] initWithNibName:@"DateToolsViewController" bundle:nil]];
ExampleNavigationController *tpVC = [[ExampleNavigationController alloc] initWithRootViewController:[[TimePeriodsViewController alloc] initWithNibName:@"TimePeriodsViewController" bundle:nil]];
//Initialize tab bar controller
self.tabBarController = [[UITabBarController alloc] init];
//Style tab bar
if ([self.tabBarController.tabBar respondsToSelector:@selector(setTranslucent:)]) {
[self.tabBarController.tabBar setTranslucent:NO];
[self.tabBarController.tabBar setTintColor:[UIColor infoBlueColor]];
}
else {
[self.tabBarController.tabBar setBackgroundColor:[UIColor infoBlueColor]];
}
//Add view controllers
self.tabBarController.viewControllers = @[dtVC, tpVC];
}
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExample/Colours.h
================================================
// Copyright (C) 2013 by Benjamin Gordon
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and
// associated documentation files (the "Software"), to
// deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall
// be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "TargetConditionals.h"
#include
#pragma mark - Static String Keys
static NSString * kColoursRGBA_R = @"RGBA-r";
static NSString * kColoursRGBA_G = @"RGBA-g";
static NSString * kColoursRGBA_B = @"RGBA-b";
static NSString * kColoursRGBA_A = @"RGBA-a";
static NSString * kColoursHSBA_H = @"HSBA-h";
static NSString * kColoursHSBA_S = @"HSBA-s";
static NSString * kColoursHSBA_B = @"HSBA-b";
static NSString * kColoursHSBA_A = @"HSBA-a";
static NSString * kColoursCIE_L = @"LABa-L";
static NSString * kColoursCIE_A = @"LABa-A";
static NSString * kColoursCIE_B = @"LABa-B";
static NSString * kColoursCIE_alpha = @"LABa-a";
static NSString * kColoursCMYK_C = @"CMYK-c";
static NSString * kColoursCMYK_M = @"CMYK-m";
static NSString * kColoursCMYK_Y = @"CMYK-y";
static NSString * kColoursCMYK_K = @"CMYK-k";
#pragma mark - Create correct iOS/OSX interface
#if TARGET_OS_IPHONE
#import
@interface UIColor (Colours)
#elif TARGET_OS_MAC
#import
@interface NSColor (Colours)
#endif
#pragma mark - Enums
// Color Scheme Generation Enum
typedef NS_ENUM(NSInteger, ColorScheme) {
ColorSchemeAnalagous,
ColorSchemeMonochromatic,
ColorSchemeTriad,
ColorSchemeComplementary
};
// ColorFormulation Type
typedef NS_ENUM(NSInteger, ColorFormulation) {
ColorFormulationRGBA,
ColorFormulationHSBA,
ColorFormulationLAB,
ColorFormulationCMYK
};
// ColorDistance
typedef NS_ENUM(NSInteger, ColorDistance) {
ColorDistanceCIE76,
ColorDistanceCIE94,
ColorDistanceCIE2000,
};
#pragma mark - Color from Hex/RGBA/HSBA/CIE_LAB/CMYK
/**
Creates a Color from a Hex representation string
@param hexString Hex string that looks like @"#FF0000" or @"FF0000"
@return Color
*/
+ (instancetype)colorFromHexString:(NSString *)hexString;
/**
Creates a Color from an array of 4 NSNumbers (r,g,b,a)
@param rgbaArray 4 NSNumbers for rgba between 0 - 1
@return Color
*/
+ (instancetype)colorFromRGBAArray:(NSArray *)rgbaArray;
/**
Creates a Color from a dictionary of 4 NSNumbers
Keys: kColoursRGBA_R, kColoursRGBA_G, kColoursRGBA_B, kColoursRGBA_A
@param rgbaDictionary 4 NSNumbers for rgba between 0 - 1
@return Color
*/
+ (instancetype)colorFromRGBADictionary:(NSDictionary *)rgbaDict;
/**
Creates a Color from an array of 4 NSNumbers (h,s,b,a)
@param hsbaArray 4 NSNumbers for rgba between 0 - 1
@return Color
*/
+ (instancetype)colorFromHSBAArray:(NSArray *)hsbaArray;
/**
Creates a Color from a dictionary of 4 NSNumbers
Keys: kColoursHSBA_H, kColoursHSBA_S, kColoursHSBA_B, kColoursHSBA_A
@param hsbaDictionary 4 NSNumbers for rgba between 0 - 1
@return Color
*/
+ (instancetype)colorFromHSBADictionary:(NSDictionary *)hsbaDict;
/**
Creates a Color from an array of 4 NSNumbers (L,a,b,alpha)
@param colors 4 NSNumbers for CIE_LAB between 0 - 1
@return Color
*/
+ (instancetype)colorFromCIE_LabArray:(NSArray *)colors;
/**
Creates a Color from a dictionary of 4 NSNumbers
Keys: kColoursCIE_L, kColoursCIE_A, kColoursCIE_B, kColoursCIE_alpha
@param colors 4 NSNumbers for CIE_LAB between 0 - 1
@return Color
*/
+ (instancetype)colorFromCIE_LabDictionary:(NSDictionary *)colors;
/**
Creates a Color from an array of 4 NSNumbers (C,M,Y,K)
@param colors 4 NSNumbers for CMYK between 0 - 1
@return Color
*/
+ (instancetype)colorFromCMYKArray:(NSArray *)cmyk;
/**
Creates a Color from a dictionary of 4 NSNumbers
Keys: kColoursCMYK_C, kColoursCMYK_M, kColoursCMYK_Y, kColoursCMYK_K
@param colors 4 NSNumbers for CMYK between 0 - 1
@return Color
*/
+ (instancetype)colorFromCMYKDictionary:(NSDictionary *)cmyk;
#pragma mark - Hex/RGBA/HSBA/CIE_LAB/CMYK from Color
/**
Creates a Hex representation from a Color
@return NSString
*/
- (NSString *)hexString;
/**
Creates an array of 4 NSNumbers representing the float values of r, g, b, a in that order.
@return NSArray
*/
- (NSArray *)rgbaArray;
/**
Creates an array of 4 NSNumbers representing the float values of h, s, b, a in that order.
@return NSArray
*/
- (NSArray *)hsbaArray;
/**
Creates a dictionary of 4 NSNumbers representing float values with keys: kColoursRGBA_R, kColoursRGBA_G, kColoursRGBA_B, kColoursRGBA_A
@return NSDictionary
*/
- (NSDictionary *)rgbaDictionary;
/**
Creates a dictionary of 4 NSNumbers representing float values with keys: kColoursHSBA_H, kColoursHSBA_S, kColoursHSBA_B, kColoursHSBA_A
@return NSDictionary
*/
- (NSDictionary *)hsbaDictionary;
/**
* Creates an array of 4 NSNumbers representing the float values of L*, a, b, alpha in that order.
*
* @return NSArray
*/
- (NSArray *)CIE_LabArray;
/**
* Creates a dictionary of 4 NSNumbers representing the float values with keys: kColoursCIE_L, kColoursCIE_A, kColoursCIE_B, kColoursCIE_alpha
*
* @return NSDictionary
*/
- (NSDictionary *)CIE_LabDictionary;
/**
* Creates an array of 4 NSNumbers representing the float values of C, M, Y, K in that order.
*
* @return NSArray
*/
- (NSArray *)cmykArray;
/**
* Creates a dictionary of 4 NSNumbers representing the float values with keys: kColoursCMYK_C, kColoursCMYK_M, kColoursCMYK_Y, kColoursCMYK_K
*
* @return NSDictionary
*/
- (NSDictionary *)cmykDictionary;
#pragma mark - Color Components
/**
* Creates an NSDictionary with RGBA and HSBA color components inside.
*
* @return NSDictionary
*/
- (NSDictionary *)colorComponents;
/**
* Returns the red value from an RGBA formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)red;
/**
* Returns the green value from an RGBA formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)green;
/**
* Returns the blue value from an RGBA formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)blue;
/**
* Returns the hue value from an HSBA formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)hue;
/**
* Returns the saturation value from an HSBA formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)saturation;
/**
* Returns the brightness value from an HSBA formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)brightness;
/**
* Returns the alpha value from an RGBA formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)alpha;
/**
* Returns the lightness value from a CIELAB formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)CIE_Lightness;
/**
* Returns the a value from a CIELAB formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)CIE_a;
/**
* Returns the b value from a CIELAB formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)CIE_b;
/**
* Returns the cyan value from a CMYK formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)cyan;
/**
* Returns the magenta value from a CMYK formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)magenta;
/**
* Returns the yellow value from a CMYK formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)yellow;
/**
* Returns the black (K) value from a CMYK formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)keyBlack;
#pragma mark - 4 Color Scheme from Color
/**
Creates an NSArray of 4 Colors that complement the Color.
@param type ColorSchemeAnalagous, ColorSchemeMonochromatic, ColorSchemeTriad, ColorSchemeComplementary
@return NSArray
*/
- (NSArray *)colorSchemeOfType:(ColorScheme)type;
#pragma mark - Contrasting Color from Color
/**
Creates either [Color whiteColor] or [Color blackColor] depending on if the color this method is run on is dark or light.
@return Color
*/
- (instancetype)blackOrWhiteContrastingColor;
#pragma mark - Complementary Color
/**
Creates a complementary color - a color directly opposite it on the color wheel.
@return Color
*/
- (instancetype)complementaryColor;
#pragma mark - Distance between Colors
/**
* Returns a float of the distance between 2 colors. Defaults to the
* CIE94 specification found here: http://en.wikipedia.org/wiki/Color_difference
*
* @param color Color to check self with.
*
* @return CGFloat
*/
- (CGFloat)distanceFromColor:(id)color;
/**
* Returns a float of the distance between 2 colors, using one of
*
*
* @param color Color to check against
* @param distanceType Formula to calculate with
*
* @return CGFloat
*/
- (CGFloat)distanceFromColor:(id)color type:(ColorDistance)distanceType;
#pragma mark - Colors
// System Colors
+ (instancetype)infoBlueColor;
+ (instancetype)successColor;
+ (instancetype)warningColor;
+ (instancetype)dangerColor;
// Whites
+ (instancetype)antiqueWhiteColor;
+ (instancetype)oldLaceColor;
+ (instancetype)ivoryColor;
+ (instancetype)seashellColor;
+ (instancetype)ghostWhiteColor;
+ (instancetype)snowColor;
+ (instancetype)linenColor;
// Grays
+ (instancetype)black25PercentColor;
+ (instancetype)black50PercentColor;
+ (instancetype)black75PercentColor;
+ (instancetype)warmGrayColor;
+ (instancetype)coolGrayColor;
+ (instancetype)charcoalColor;
// Blues
+ (instancetype)tealColor;
+ (instancetype)steelBlueColor;
+ (instancetype)robinEggColor;
+ (instancetype)pastelBlueColor;
+ (instancetype)turquoiseColor;
+ (instancetype)skyBlueColor;
+ (instancetype)indigoColor;
+ (instancetype)denimColor;
+ (instancetype)blueberryColor;
+ (instancetype)cornflowerColor;
+ (instancetype)babyBlueColor;
+ (instancetype)midnightBlueColor;
+ (instancetype)fadedBlueColor;
+ (instancetype)icebergColor;
+ (instancetype)waveColor;
// Greens
+ (instancetype)emeraldColor;
+ (instancetype)grassColor;
+ (instancetype)pastelGreenColor;
+ (instancetype)seafoamColor;
+ (instancetype)paleGreenColor;
+ (instancetype)cactusGreenColor;
+ (instancetype)chartreuseColor;
+ (instancetype)hollyGreenColor;
+ (instancetype)oliveColor;
+ (instancetype)oliveDrabColor;
+ (instancetype)moneyGreenColor;
+ (instancetype)honeydewColor;
+ (instancetype)limeColor;
+ (instancetype)cardTableColor;
// Reds
+ (instancetype)salmonColor;
+ (instancetype)brickRedColor;
+ (instancetype)easterPinkColor;
+ (instancetype)grapefruitColor;
+ (instancetype)pinkColor;
+ (instancetype)indianRedColor;
+ (instancetype)strawberryColor;
+ (instancetype)coralColor;
+ (instancetype)maroonColor;
+ (instancetype)watermelonColor;
+ (instancetype)tomatoColor;
+ (instancetype)pinkLipstickColor;
+ (instancetype)paleRoseColor;
+ (instancetype)crimsonColor;
// Purples
+ (instancetype)eggplantColor;
+ (instancetype)pastelPurpleColor;
+ (instancetype)palePurpleColor;
+ (instancetype)coolPurpleColor;
+ (instancetype)violetColor;
+ (instancetype)plumColor;
+ (instancetype)lavenderColor;
+ (instancetype)raspberryColor;
+ (instancetype)fuschiaColor;
+ (instancetype)grapeColor;
+ (instancetype)periwinkleColor;
+ (instancetype)orchidColor;
// Yellows
+ (instancetype)goldenrodColor;
+ (instancetype)yellowGreenColor;
+ (instancetype)bananaColor;
+ (instancetype)mustardColor;
+ (instancetype)buttermilkColor;
+ (instancetype)goldColor;
+ (instancetype)creamColor;
+ (instancetype)lightCreamColor;
+ (instancetype)wheatColor;
+ (instancetype)beigeColor;
// Oranges
+ (instancetype)peachColor;
+ (instancetype)burntOrangeColor;
+ (instancetype)pastelOrangeColor;
+ (instancetype)cantaloupeColor;
+ (instancetype)carrotColor;
+ (instancetype)mandarinColor;
// Browns
+ (instancetype)chiliPowderColor;
+ (instancetype)burntSiennaColor;
+ (instancetype)chocolateColor;
+ (instancetype)coffeeColor;
+ (instancetype)cinnamonColor;
+ (instancetype)almondColor;
+ (instancetype)eggshellColor;
+ (instancetype)sandColor;
+ (instancetype)mudColor;
+ (instancetype)siennaColor;
+ (instancetype)dustColor;
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExample/Colours.m
================================================
// Copyright (C) 2013 by Benjamin Gordon
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and
// associated documentation files (the "Software"), to
// deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall
// be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "Colours.h"
// Swizzle
#import
#pragma mark - Create correct iOS/OSX implementation
#if TARGET_OS_IPHONE
#import
@implementation UIColor (Colours)
#elif TARGET_OS_MAC
#import
@implementation NSColor (Colours)
#endif
#pragma mark - Color from Hex
+ (instancetype)colorFromHexString:(NSString *)hexString
{
unsigned rgbValue = 0;
hexString = [hexString stringByReplacingOccurrencesOfString:@"#" withString:@""];
NSScanner *scanner = [NSScanner scannerWithString:hexString];
[scanner scanHexInt:&rgbValue];
return [[self class] colorWithR:((rgbValue & 0xFF0000) >> 16) G:((rgbValue & 0xFF00) >> 8) B:(rgbValue & 0xFF) A:1.0];
}
#pragma mark - Hex from Color
- (NSString *)hexString
{
NSArray *colorArray = [self rgbaArray];
int r = [colorArray[0] floatValue] * 255;
int g = [colorArray[1] floatValue] * 255;
int b = [colorArray[2] floatValue] * 255;
NSString *red = [NSString stringWithFormat:@"%02x", r];
NSString *green = [NSString stringWithFormat:@"%02x", g];
NSString *blue = [NSString stringWithFormat:@"%02x", b];
return [NSString stringWithFormat:@"#%@%@%@", red, green, blue];
}
#pragma mark - Color from RGBA
+ (instancetype)colorFromRGBAArray:(NSArray *)rgbaArray
{
if (rgbaArray.count < 4) {
return [[self class] clearColor];
}
return [[self class] colorWithRed:[rgbaArray[0] floatValue]
green:[rgbaArray[1] floatValue]
blue:[rgbaArray[2] floatValue]
alpha:[rgbaArray[3] floatValue]];
}
+ (instancetype)colorFromRGBADictionary:(NSDictionary *)rgbaDict
{
if (rgbaDict[kColoursRGBA_R] && rgbaDict[kColoursRGBA_G] && rgbaDict[kColoursRGBA_B] && rgbaDict[kColoursRGBA_A]) {
return [[self class] colorWithRed:[rgbaDict[kColoursRGBA_R] floatValue]
green:[rgbaDict[kColoursRGBA_G] floatValue]
blue:[rgbaDict[kColoursRGBA_B] floatValue]
alpha:[rgbaDict[kColoursRGBA_A] floatValue]];
}
return [[self class] clearColor];
}
#pragma mark - RGBA from Color
- (NSArray *)rgbaArray
{
CGFloat r=0,g=0,b=0,a=0;
if ([self respondsToSelector:@selector(getRed:green:blue:alpha:)]) {
[self getRed:&r green:&g blue:&b alpha:&a];
}
else {
const CGFloat *components = CGColorGetComponents(self.CGColor);
r = components[0];
g = components[1];
b = components[2];
a = components[3];
}
return @[@(r),
@(g),
@(b),
@(a)];
}
- (NSDictionary *)rgbaDictionary
{
CGFloat r=0,g=0,b=0,a=0;
if ([self respondsToSelector:@selector(getRed:green:blue:alpha:)]) {
[self getRed:&r green:&g blue:&b alpha:&a];
}
else {
const CGFloat *components = CGColorGetComponents(self.CGColor);
r = components[0];
g = components[1];
b = components[2];
a = components[3];
}
return @{kColoursRGBA_R:@(r),
kColoursRGBA_G:@(g),
kColoursRGBA_B:@(b),
kColoursRGBA_A:@(a)};
}
#pragma mark - HSBA from Color
- (NSArray *)hsbaArray
{
// Takes a [self class] and returns Hue,Saturation,Brightness,Alpha values in NSNumber form
CGFloat h=0,s=0,b=0,a=0;
if ([self respondsToSelector:@selector(getHue:saturation:brightness:alpha:)]) {
[self getHue:&h saturation:&s brightness:&b alpha:&a];
}
return @[@(h),
@(s),
@(b),
@(a)];
}
- (NSDictionary *)hsbaDictionary
{
CGFloat h=0,s=0,b=0,a=0;
if ([self respondsToSelector:@selector(getHue:saturation:brightness:alpha:)]) {
[self getHue:&h saturation:&s brightness:&b alpha:&a];
}
return @{kColoursHSBA_H:@(h),
kColoursHSBA_S:@(s),
kColoursHSBA_B:@(b),
kColoursHSBA_A:@(a)};
}
#pragma mark - Color from HSBA
+ (instancetype)colorFromHSBAArray:(NSArray *)hsbaArray
{
if (hsbaArray.count < 4) {
return [[self class] clearColor];
}
return [[self class] colorWithHue:[hsbaArray[0] doubleValue]
saturation:[hsbaArray[1] doubleValue]
brightness:[hsbaArray[2] doubleValue]
alpha:[hsbaArray[3] doubleValue]];
}
+ (instancetype)colorFromHSBADictionary:(NSDictionary *)hsbaDict
{
if (hsbaDict[kColoursHSBA_H] && hsbaDict[kColoursHSBA_S] && hsbaDict[kColoursHSBA_B] && hsbaDict[kColoursHSBA_A]) {
return [[self class] colorWithHue:[hsbaDict[kColoursHSBA_H] doubleValue]
saturation:[hsbaDict[kColoursHSBA_S] doubleValue]
brightness:[hsbaDict[kColoursHSBA_B] doubleValue]
alpha:[hsbaDict[kColoursHSBA_A] doubleValue]];
}
return [[self class] clearColor];
}
#pragma mark - LAB from Color
- (NSArray *)CIE_LabArray {
// Convert Color to XYZ format first
NSArray *rgba = [self rgbaArray];
CGFloat R = [rgba[0] floatValue];
CGFloat G = [rgba[1] floatValue];
CGFloat B = [rgba[2] floatValue];
// Create deltaR block
void (^deltaRGB)(CGFloat *R);
deltaRGB = ^(CGFloat *R) {
*R = (*R > 0.04045) ? pow((*R + 0.055)/1.055, 2.40) : (*R/12.92);
};
deltaRGB(&R);
deltaRGB(&G);
deltaRGB(&B);
CGFloat X = R*41.24 + G*35.76 + B*18.05;
CGFloat Y = R*21.26 + G*71.52 + B*7.22;
CGFloat Z = R*1.93 + G*11.92 + B*95.05;
// Convert XYZ to L*a*b*
X = X/95.047;
Y = Y/100.000;
Z = Z/108.883;
// Create deltaF block
void (^deltaF)(CGFloat *f);
deltaF = ^(CGFloat *f){
*f = (*f > pow((6.0/29.0), 3.0)) ? pow(*f, 1.0/3.0) : (1/3)*pow((29.0/6.0), 2.0) * *f + 4/29.0;
};
deltaF(&X);
deltaF(&Y);
deltaF(&Z);
NSNumber *L = @(116*Y - 16);
NSNumber *a = @(500 * (X - Y));
NSNumber *b = @(200 * (Y - Z));
return @[L,
a,
b,
rgba[3]];
}
- (NSDictionary *)CIE_LabDictionary {
NSArray *colors = [self CIE_LabArray];
return @{kColoursCIE_L:colors[0],
kColoursCIE_A:colors[1],
kColoursCIE_B:colors[2],
kColoursCIE_alpha:colors[3],};
}
#pragma mark - Color from LAB
+ (instancetype)colorFromCIE_LabArray:(NSArray *)colors {
if (!colors || colors.count < 4) {
return [[self class] clearColor];
}
// Convert LAB to XYZ
CGFloat L = [colors[0] floatValue];
CGFloat A = [colors[1] floatValue];
CGFloat B = [colors[2] floatValue];
CGFloat Y = (L + 16.0)/116.0;
CGFloat X = A/500 + Y;
CGFloat Z = Y - B/200;
void (^deltaXYZ)(CGFloat *);
deltaXYZ = ^(CGFloat *k){
*k = (pow(*k, 3.0) > 0.008856) ? pow(*k, 3.0) : (*k - 4/29.0)/7.787;
};
deltaXYZ(&X);
deltaXYZ(&Y);
deltaXYZ(&Z);
X = X*.95047;
Y = Y*1.00000;
Z = Z*1.08883;
// Convert XYZ to RGB
CGFloat R = X*3.2406 + Y*-1.5372 + Z*-0.4986;
CGFloat G = X*-0.9689 + Y*1.8758 + Z*0.0415;
CGFloat _B = X*0.0557 + Y*-0.2040 + Z*1.0570;
void (^deltaRGB)(CGFloat *);
deltaRGB = ^(CGFloat *k){
*k = (*k > 0.0031308) ? 1.055 * (pow(*k, (1/2.4))) - 0.055 : *k * 12.92;
};
deltaRGB(&R);
deltaRGB(&G);
deltaRGB(&_B);
// return Color
return [[self class] colorFromRGBAArray:@[@(R), @(G), @(_B), colors[3]]];
}
+ (instancetype)colorFromCIE_LabDictionary:(NSDictionary *)colors {
if (!colors) {
return [[self class] clearColor];
}
if (colors[kColoursCIE_L] && colors[kColoursCIE_A] && colors[kColoursCIE_B] && colors[kColoursCIE_alpha]) {
return [self colorFromCIE_LabArray:@[colors[kColoursCIE_L],
colors[kColoursCIE_A],
colors[kColoursCIE_B],
colors[kColoursCIE_alpha]]];
}
return [[self class] clearColor];
}
#pragma mark - Color to CMYK
- (NSArray *)cmykArray
{
// Convert RGB to CMY
NSArray *rgb = [self rgbaArray];
CGFloat C = 1 - [rgb[0] floatValue];
CGFloat M = 1 - [rgb[1] floatValue];
CGFloat Y = 1 - [rgb[2] floatValue];
// Find K
CGFloat K = MIN(1, MIN(C, MIN(Y, M)));
if (K == 1) {
C = 0;
M = 0;
Y = 0;
}
else {
void (^newCMYK)(CGFloat *);
newCMYK = ^(CGFloat *x){
*x = (*x - K)/(1 - K);
};
newCMYK(&C);
newCMYK(&M);
newCMYK(&Y);
}
return @[@(C),
@(M),
@(Y),
@(K)];
}
- (NSDictionary *)cmykDictionary
{
NSArray *colors = [self cmykArray];
return @{kColoursCMYK_C:colors[0],
kColoursCMYK_M:colors[1],
kColoursCMYK_Y:colors[2],
kColoursCMYK_K:colors[3]};
}
#pragma mark - CMYK to Color
+ (instancetype)colorFromCMYKArray:(NSArray *)cmyk
{
if (!cmyk || cmyk.count < 4) {
return [[self class] clearColor];
}
// Find CMY values
CGFloat C = [cmyk[0] floatValue];
CGFloat M = [cmyk[1] floatValue];
CGFloat Y = [cmyk[2] floatValue];
CGFloat K = [cmyk[3] floatValue];
void (^cmyTransform)(CGFloat *);
cmyTransform = ^(CGFloat *x){
*x = *x * (1 - K) + K;
};
cmyTransform(&C);
cmyTransform(&M);
cmyTransform(&Y);
// Translate CMY to RGB
CGFloat R = 1 - C;
CGFloat G = 1 - M;
CGFloat B = 1 - Y;
// return the Color
return [[self class] colorFromRGBAArray:@[@(R),
@(G),
@(B),
@(1)]];
}
+ (instancetype)colorFromCMYKDictionary:(NSDictionary *)cmyk
{
if (!cmyk) {
return [[self class] clearColor];
}
if (cmyk[kColoursCMYK_C] && cmyk[kColoursCMYK_M] && cmyk[kColoursCMYK_Y] && cmyk[kColoursCMYK_K]) {
return [[self class] colorFromCMYKArray:@[cmyk[kColoursCMYK_C],
cmyk[kColoursCMYK_M],
cmyk[kColoursCMYK_Y],
cmyk[kColoursCMYK_K]]];
}
return [[self class] clearColor];
}
#pragma mark - Color Components
- (NSDictionary *)colorComponents
{
NSMutableDictionary *components = [[self rgbaDictionary] mutableCopy];
[components addEntriesFromDictionary:[self hsbaDictionary]];
[components addEntriesFromDictionary:[self CIE_LabDictionary]];
return components;
}
- (CGFloat)red
{
return [[self rgbaArray][0] floatValue];
}
- (CGFloat)green
{
return [[self rgbaArray][1] floatValue];
}
- (CGFloat)blue
{
return [[self rgbaArray][2] floatValue];
}
- (CGFloat)hue
{
return [[self hsbaArray][0] floatValue];
}
- (CGFloat)saturation
{
return [[self hsbaArray][1] floatValue];
}
- (CGFloat)brightness
{
return [[self hsbaArray][2] floatValue];
}
- (CGFloat)alpha
{
return [[self rgbaArray][3] floatValue];
}
- (CGFloat)CIE_Lightness
{
return [[self CIE_LabArray][0] floatValue];
}
- (CGFloat)CIE_a
{
return [[self CIE_LabArray][1] floatValue];
}
- (CGFloat)CIE_b
{
return [[self CIE_LabArray][2] floatValue];
}
- (CGFloat)cyan {
return [[self cmykArray][0] floatValue];
}
- (CGFloat)magenta {
return [[self cmykArray][1] floatValue];
}
- (CGFloat)yellow {
return [[self cmykArray][2] floatValue];
}
- (CGFloat)keyBlack {
return [[self cmykArray][3] floatValue];
}
#pragma mark - Generate Color Scheme
- (NSArray *)colorSchemeOfType:(ColorScheme)type
{
NSArray *hsbArray = [self hsbaArray];
float hue = [hsbArray[0] floatValue] * 360;
float sat = [hsbArray[1] floatValue] * 100;
float bright = [hsbArray[2] floatValue] * 100;
float alpha = [hsbArray[3] floatValue];
switch (type) {
case ColorSchemeAnalagous:
return [[self class] analagousColorsFromHue:hue saturation:sat brightness:bright alpha:alpha];
case ColorSchemeMonochromatic:
return [[self class] monochromaticColorsFromHue:hue saturation:sat brightness:bright alpha:alpha];
case ColorSchemeTriad:
return [[self class] triadColorsFromHue:hue saturation:sat brightness:bright alpha:alpha];
case ColorSchemeComplementary:
return [[self class] complementaryColorsFromHue:hue saturation:sat brightness:bright alpha:alpha];
default:
return nil;
}
}
#pragma mark - Color Scheme Generation - Helper methods
+ (NSArray *)analagousColorsFromHue:(float)h saturation:(float)s brightness:(float)b alpha:(float)a
{
return @[[[self class] colorWithHue:[[self class] addDegrees:30 toDegree:h]/360 saturation:(s-5)/100 brightness:(b-10)/100 alpha:a],
[[self class] colorWithHue:[[self class] addDegrees:15 toDegree:h]/360 saturation:(s-5)/100 brightness:(b-5)/100 alpha:a],
[[self class] colorWithHue:[[self class] addDegrees:-15 toDegree:h]/360 saturation:(s-5)/100 brightness:(b-5)/100 alpha:a],
[[self class] colorWithHue:[[self class] addDegrees:-30 toDegree:h]/360 saturation:(s-5)/100 brightness:(b-10)/100 alpha:a]];
}
+ (NSArray *)monochromaticColorsFromHue:(float)h saturation:(float)s brightness:(float)b alpha:(float)a
{
return @[[[self class] colorWithHue:h/360 saturation:(s/2)/100 brightness:(b/3)/100 alpha:a],
[[self class] colorWithHue:h/360 saturation:s/100 brightness:(b/2)/100 alpha:a],
[[self class] colorWithHue:h/360 saturation:(s/3)/100 brightness:(2*b/3)/100 alpha:a],
[[self class] colorWithHue:h/360 saturation:s/100 brightness:(4*b/5)/100 alpha:a]];
}
+ (NSArray *)triadColorsFromHue:(float)h saturation:(float)s brightness:(float)b alpha:(float)a
{
return @[[[self class] colorWithHue:[[self class] addDegrees:120 toDegree:h]/360 saturation:(7*s/6)/100 brightness:(b-5)/100 alpha:a],
[[self class] colorWithHue:[[self class] addDegrees:120 toDegree:h]/360 saturation:s/100 brightness:b/100 alpha:a],
[[self class] colorWithHue:[[self class] addDegrees:240 toDegree:h]/360 saturation:s/100 brightness:b/100 alpha:a],
[[self class] colorWithHue:[[self class] addDegrees:240 toDegree:h]/360 saturation:(7*s/6)/100 brightness:(b-5)/100 alpha:a]];
}
+ (NSArray *)complementaryColorsFromHue:(float)h saturation:(float)s brightness:(float)b alpha:(float)a
{
return @[[[self class] colorWithHue:h/360 saturation:s/100 brightness:(4*b/5)/100 alpha:a],
[[self class] colorWithHue:h/360 saturation:(5*s/7)/100 brightness:b/100 alpha:a],
[[self class] colorWithHue:[[self class] addDegrees:180 toDegree:h]/360 saturation:s/100 brightness:b/100 alpha:a],
[[self class] colorWithHue:[[self class] addDegrees:180 toDegree:h]/360 saturation:(5*s/7)/100 brightness:b/100 alpha:a]];
}
#pragma mark - Contrasting Color
- (instancetype)blackOrWhiteContrastingColor
{
NSArray *rgbaArray = [self rgbaArray];
double a = 1 - ((0.299 * [rgbaArray[0] doubleValue]) + (0.587 * [rgbaArray[1] doubleValue]) + (0.114 * [rgbaArray[2] doubleValue]));
return a < 0.5 ? [[self class] blackColor] : [[self class] whiteColor];
}
#pragma mark - Complementary Color
- (instancetype)complementaryColor
{
NSMutableDictionary *hsba = [[self hsbaDictionary] mutableCopy];
float newH = [[self class] addDegrees:180.0f toDegree:([hsba[kColoursHSBA_H] floatValue]*360)];
[hsba setObject:@(newH) forKey:kColoursHSBA_H];
return [[self class] colorFromHSBADictionary:hsba];
}
#pragma mark - Distance between Colors
- (CGFloat)distanceFromColor:(id)color
{
// Defaults to CIE94
return [self distanceFromColor:color type:ColorDistanceCIE94];
}
- (CGFloat)distanceFromColor:(id)color type:(ColorDistance)distanceType {
/**
*
* Detecting a difference in two colors is not as trivial as it sounds.
* One's first instinct is to go for a difference in RGB values, leaving
* you with a sum of the differences of each point. It looks great! Until
* you actually start comparing colors. Why do these two reds have a different
* distance than these two blues *in real life* vs computationally?
* Human visual perception is next in the line of things between a color
* and your brain. Some colors are just perceived to have larger variants inside
* of their respective areas than others, so we need a way to model this
* human variable to colors. Enter CIELAB. This color formulation is supposed to be
* this model. So now we need to standardize a unit of distance between any two
* colors that works independent of how humans visually perceive that distance.
* Enter CIE76,94,2000. These are methods that use user-tested data and other
* mathematically and statistically significant correlations to output this info.
* You can read the wiki articles below to get a better understanding historically
* of how we moved to newer and better color distance formulas, and what
* their respective pros/cons are.
*
* References:
*
* http://en.wikipedia.org/wiki/Color_difference
* http://en.wikipedia.org/wiki/Just_noticeable_difference
* http://en.wikipedia.org/wiki/CIELAB
*
*/
// Check if it's a color
if (![color isKindOfClass:[self class]]) {
// NSLog(@"Not a %@ object.", NSStringFromClass([self class]));
return MAXFLOAT;
}
// Set Up Common Variables
NSArray *lab1 = [self CIE_LabArray];
NSArray *lab2 = [color CIE_LabArray];
CGFloat L1 = [lab1[0] floatValue];
CGFloat A1 = [lab1[1] floatValue];
CGFloat B1 = [lab1[2] floatValue];
CGFloat L2 = [lab2[0] floatValue];
CGFloat A2 = [lab2[1] floatValue];
CGFloat B2 = [lab2[2] floatValue];
// CIE76 first
if (distanceType == ColorDistanceCIE76) {
CGFloat distance = sqrtf(pow((L1-L2), 2) + pow((A1-A2), 2) + pow((B1-B2), 2));
return distance;
}
// More Common Variables
CGFloat kL = 1;
CGFloat kC = 1;
CGFloat kH = 1;
CGFloat k1 = 0.045;
CGFloat k2 = 0.015;
CGFloat deltaL = L1 - L2;
CGFloat C1 = sqrt((A1*A1) + (B1*B1));
CGFloat C2 = sqrt((A2*A2) + (B2*B2));
CGFloat deltaC = C1 - C2;
CGFloat deltaH = sqrt(pow((A1-A2), 2.0) + pow((B1-B2), 2.0) - pow(deltaC, 2.0));
CGFloat sL = 1;
CGFloat sC = 1 + k1*(sqrt((A1*A1) + (B1*B1)));
CGFloat sH = 1 + k2*(sqrt((A1*A1) + (B1*B1)));
// CIE94
if (distanceType == ColorDistanceCIE94) {
return sqrt(pow((deltaL/(kL*sL)), 2.0) + pow((deltaC/(kC*sC)), 2.0) + pow((deltaH/(kH*sH)), 2.0));
}
// CIE2000
// More variables
CGFloat deltaLPrime = L2 - L1;
CGFloat meanL = (L1 + L2)/2;
CGFloat meanC = (C1 + C2)/2;
CGFloat aPrime1 = A1 + A1/2*(1 - sqrt(pow(meanC, 7.0)/(pow(meanC, 7.0) + pow(25.0, 7.0))));
CGFloat aPrime2 = A2 + A2/2*(1 - sqrt(pow(meanC, 7.0)/(pow(meanC, 7.0) + pow(25.0, 7.0))));
CGFloat cPrime1 = sqrt((aPrime1*aPrime1) + (B1*B1));
CGFloat cPrime2 = sqrt((aPrime2*aPrime2) + (B2*B2));
CGFloat cMeanPrime = (cPrime1 + cPrime2)/2;
CGFloat deltaCPrime = cPrime1 - cPrime2;
CGFloat hPrime1 = atan2(B1, aPrime1);
CGFloat hPrime2 = atan2(B2, aPrime2);
hPrime1 = fmodf(hPrime1, [self radiansFromDegree:360]);
hPrime2 = fmodf(hPrime2, [self radiansFromDegree:360]);
CGFloat deltahPrime = 0;
if (fabsf(hPrime1 - hPrime2) <= [self radiansFromDegree:180]) {
deltahPrime = hPrime2 - hPrime1;
}
else {
deltahPrime = (hPrime2 <= hPrime1) ? hPrime2 - hPrime1 + [self radiansFromDegree:360] : hPrime2 - hPrime1 - [self radiansFromDegree:360];
}
CGFloat deltaHPrime = 2 * sqrt(cPrime1*cPrime2) * sin(deltahPrime/2);
CGFloat meanHPrime = (fabsf(hPrime1 - hPrime2) <= [self radiansFromDegree:180]) ? (hPrime1 + hPrime2)/2 : (hPrime1 + hPrime2 + [self radiansFromDegree:360])/2;
CGFloat T = 1 - 0.17*cos(meanHPrime - [self radiansFromDegree:30]) + 0.24*cos(2*meanHPrime)+0.32*cos(3*meanHPrime + [self radiansFromDegree:6]) - 0.20*cos(4*meanHPrime - [self radiansFromDegree:63]);
sL = 1 + (0.015 * pow((meanL - 50), 2))/sqrt(20 + pow((meanL - 50), 2));
sC = 1 + 0.045*cMeanPrime;
sH = 1 + 0.015*cMeanPrime*T;
CGFloat Rt = -2 * sqrt(pow(cMeanPrime, 7)/(pow(cMeanPrime, 7) + pow(25.0, 7))) * sin([self radiansFromDegree:60]* exp(-1 * pow((meanHPrime - [self radiansFromDegree:275])/[self radiansFromDegree:25], 2)));
// Finally return CIE2000 distance
return sqrt(pow((deltaLPrime/(kL*sL)), 2) + pow((deltaCPrime/(kC*sC)), 2) + pow((deltaHPrime/(kH*sH)), 2) + Rt*(deltaC/(kC*sC))*(deltaHPrime/(kH*sH)));
}
#pragma mark - System Colors
+ (instancetype)infoBlueColor
{
return [[self class] colorWithR:47 G:112 B:225 A:1.0];
}
+ (instancetype)successColor
{
return [[self class] colorWithR:83 G:215 B:106 A:1.0];
}
+ (instancetype)warningColor
{
return [[self class] colorWithR:221 G:170 B:59 A:1.0];
}
+ (instancetype)dangerColor
{
return [[self class] colorWithR:229 G:0 B:15 A:1.0];
}
#pragma mark - Whites
+ (instancetype)antiqueWhiteColor
{
return [[self class] colorWithR:250 G:235 B:215 A:1.0];
}
+ (instancetype)oldLaceColor
{
return [[self class] colorWithR:253 G:245 B:230 A:1.0];
}
+ (instancetype)ivoryColor
{
return [[self class] colorWithR:255 G:255 B:240 A:1.0];
}
+ (instancetype)seashellColor
{
return [[self class] colorWithR:255 G:245 B:238 A:1.0];
}
+ (instancetype)ghostWhiteColor
{
return [[self class] colorWithR:248 G:248 B:255 A:1.0];
}
+ (instancetype)snowColor
{
return [[self class] colorWithR:255 G:250 B:250 A:1.0];
}
+ (instancetype)linenColor
{
return [[self class] colorWithR:250 G:240 B:230 A:1.0];
}
#pragma mark - Grays
+ (instancetype)black25PercentColor
{
return [[self class] colorWithWhite:0.25 alpha:1.0];
}
+ (instancetype)black50PercentColor
{
return [[self class] colorWithWhite:0.5 alpha:1.0];
}
+ (instancetype)black75PercentColor
{
return [[self class] colorWithWhite:0.75 alpha:1.0];
}
+ (instancetype)warmGrayColor
{
return [[self class] colorWithR:133 G:117 B:112 A:1.0];
}
+ (instancetype)coolGrayColor
{
return [[self class] colorWithR:118 G:122 B:133 A:1.0];
}
+ (instancetype)charcoalColor
{
return [[self class] colorWithR:34 G:34 B:34 A:1.0];
}
#pragma mark - Blues
+ (instancetype)tealColor
{
return [[self class] colorWithR:28 G:160 B:170 A:1.0];
}
+ (instancetype)steelBlueColor
{
return [[self class] colorWithR:103 G:153 B:170 A:1.0];
}
+ (instancetype)robinEggColor
{
return [[self class] colorWithR:141 G:218 B:247 A:1.0];
}
+ (instancetype)pastelBlueColor
{
return [[self class] colorWithR:99 G:161 B:247 A:1.0];
}
+ (instancetype)turquoiseColor
{
return [[self class] colorWithR:112 G:219 B:219 A:1.0];
}
+ (instancetype)skyBlueColor
{
return [[self class] colorWithR:0 G:178 B:238 A:1.0];
}
+ (instancetype)indigoColor
{
return [[self class] colorWithR:13 G:79 B:139 A:1.0];
}
+ (instancetype)denimColor
{
return [[self class] colorWithR:67 G:114 B:170 A:1.0];
}
+ (instancetype)blueberryColor
{
return [[self class] colorWithR:89 G:113 B:173 A:1.0];
}
+ (instancetype)cornflowerColor
{
return [[self class] colorWithR:100 G:149 B:237 A:1.0];
}
+ (instancetype)babyBlueColor
{
return [[self class] colorWithR:190 G:220 B:230 A:1.0];
}
+ (instancetype)midnightBlueColor
{
return [[self class] colorWithR:13 G:26 B:35 A:1.0];
}
+ (instancetype)fadedBlueColor
{
return [[self class] colorWithR:23 G:137 B:155 A:1.0];
}
+ (instancetype)icebergColor
{
return [[self class] colorWithR:200 G:213 B:219 A:1.0];
}
+ (instancetype)waveColor
{
return [[self class] colorWithR:102 G:169 B:251 A:1.0];
}
#pragma mark - Greens
+ (instancetype)emeraldColor
{
return [[self class] colorWithR:1 G:152 B:117 A:1.0];
}
+ (instancetype)grassColor
{
return [[self class] colorWithR:99 G:214 B:74 A:1.0];
}
+ (instancetype)pastelGreenColor
{
return [[self class] colorWithR:126 G:242 B:124 A:1.0];
}
+ (instancetype)seafoamColor
{
return [[self class] colorWithR:77 G:226 B:140 A:1.0];
}
+ (instancetype)paleGreenColor
{
return [[self class] colorWithR:176 G:226 B:172 A:1.0];
}
+ (instancetype)cactusGreenColor
{
return [[self class] colorWithR:99 G:111 B:87 A:1.0];
}
+ (instancetype)chartreuseColor
{
return [[self class] colorWithR:69 G:139 B:0 A:1.0];
}
+ (instancetype)hollyGreenColor
{
return [[self class] colorWithR:32 G:87 B:14 A:1.0];
}
+ (instancetype)oliveColor
{
return [[self class] colorWithR:91 G:114 B:34 A:1.0];
}
+ (instancetype)oliveDrabColor
{
return [[self class] colorWithR:107 G:142 B:35 A:1.0];
}
+ (instancetype)moneyGreenColor
{
return [[self class] colorWithR:134 G:198 B:124 A:1.0];
}
+ (instancetype)honeydewColor
{
return [[self class] colorWithR:216 G:255 B:231 A:1.0];
}
+ (instancetype)limeColor
{
return [[self class] colorWithR:56 G:237 B:56 A:1.0];
}
+ (instancetype)cardTableColor
{
return [[self class] colorWithR:87 G:121 B:107 A:1.0];
}
#pragma mark - Reds
+ (instancetype)salmonColor
{
return [[self class] colorWithR:233 G:87 B:95 A:1.0];
}
+ (instancetype)brickRedColor
{
return [[self class] colorWithR:151 G:27 B:16 A:1.0];
}
+ (instancetype)easterPinkColor
{
return [[self class] colorWithR:241 G:167 B:162 A:1.0];
}
+ (instancetype)grapefruitColor
{
return [[self class] colorWithR:228 G:31 B:54 A:1.0];
}
+ (instancetype)pinkColor
{
return [[self class] colorWithR:255 G:95 B:154 A:1.0];
}
+ (instancetype)indianRedColor
{
return [[self class] colorWithR:205 G:92 B:92 A:1.0];
}
+ (instancetype)strawberryColor
{
return [[self class] colorWithR:190 G:38 B:37 A:1.0];
}
+ (instancetype)coralColor
{
return [[self class] colorWithR:240 G:128 B:128 A:1.0];
}
+ (instancetype)maroonColor
{
return [[self class] colorWithR:80 G:4 B:28 A:1.0];
}
+ (instancetype)watermelonColor
{
return [[self class] colorWithR:242 G:71 B:63 A:1.0];
}
+ (instancetype)tomatoColor
{
return [[self class] colorWithR:255 G:99 B:71 A:1.0];
}
+ (instancetype)pinkLipstickColor
{
return [[self class] colorWithR:255 G:105 B:180 A:1.0];
}
+ (instancetype)paleRoseColor
{
return [[self class] colorWithR:255 G:228 B:225 A:1.0];
}
+ (instancetype)crimsonColor
{
return [[self class] colorWithR:187 G:18 B:36 A:1.0];
}
#pragma mark - Purples
+ (instancetype)eggplantColor
{
return [[self class] colorWithR:105 G:5 B:98 A:1.0];
}
+ (instancetype)pastelPurpleColor
{
return [[self class] colorWithR:207 G:100 B:235 A:1.0];
}
+ (instancetype)palePurpleColor
{
return [[self class] colorWithR:229 G:180 B:235 A:1.0];
}
+ (instancetype)coolPurpleColor
{
return [[self class] colorWithR:140 G:93 B:228 A:1.0];
}
+ (instancetype)violetColor
{
return [[self class] colorWithR:191 G:95 B:255 A:1.0];
}
+ (instancetype)plumColor
{
return [[self class] colorWithR:139 G:102 B:139 A:1.0];
}
+ (instancetype)lavenderColor
{
return [[self class] colorWithR:204 G:153 B:204 A:1.0];
}
+ (instancetype)raspberryColor
{
return [[self class] colorWithR:135 G:38 B:87 A:1.0];
}
+ (instancetype)fuschiaColor
{
return [[self class] colorWithR:255 G:20 B:147 A:1.0];
}
+ (instancetype)grapeColor
{
return [[self class] colorWithR:54 G:11 B:88 A:1.0];
}
+ (instancetype)periwinkleColor
{
return [[self class] colorWithR:135 G:159 B:237 A:1.0];
}
+ (instancetype)orchidColor
{
return [[self class] colorWithR:218 G:112 B:214 A:1.0];
}
#pragma mark - Yellows
+ (instancetype)goldenrodColor
{
return [[self class] colorWithR:215 G:170 B:51 A:1.0];
}
+ (instancetype)yellowGreenColor
{
return [[self class] colorWithR:192 G:242 B:39 A:1.0];
}
+ (instancetype)bananaColor
{
return [[self class] colorWithR:229 G:227 B:58 A:1.0];
}
+ (instancetype)mustardColor
{
return [[self class] colorWithR:205 G:171 B:45 A:1.0];
}
+ (instancetype)buttermilkColor
{
return [[self class] colorWithR:254 G:241 B:181 A:1.0];
}
+ (instancetype)goldColor
{
return [[self class] colorWithR:139 G:117 B:18 A:1.0];
}
+ (instancetype)creamColor
{
return [[self class] colorWithR:240 G:226 B:187 A:1.0];
}
+ (instancetype)lightCreamColor
{
return [[self class] colorWithR:240 G:238 B:215 A:1.0];
}
+ (instancetype)wheatColor
{
return [[self class] colorWithR:240 G:238 B:215 A:1.0];
}
+ (instancetype)beigeColor
{
return [[self class] colorWithR:245 G:245 B:220 A:1.0];
}
#pragma mark - Oranges
+ (instancetype)peachColor
{
return [[self class] colorWithR:242 G:187 B:97 A:1.0];
}
+ (instancetype)burntOrangeColor
{
return [[self class] colorWithR:184 G:102 B:37 A:1.0];
}
+ (instancetype)pastelOrangeColor
{
return [[self class] colorWithR:248 G:197 B:143 A:1.0];
}
+ (instancetype)cantaloupeColor
{
return [[self class] colorWithR:250 G:154 B:79 A:1.0];
}
+ (instancetype)carrotColor
{
return [[self class] colorWithR:237 G:145 B:33 A:1.0];
}
+ (instancetype)mandarinColor
{
return [[self class] colorWithR:247 G:145 B:55 A:1.0];
}
#pragma mark - Browns
+ (instancetype)chiliPowderColor
{
return [[self class] colorWithR:199 G:63 B:23 A:1.0];
}
+ (instancetype)burntSiennaColor
{
return [[self class] colorWithR:138 G:54 B:15 A:1.0];
}
+ (instancetype)chocolateColor
{
return [[self class] colorWithR:94 G:38 B:5 A:1.0];
}
+ (instancetype)coffeeColor
{
return [[self class] colorWithR:141 G:60 B:15 A:1.0];
}
+ (instancetype)cinnamonColor
{
return [[self class] colorWithR:123 G:63 B:9 A:1.0];
}
+ (instancetype)almondColor
{
return [[self class] colorWithR:196 G:142 B:72 A:1.0];
}
+ (instancetype)eggshellColor
{
return [[self class] colorWithR:252 G:230 B:201 A:1.0];
}
+ (instancetype)sandColor
{
return [[self class] colorWithR:222 G:182 B:151 A:1.0];
}
+ (instancetype)mudColor
{
return [[self class] colorWithR:70 G:45 B:29 A:1.0];
}
+ (instancetype)siennaColor
{
return [[self class] colorWithR:160 G:82 B:45 A:1.0];
}
+ (instancetype)dustColor
{
return [[self class] colorWithR:236 G:214 B:197 A:1.0];
}
#pragma mark - Private
#pragma mark - RGBA Helper method
+ (instancetype)colorWithR:(CGFloat)red G:(CGFloat)green B:(CGFloat)blue A:(CGFloat)alpha
{
return [[self class] colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha];
}
#pragma mark - Degrees Helper method for Color Schemes
+ (float)addDegrees:(float)addDeg toDegree:(float)staticDeg
{
staticDeg += addDeg;
if (staticDeg > 360) {
float offset = staticDeg - 360;
return offset;
}
else if (staticDeg < 0) {
return -1 * staticDeg;
}
else {
return staticDeg;
}
}
- (CGFloat)radiansFromDegree:(CGFloat)degree {
return degree * M_PI/180;
}
#pragma mark - Swizzle
#pragma mark - On Load - Flip methods
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
SEL rgbaSelector = @selector(getRed:green:blue:alpha:);
SEL swizzledRGBASelector = @selector(colours_getRed:green:blue:alpha:);
SEL hsbaSelector = @selector(getHue:saturation:brightness:alpha:);
SEL swizzledHSBASelector = @selector(colours_getHue:saturation:brightness:alpha:);
Method rgbaMethod = class_getInstanceMethod(class, rgbaSelector);
Method swizzledRGBAMethod = class_getInstanceMethod(class, swizzledRGBASelector);
Method hsbaMethod = class_getInstanceMethod(class, hsbaSelector);
Method swizzledHSBAMethod = class_getInstanceMethod(class, swizzledHSBASelector);
// Attempt adding the methods
BOOL didAddRGBAMethod =
class_addMethod(class,
rgbaSelector,
method_getImplementation(swizzledRGBAMethod),
method_getTypeEncoding(swizzledRGBAMethod));
BOOL didAddHSBAMethod =
class_addMethod(class,
hsbaSelector,
method_getImplementation(swizzledHSBAMethod),
method_getTypeEncoding(swizzledHSBAMethod));
// Replace methods
if (didAddRGBAMethod) {
class_replaceMethod(class,
swizzledRGBASelector,
method_getImplementation(swizzledRGBAMethod),
method_getTypeEncoding(swizzledRGBAMethod));
} else {
method_exchangeImplementations(rgbaMethod, swizzledRGBAMethod);
}
if (didAddHSBAMethod) {
class_replaceMethod(class,
swizzledHSBASelector,
method_getImplementation(swizzledHSBAMethod),
method_getTypeEncoding(swizzledHSBAMethod));
} else {
method_exchangeImplementations(hsbaMethod, swizzledHSBAMethod);
}
});
}
#pragma mark - Swizzled Methods
- (BOOL)colours_getRed:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue alpha:(CGFloat *)alpha
{
if (CGColorGetNumberOfComponents(self.CGColor) == 4) {
return [self colours_getRed:red green:green blue:blue alpha:alpha];
}
else if (CGColorGetNumberOfComponents(self.CGColor) == 2) {
CGFloat white;
CGFloat m_alpha;
if ([self getWhite:&white alpha:&m_alpha]) {
*red = white * 1.0;
*green = white * 1.0;
*blue = white * 1.0;
*alpha = m_alpha;
return YES;
}
}
return NO;
}
- (BOOL)colours_getHue:(CGFloat *)hue saturation:(CGFloat *)saturation brightness:(CGFloat *)brightness alpha:(CGFloat *)alpha
{
if (CGColorGetNumberOfComponents(self.CGColor) == 4) {
return [self colours_getHue:hue saturation:saturation brightness:brightness alpha:alpha];
}
else if (CGColorGetNumberOfComponents(self.CGColor) == 2) {
CGFloat white = 0;
CGFloat a = 0;
if ([self getWhite:&white alpha:&a]) {
*hue = 0;
*saturation = 0;
*brightness = white * 1.0;
*alpha = a * 1.0;
return YES;
}
}
return NO;
}
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExample/DateToolsExample-Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleDisplayName
${PRODUCT_NAME}
CFBundleExecutable
${EXECUTABLE_NAME}
CFBundleIdentifier
com.mattyork.${PRODUCT_NAME:rfc1034identifier}
CFBundleInfoDictionaryVersion
6.0
CFBundleName
${PRODUCT_NAME}
CFBundlePackageType
APPL
CFBundleShortVersionString
1.0
CFBundleSignature
????
CFBundleVersion
1.0
LSRequiresIPhoneOS
UIRequiredDeviceCapabilities
armv7
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExample/DateToolsExample-Prefix.pch
================================================
//
// Prefix header
//
// The contents of this file are implicitly included at the beginning of every source file.
//
#import
#ifndef __IPHONE_5_0
#warning "This project uses features only available in iOS SDK 5.0 and later."
#endif
#ifdef __OBJC__
#import
#import
#endif
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExample/DateToolsViewController.h
================================================
//
// DateToolsViewController.h
// DateToolsExample
//
// Created by Matthew York on 3/22/14.
//
//
#import
@interface DateToolsViewController : UIViewController
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExample/DateToolsViewController.m
================================================
//
// DateToolsViewController.m
// DateToolsExample
//
// Created by Matthew York on 3/22/14.
//
//
#import "DateToolsViewController.h"
#import "NSDate+DateTools.h"
#import "Colours.h"
@interface DateToolsViewController ()
@property (weak, nonatomic) IBOutlet UIScrollView *MasterScrollView;
@property NSTimer *updateTimer;
@property NSDate *selectedDate;
@property NSDateFormatter *formatter;
//Time Ago View
@property (strong, nonatomic) IBOutlet UIView *TimeAgoView;
@property (weak, nonatomic) IBOutlet UILabel *TimeAgoLabel;
@property (weak, nonatomic) IBOutlet UISlider *TimeAgoSlider;
@property (weak, nonatomic) IBOutlet UILabel *SecondsLabel;
@property (weak, nonatomic) IBOutlet UILabel *MinutesLabel;
@property (weak, nonatomic) IBOutlet UILabel *HoursLabel;
@property (weak, nonatomic) IBOutlet UILabel *DaysLabel;
@property (weak, nonatomic) IBOutlet UILabel *WeeksLabel;
@property (weak, nonatomic) IBOutlet UILabel *MonthsLabel;
@property (weak, nonatomic) IBOutlet UILabel *YearsLabel;
@end
@implementation DateToolsViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
self.title = @"NSDate+DateTools";
self.tabBarItem.title = @"NSDate+DateTools";
self.tabBarItem.image = [UIImage imageNamed:@"Calendar"];
self.tabBarItem.selectedImage = [UIImage imageNamed:@"Calendar_filled"];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//Setup date formatter
self.formatter = [[NSDateFormatter alloc] init];
[self.formatter setDateFormat:@"HHmm MMMM d yyyy"];
//Set initial date
self.selectedDate = [self.formatter dateFromString:@"0000 November 5 1605"];
self.TimeAgoSlider.value = [self.selectedDate timeIntervalSinceNow];
//Set up timer for updating UI
self.updateTimer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(updateTimeAgoLabels) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.updateTimer forMode:NSRunLoopCommonModes];
[self setupViews];
[self updateTimeAgoLabels];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)setupViews{
[self.MasterScrollView addSubview:self.TimeAgoView];
[self.MasterScrollView setContentSize:self.TimeAgoView.frame.size];
self.SecondsLabel.textColor = [UIColor tealColor];
self.MinutesLabel.textColor = [UIColor moneyGreenColor];
self.HoursLabel.textColor = [UIColor salmonColor];
self.DaysLabel.textColor = [UIColor violetColor];
self.WeeksLabel.textColor = [UIColor tealColor];
self.MonthsLabel.textColor = [UIColor waveColor];
self.YearsLabel.textColor = [UIColor bananaColor];
}
#pragma mark - Update
-(void)updateTimeAgoLabels{
//Account for now
if (self.TimeAgoSlider.value == 0) {
self.selectedDate = [NSDate date];
}
//Set time ago label
self.TimeAgoLabel.text = [self.formatter stringFromDate:self.selectedDate];
//Set date component labels
self.SecondsLabel.text = [NSString stringWithFormat:@"%.0f", self.selectedDate.secondsAgo];
self.MinutesLabel.text = [NSString stringWithFormat:@"%.0f", self.selectedDate.minutesAgo];
self.HoursLabel.text = [NSString stringWithFormat:@"%.0f", self.selectedDate.hoursAgo];
self.DaysLabel.text = [NSString stringWithFormat:@"%ld", (long)self.selectedDate.daysAgo];
self.WeeksLabel.text = [NSString stringWithFormat:@"%ld", (long)self.selectedDate.weeksAgo];
self.MonthsLabel.text = [NSString stringWithFormat:@"%ld", (long)self.selectedDate.monthsAgo];
self.YearsLabel.text = [NSString stringWithFormat:@"%ld", (long)self.selectedDate.yearsAgo];
}
- (IBAction)sliderValueDidChange:(UISlider *)sender {
self.selectedDate = [NSDate dateWithTimeIntervalSinceNow:sender.value];
//Update UI
[self updateTimeAgoLabels];
}
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExample/DateToolsViewController.xib
================================================
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExample/ExampleNavigationController.h
================================================
//
// ExampleNavigationController.h
// DateToolsExample
//
// Created by Matthew York on 3/22/14.
//
//
#import
@interface ExampleNavigationController : UINavigationController
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExample/ExampleNavigationController.m
================================================
//
// ExampleNavigationController.m
// DateToolsExample
//
// Created by Matthew York on 3/22/14.
//
//
#import "ExampleNavigationController.h"
#import "Colours.h"
@interface ExampleNavigationController ()
@end
@implementation ExampleNavigationController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
if ([self.navigationBar respondsToSelector:@selector(setTranslucent:)]) {
self.navigationBar.translucent = NO;
self.navigationBar.barTintColor = [UIColor infoBlueColor];
self.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName: [UIColor whiteColor], NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue-Light" size:21.0]};
[[UIBarButtonItem appearance] setTintColor:[UIColor whiteColor]];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(UIStatusBarStyle)preferredStatusBarStyle{
return UIStatusBarStyleLightContent;
}
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExample/Images.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExample/Images.xcassets/LaunchImage.launchimage/Contents.json
================================================
{
"images" : [
{
"orientation" : "portrait",
"idiom" : "iphone",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"subtype" : "retina4",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExample/TimePeriodsViewController.h
================================================
//
// TimePeriodsViewController.h
// DateToolsExample
//
// Created by Matthew York on 3/22/14.
//
//
#import
@interface TimePeriodsViewController : UIViewController
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExample/TimePeriodsViewController.m
================================================
//
// TimePeriodsViewController.m
// DateToolsExample
//
// Created by Matthew York on 3/22/14.
//
//
#import "TimePeriodsViewController.h"
#import "DTTimePeriod.h"
@interface TimePeriodsViewController ()
@property (weak, nonatomic) IBOutlet UIView *AView;
@property (weak, nonatomic) IBOutlet UIView *BView;
@property (weak, nonatomic) IBOutlet UIView *CView;
//Relationships
@property (weak, nonatomic) IBOutlet UILabel *ABRelationship;
@property (weak, nonatomic) IBOutlet UILabel *ACRelationship;
@property (weak, nonatomic) IBOutlet UILabel *BARelationship;
@property (weak, nonatomic) IBOutlet UILabel *BCRelationship;
@property (weak, nonatomic) IBOutlet UILabel *CARelationship;
@property (weak, nonatomic) IBOutlet UILabel *CBRelationship;
@end
@implementation TimePeriodsViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
// Custom initialization
self.title = @"Time Periods";
self.tabBarItem.title = @"Time Periods";
self.tabBarItem.image = [UIImage imageNamed:@"Recents"];
self.tabBarItem.selectedImage = [UIImage imageNamed:@"Recents_filled"];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
//Setup pan recognizers
UIPanGestureRecognizer *recognizerA = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
[recognizerA setMaximumNumberOfTouches:1];
[recognizerA setMinimumNumberOfTouches:1];
[self.AView addGestureRecognizer:recognizerA];
UIPanGestureRecognizer *recognizerB = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
[recognizerB setMaximumNumberOfTouches:1];
[recognizerB setMinimumNumberOfTouches:1];
[self.BView addGestureRecognizer:recognizerB];
UIPanGestureRecognizer *recognizerC = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
[recognizerC setMaximumNumberOfTouches:1];
[recognizerC setMinimumNumberOfTouches:1];
[self.CView addGestureRecognizer:recognizerC];
//Set initial relationships
[self updateRelationships];
//Set up info button for alert
[self.navigationItem setRightBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:@"Info" style:UIBarButtonItemStyleBordered target:self action:@selector(showInfo)]];
}
-(void)showInfo{
[[[UIAlertView alloc] initWithTitle:@"Legend" message:@"Ins. - Inside\nEnc. - Enclosing\n\nFor more information on the various DTTimePeriod relationships, please see the DateTools README on GitHub." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil] show];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Pan Recognizers
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {
CGPoint translation = [recognizer translationInView:self.view];
recognizer.view.frame = CGRectMake(MAX(10, MIN((self.view.frame.size.width-recognizer.view.frame.size.width - 10), recognizer.view.frame.origin.x + translation.x)), recognizer.view.frame.origin.y, recognizer.view.frame.size.width, recognizer.view.frame.size.height);
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
[self updateRelationships];
}
#pragma mark - Update
-(void)updateRelationships{
NSInteger AOffset = -300 + (self.AView.frame.origin.x - 10);
NSInteger BOffset = -300 + (self.BView.frame.origin.x - 10);
NSInteger COffset = -300 + (self.CView.frame.origin.x - 10);
//AOffset *= 4;
//BOffset *= 4;
//COffset *= 4;
DTTimePeriod *aPeriod = [DTTimePeriod timePeriodWithStartDate:[NSDate dateWithTimeIntervalSince1970:AOffset] endDate:[NSDate dateWithTimeIntervalSince1970:AOffset+self.AView.frame.size.width]];
DTTimePeriod *bPeriod = [DTTimePeriod timePeriodWithStartDate:[NSDate dateWithTimeIntervalSince1970:BOffset] endDate:[NSDate dateWithTimeIntervalSince1970:BOffset+self.BView.frame.size.width]];
DTTimePeriod *cPeriod = [DTTimePeriod timePeriodWithStartDate:[NSDate dateWithTimeIntervalSince1970:COffset] endDate:[NSDate dateWithTimeIntervalSince1970:COffset+self.CView.frame.size.width]];
//Set A relationships
self.ABRelationship.text = [self stringForRelation:[aPeriod relationToPeriod:bPeriod] forPeriodName:@"B"];
self.ACRelationship.text = [self stringForRelation:[aPeriod relationToPeriod:cPeriod] forPeriodName:@"C"];
//Set B relationships
self.BARelationship.text = [self stringForRelation:[bPeriod relationToPeriod:aPeriod] forPeriodName:@"A"];
self.BCRelationship.text = [self stringForRelation:[bPeriod relationToPeriod:cPeriod] forPeriodName:@"C"];
//Set C relationships
self.CARelationship.text = [self stringForRelation:[cPeriod relationToPeriod:aPeriod] forPeriodName:@"A"];
self.CBRelationship.text = [self stringForRelation:[cPeriod relationToPeriod:bPeriod] forPeriodName:@"B"];
}
-(NSString *)stringForRelation:(DTTimePeriodRelation)relation forPeriodName:(NSString *)periodName{
switch (relation) {
case DTTimePeriodRelationAfter:
return [NSString stringWithFormat:@"After %@", periodName];
case DTTimePeriodRelationBefore:
return [NSString stringWithFormat:@"Before %@", periodName];
case DTTimePeriodRelationEnclosing:
return [NSString stringWithFormat:@"Enclosing %@", periodName];
case DTTimePeriodRelationEnclosingEndTouching:
return [NSString stringWithFormat:@"Enc. End Touch %@", periodName];
case DTTimePeriodRelationEnclosingStartTouching:
return [NSString stringWithFormat:@"Enc. Start Touch %@", periodName];
case DTTimePeriodRelationEndInside:
return [NSString stringWithFormat:@"Ends Inside %@", periodName];
case DTTimePeriodRelationEndTouching:
return [NSString stringWithFormat:@"Ends Touching %@", periodName];
case DTTimePeriodRelationExactMatch:
return [NSString stringWithFormat:@"Exact Match %@", periodName];
case DTTimePeriodRelationInside:
return [NSString stringWithFormat:@"Inside %@", periodName];
case DTTimePeriodRelationInsideEndTouching:
return [NSString stringWithFormat:@"Ins. End Touch %@", periodName];
case DTTimePeriodRelationInsideStartTouching:
return [NSString stringWithFormat:@"Ins. Start Touch %@", periodName];
case DTTimePeriodRelationNone:
return [NSString stringWithFormat:@"No Relation to %@", periodName];
case DTTimePeriodRelationStartInside:
return [NSString stringWithFormat:@"Starts Inside %@", periodName];
case DTTimePeriodRelationStartTouching:
return [NSString stringWithFormat:@"Starts Touching %@", periodName];
default:
break;
}
typedef NS_ENUM(NSUInteger, DTTimePeriodRelation){
DTTimePeriodRelationAfter,
DTTimePeriodRelationStartTouching,
DTTimePeriodRelationStartInside,
DTTimePeriodRelationInsideStartTouching,
DTTimePeriodRelationEnclosingStartTouching,
DTTimePeriodRelationEnclosing,
DTTimePeriodRelationEnclosingEndTouching,
DTTimePeriodRelationExactMatch,
DTTimePeriodRelationInside,
DTTimePeriodRelationInsideEndTouching,
DTTimePeriodRelationEndInside,
DTTimePeriodRelationEndTouching,
DTTimePeriodRelationBefore,
DTTimePeriodRelationNone //One or more of the dates does not exist
};
}
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExample/TimePeriodsViewController.xib
================================================
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExample/en.lproj/InfoPlist.strings
================================================
/* Localized versions of Info.plist keys */
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExample/main.m
================================================
//
// main.m
// DateToolsExample
//
// Created by Matthew York on 3/19/14.
//
//
#import
#import "AppDelegate.h"
int main(int argc, char * argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExample.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
0AFD486518F0BBC0004D0FE1 /* DateTools.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 0AFD486418F0BBC0004D0FE1 /* DateTools.bundle */; };
901CF0E31B6CA9FE00F6414B /* DateTools.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 901CF0D31B6CA9FE00F6414B /* DateTools.bundle */; };
901CF0E41B6CA9FE00F6414B /* DateTools.h in Headers */ = {isa = PBXBuildFile; fileRef = 901CF0D41B6CA9FE00F6414B /* DateTools.h */; settings = {ATTRIBUTES = (Public, ); }; };
901CF0E51B6CA9FE00F6414B /* DTConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 901CF0D51B6CA9FE00F6414B /* DTConstants.h */; settings = {ATTRIBUTES = (Public, ); }; };
901CF0E61B6CA9FE00F6414B /* DTConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 901CF0D61B6CA9FE00F6414B /* DTConstants.m */; };
901CF0E71B6CA9FE00F6414B /* DTError.h in Headers */ = {isa = PBXBuildFile; fileRef = 901CF0D71B6CA9FE00F6414B /* DTError.h */; settings = {ATTRIBUTES = (Public, ); }; };
901CF0E81B6CA9FE00F6414B /* DTError.m in Sources */ = {isa = PBXBuildFile; fileRef = 901CF0D81B6CA9FE00F6414B /* DTError.m */; };
901CF0E91B6CA9FE00F6414B /* DTTimePeriod.h in Headers */ = {isa = PBXBuildFile; fileRef = 901CF0D91B6CA9FE00F6414B /* DTTimePeriod.h */; settings = {ATTRIBUTES = (Public, ); }; };
901CF0EA1B6CA9FE00F6414B /* DTTimePeriod.m in Sources */ = {isa = PBXBuildFile; fileRef = 901CF0DA1B6CA9FE00F6414B /* DTTimePeriod.m */; };
901CF0EB1B6CA9FE00F6414B /* DTTimePeriodChain.h in Headers */ = {isa = PBXBuildFile; fileRef = 901CF0DB1B6CA9FE00F6414B /* DTTimePeriodChain.h */; settings = {ATTRIBUTES = (Public, ); }; };
901CF0EC1B6CA9FE00F6414B /* DTTimePeriodChain.m in Sources */ = {isa = PBXBuildFile; fileRef = 901CF0DC1B6CA9FE00F6414B /* DTTimePeriodChain.m */; };
901CF0ED1B6CA9FE00F6414B /* DTTimePeriodCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 901CF0DD1B6CA9FE00F6414B /* DTTimePeriodCollection.h */; settings = {ATTRIBUTES = (Public, ); }; };
901CF0EE1B6CA9FE00F6414B /* DTTimePeriodCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = 901CF0DE1B6CA9FE00F6414B /* DTTimePeriodCollection.m */; };
901CF0EF1B6CA9FE00F6414B /* DTTimePeriodGroup.h in Headers */ = {isa = PBXBuildFile; fileRef = 901CF0DF1B6CA9FE00F6414B /* DTTimePeriodGroup.h */; settings = {ATTRIBUTES = (Public, ); }; };
901CF0F01B6CA9FE00F6414B /* DTTimePeriodGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 901CF0E01B6CA9FE00F6414B /* DTTimePeriodGroup.m */; };
901CF0F11B6CA9FE00F6414B /* NSDate+DateTools.h in Headers */ = {isa = PBXBuildFile; fileRef = 901CF0E11B6CA9FE00F6414B /* NSDate+DateTools.h */; settings = {ATTRIBUTES = (Public, ); }; };
901CF0F21B6CA9FE00F6414B /* NSDate+DateTools.m in Sources */ = {isa = PBXBuildFile; fileRef = 901CF0E21B6CA9FE00F6414B /* NSDate+DateTools.m */; };
D935DB441B567FBD00BAA4F0 /* DTConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = D935DB431B567FBD00BAA4F0 /* DTConstants.m */; };
F007632018DE5F5E00A99075 /* DateToolsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F007631E18DE5F5E00A99075 /* DateToolsViewController.m */; };
F007632118DE5F5E00A99075 /* DateToolsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F007631F18DE5F5E00A99075 /* DateToolsViewController.xib */; };
F007632518DE5FE300A99075 /* Colours.m in Sources */ = {isa = PBXBuildFile; fileRef = F007632418DE5FE300A99075 /* Colours.m */; };
F007632C18DE61EE00A99075 /* Calendar_filled.png in Resources */ = {isa = PBXBuildFile; fileRef = F007632818DE61EE00A99075 /* Calendar_filled.png */; };
F007632D18DE61EE00A99075 /* Calendar_filled@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F007632918DE61EE00A99075 /* Calendar_filled@2x.png */; };
F007632E18DE61EE00A99075 /* Calendar.png in Resources */ = {isa = PBXBuildFile; fileRef = F007632A18DE61EE00A99075 /* Calendar.png */; };
F007632F18DE61EE00A99075 /* Calendar@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F007632B18DE61EE00A99075 /* Calendar@2x.png */; };
F007633418DE628900A99075 /* ExampleNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = F007633318DE628900A99075 /* ExampleNavigationController.m */; };
F007633918DE63C400A99075 /* TimePeriodsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F007633718DE63C400A99075 /* TimePeriodsViewController.m */; };
F007633A18DE63C400A99075 /* TimePeriodsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F007633818DE63C400A99075 /* TimePeriodsViewController.xib */; };
F007633F18DE647600A99075 /* Recents_filled.png in Resources */ = {isa = PBXBuildFile; fileRef = F007633B18DE647600A99075 /* Recents_filled.png */; };
F007634018DE647600A99075 /* Recents_filled@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F007633C18DE647600A99075 /* Recents_filled@2x.png */; };
F007634118DE647600A99075 /* Recents.png in Resources */ = {isa = PBXBuildFile; fileRef = F007633D18DE647600A99075 /* Recents.png */; };
F007634218DE647600A99075 /* Recents@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F007633E18DE647600A99075 /* Recents@2x.png */; };
F07A1A0818DCC76500B3E9FF /* DTTimePeriodCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = F07A1A0718DCC76500B3E9FF /* DTTimePeriodCollection.m */; };
F0A426D618D9FDB500E236C0 /* DTTimePeriod.m in Sources */ = {isa = PBXBuildFile; fileRef = F0A426D518D9FDB500E236C0 /* DTTimePeriod.m */; };
F0EE17E718DEB1A10010FAD8 /* DTError.m in Sources */ = {isa = PBXBuildFile; fileRef = F0EE17E218DEB1A10010FAD8 /* DTError.m */; };
F0EE17E818DEB1A10010FAD8 /* DTError.m in Sources */ = {isa = PBXBuildFile; fileRef = F0EE17E218DEB1A10010FAD8 /* DTError.m */; };
F0EE17E918DEB1A10010FAD8 /* DTTimePeriodChain.m in Sources */ = {isa = PBXBuildFile; fileRef = F0EE17E418DEB1A10010FAD8 /* DTTimePeriodChain.m */; };
F0EE17EA18DEB1A10010FAD8 /* DTTimePeriodChain.m in Sources */ = {isa = PBXBuildFile; fileRef = F0EE17E418DEB1A10010FAD8 /* DTTimePeriodChain.m */; };
F0EE17EB18DEB1A10010FAD8 /* DTTimePeriodGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = F0EE17E618DEB1A10010FAD8 /* DTTimePeriodGroup.m */; };
F0EE17EC18DEB1A10010FAD8 /* DTTimePeriodGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = F0EE17E618DEB1A10010FAD8 /* DTTimePeriodGroup.m */; };
F0F08D9F18D9E80E00214C6B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F0F08D9E18D9E80E00214C6B /* Foundation.framework */; };
F0F08DA118D9E80E00214C6B /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F0F08DA018D9E80E00214C6B /* CoreGraphics.framework */; };
F0F08DA318D9E80E00214C6B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F0F08DA218D9E80E00214C6B /* UIKit.framework */; };
F0F08DA918D9E80E00214C6B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F0F08DA718D9E80E00214C6B /* InfoPlist.strings */; };
F0F08DAB18D9E80E00214C6B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F0F08DAA18D9E80E00214C6B /* main.m */; };
F0F08DAF18D9E80E00214C6B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F0F08DAE18D9E80E00214C6B /* AppDelegate.m */; };
F0F08DB718D9E80E00214C6B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F0F08DB618D9E80E00214C6B /* Images.xcassets */; };
F0F08DBE18D9E80E00214C6B /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F0F08DBD18D9E80E00214C6B /* XCTest.framework */; };
F0F08DBF18D9E80E00214C6B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F0F08D9E18D9E80E00214C6B /* Foundation.framework */; };
F0F08DC018D9E80E00214C6B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F0F08DA218D9E80E00214C6B /* UIKit.framework */; };
F0F08DC818D9E80E00214C6B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F0F08DC618D9E80E00214C6B /* InfoPlist.strings */; };
F0F08DD918D9E94F00214C6B /* NSDate+DateTools.m in Sources */ = {isa = PBXBuildFile; fileRef = F0F08DD818D9E94F00214C6B /* NSDate+DateTools.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
F0F08DC118D9E80E00214C6B /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = F0F08D9318D9E80E00214C6B /* Project object */;
proxyType = 1;
remoteGlobalIDString = F0F08D9A18D9E80E00214C6B;
remoteInfo = DateToolsExample;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
0AFD486418F0BBC0004D0FE1 /* DateTools.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = DateTools.bundle; path = ../../../DateTools/DateTools.bundle; sourceTree = ""; };
901CF0D31B6CA9FE00F6414B /* DateTools.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = DateTools.bundle; sourceTree = ""; };
901CF0D41B6CA9FE00F6414B /* DateTools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DateTools.h; sourceTree = ""; };
901CF0D51B6CA9FE00F6414B /* DTConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTConstants.h; sourceTree = ""; };
901CF0D61B6CA9FE00F6414B /* DTConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTConstants.m; sourceTree = ""; };
901CF0D71B6CA9FE00F6414B /* DTError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTError.h; sourceTree = ""; };
901CF0D81B6CA9FE00F6414B /* DTError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTError.m; sourceTree = ""; };
901CF0D91B6CA9FE00F6414B /* DTTimePeriod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTTimePeriod.h; sourceTree = ""; };
901CF0DA1B6CA9FE00F6414B /* DTTimePeriod.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTTimePeriod.m; sourceTree = ""; };
901CF0DB1B6CA9FE00F6414B /* DTTimePeriodChain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTTimePeriodChain.h; sourceTree = ""; };
901CF0DC1B6CA9FE00F6414B /* DTTimePeriodChain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTTimePeriodChain.m; sourceTree = ""; };
901CF0DD1B6CA9FE00F6414B /* DTTimePeriodCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTTimePeriodCollection.h; sourceTree = ""; };
901CF0DE1B6CA9FE00F6414B /* DTTimePeriodCollection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTTimePeriodCollection.m; sourceTree = ""; };
901CF0DF1B6CA9FE00F6414B /* DTTimePeriodGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTTimePeriodGroup.h; sourceTree = ""; };
901CF0E01B6CA9FE00F6414B /* DTTimePeriodGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTTimePeriodGroup.m; sourceTree = ""; };
901CF0E11B6CA9FE00F6414B /* NSDate+DateTools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+DateTools.h"; sourceTree = ""; };
901CF0E21B6CA9FE00F6414B /* NSDate+DateTools.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+DateTools.m"; sourceTree = ""; };
908837C91B637C240063096B /* DateTools.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DateTools.framework; sourceTree = BUILT_PRODUCTS_DIR; };
908837CC1B637C240063096B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
D935DB431B567FBD00BAA4F0 /* DTConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DTConstants.m; path = ../../../DateTools/DTConstants.m; sourceTree = ""; };
F007631D18DE5F5E00A99075 /* DateToolsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DateToolsViewController.h; sourceTree = ""; };
F007631E18DE5F5E00A99075 /* DateToolsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DateToolsViewController.m; sourceTree = ""; };
F007631F18DE5F5E00A99075 /* DateToolsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DateToolsViewController.xib; sourceTree = ""; };
F007632318DE5FE300A99075 /* Colours.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Colours.h; sourceTree = ""; };
F007632418DE5FE300A99075 /* Colours.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Colours.m; sourceTree = ""; };
F007632818DE61EE00A99075 /* Calendar_filled.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Calendar_filled.png; sourceTree = ""; };
F007632918DE61EE00A99075 /* Calendar_filled@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Calendar_filled@2x.png"; sourceTree = ""; };
F007632A18DE61EE00A99075 /* Calendar.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Calendar.png; sourceTree = ""; };
F007632B18DE61EE00A99075 /* Calendar@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Calendar@2x.png"; sourceTree = ""; };
F007633218DE628900A99075 /* ExampleNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExampleNavigationController.h; sourceTree = ""; };
F007633318DE628900A99075 /* ExampleNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExampleNavigationController.m; sourceTree = ""; };
F007633618DE63C400A99075 /* TimePeriodsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TimePeriodsViewController.h; sourceTree = ""; };
F007633718DE63C400A99075 /* TimePeriodsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TimePeriodsViewController.m; sourceTree = ""; };
F007633818DE63C400A99075 /* TimePeriodsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TimePeriodsViewController.xib; sourceTree = ""; };
F007633B18DE647600A99075 /* Recents_filled.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Recents_filled.png; sourceTree = ""; };
F007633C18DE647600A99075 /* Recents_filled@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Recents_filled@2x.png"; sourceTree = ""; };
F007633D18DE647600A99075 /* Recents.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Recents.png; sourceTree = ""; };
F007633E18DE647600A99075 /* Recents@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Recents@2x.png"; sourceTree = ""; };
F07A1A0618DCC76500B3E9FF /* DTTimePeriodCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DTTimePeriodCollection.h; path = ../../../DateTools/DTTimePeriodCollection.h; sourceTree = ""; };
F07A1A0718DCC76500B3E9FF /* DTTimePeriodCollection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DTTimePeriodCollection.m; path = ../../../DateTools/DTTimePeriodCollection.m; sourceTree = ""; };
F0A426D418D9FDB500E236C0 /* DTTimePeriod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DTTimePeriod.h; path = ../../../DateTools/DTTimePeriod.h; sourceTree = ""; };
F0A426D518D9FDB500E236C0 /* DTTimePeriod.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DTTimePeriod.m; path = ../../../DateTools/DTTimePeriod.m; sourceTree = ""; };
F0A426D918DA358C00E236C0 /* DTConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DTConstants.h; path = ../../../DateTools/DTConstants.h; sourceTree = ""; };
F0EE17E018DEAE190010FAD8 /* DateTools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DateTools.h; path = ../../../DateTools/DateTools.h; sourceTree = ""; };
F0EE17E118DEB1A10010FAD8 /* DTError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DTError.h; path = ../../../DateTools/DTError.h; sourceTree = ""; };
F0EE17E218DEB1A10010FAD8 /* DTError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DTError.m; path = ../../../DateTools/DTError.m; sourceTree = ""; };
F0EE17E318DEB1A10010FAD8 /* DTTimePeriodChain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DTTimePeriodChain.h; path = ../../../DateTools/DTTimePeriodChain.h; sourceTree = ""; };
F0EE17E418DEB1A10010FAD8 /* DTTimePeriodChain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DTTimePeriodChain.m; path = ../../../DateTools/DTTimePeriodChain.m; sourceTree = ""; };
F0EE17E518DEB1A10010FAD8 /* DTTimePeriodGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DTTimePeriodGroup.h; path = ../../../DateTools/DTTimePeriodGroup.h; sourceTree = ""; };
F0EE17E618DEB1A10010FAD8 /* DTTimePeriodGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DTTimePeriodGroup.m; path = ../../../DateTools/DTTimePeriodGroup.m; sourceTree = ""; };
F0F08D9B18D9E80E00214C6B /* DateToolsExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DateToolsExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
F0F08D9E18D9E80E00214C6B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
F0F08DA018D9E80E00214C6B /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
F0F08DA218D9E80E00214C6B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
F0F08DA618D9E80E00214C6B /* DateToolsExample-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "DateToolsExample-Info.plist"; sourceTree = ""; };
F0F08DA818D9E80E00214C6B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
F0F08DAA18D9E80E00214C6B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
F0F08DAC18D9E80E00214C6B /* DateToolsExample-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "DateToolsExample-Prefix.pch"; sourceTree = ""; };
F0F08DAD18D9E80E00214C6B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
F0F08DAE18D9E80E00214C6B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
F0F08DB618D9E80E00214C6B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
F0F08DBC18D9E80E00214C6B /* DateToolsExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DateToolsExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
F0F08DBD18D9E80E00214C6B /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
F0F08DC518D9E80E00214C6B /* DateToolsExampleTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "DateToolsExampleTests-Info.plist"; sourceTree = ""; };
F0F08DC718D9E80E00214C6B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
F0F08DD718D9E94F00214C6B /* NSDate+DateTools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSDate+DateTools.h"; path = "../../../DateTools/NSDate+DateTools.h"; sourceTree = ""; };
F0F08DD818D9E94F00214C6B /* NSDate+DateTools.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSDate+DateTools.m"; path = "../../../DateTools/NSDate+DateTools.m"; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
908837C51B637C240063096B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
F0F08D9818D9E80E00214C6B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F0F08DA118D9E80E00214C6B /* CoreGraphics.framework in Frameworks */,
F0F08DA318D9E80E00214C6B /* UIKit.framework in Frameworks */,
F0F08D9F18D9E80E00214C6B /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F0F08DB918D9E80E00214C6B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F0F08DBE18D9E80E00214C6B /* XCTest.framework in Frameworks */,
F0F08DC018D9E80E00214C6B /* UIKit.framework in Frameworks */,
F0F08DBF18D9E80E00214C6B /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
901CF0D21B6CA9FE00F6414B /* DateTools */ = {
isa = PBXGroup;
children = (
901CF0D31B6CA9FE00F6414B /* DateTools.bundle */,
901CF0D41B6CA9FE00F6414B /* DateTools.h */,
901CF0D51B6CA9FE00F6414B /* DTConstants.h */,
901CF0D61B6CA9FE00F6414B /* DTConstants.m */,
901CF0D71B6CA9FE00F6414B /* DTError.h */,
901CF0D81B6CA9FE00F6414B /* DTError.m */,
901CF0D91B6CA9FE00F6414B /* DTTimePeriod.h */,
901CF0DA1B6CA9FE00F6414B /* DTTimePeriod.m */,
901CF0DB1B6CA9FE00F6414B /* DTTimePeriodChain.h */,
901CF0DC1B6CA9FE00F6414B /* DTTimePeriodChain.m */,
901CF0DD1B6CA9FE00F6414B /* DTTimePeriodCollection.h */,
901CF0DE1B6CA9FE00F6414B /* DTTimePeriodCollection.m */,
901CF0DF1B6CA9FE00F6414B /* DTTimePeriodGroup.h */,
901CF0E01B6CA9FE00F6414B /* DTTimePeriodGroup.m */,
901CF0E11B6CA9FE00F6414B /* NSDate+DateTools.h */,
901CF0E21B6CA9FE00F6414B /* NSDate+DateTools.m */,
);
name = DateTools;
path = ../../../DateTools;
sourceTree = "";
};
908837CA1B637C240063096B /* DateTools */ = {
isa = PBXGroup;
children = (
901CF0D21B6CA9FE00F6414B /* DateTools */,
908837CB1B637C240063096B /* Supporting Files */,
);
path = DateTools;
sourceTree = "";
};
908837CB1B637C240063096B /* Supporting Files */ = {
isa = PBXGroup;
children = (
908837CC1B637C240063096B /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "";
};
F007632218DE5F9E00A99075 /* Colours */ = {
isa = PBXGroup;
children = (
F007632318DE5FE300A99075 /* Colours.h */,
F007632418DE5FE300A99075 /* Colours.m */,
);
name = Colours;
sourceTree = "";
};
F007632618DE612D00A99075 /* Images */ = {
isa = PBXGroup;
children = (
F007632718DE613400A99075 /* Tab bar */,
);
name = Images;
sourceTree = "";
};
F007632718DE613400A99075 /* Tab bar */ = {
isa = PBXGroup;
children = (
F007632818DE61EE00A99075 /* Calendar_filled.png */,
F007632918DE61EE00A99075 /* Calendar_filled@2x.png */,
F007632A18DE61EE00A99075 /* Calendar.png */,
F007632B18DE61EE00A99075 /* Calendar@2x.png */,
F007633B18DE647600A99075 /* Recents_filled.png */,
F007633C18DE647600A99075 /* Recents_filled@2x.png */,
F007633D18DE647600A99075 /* Recents.png */,
F007633E18DE647600A99075 /* Recents@2x.png */,
);
name = "Tab bar";
sourceTree = "";
};
F007633018DE626600A99075 /* Controllers */ = {
isa = PBXGroup;
children = (
F007633218DE628900A99075 /* ExampleNavigationController.h */,
F007633318DE628900A99075 /* ExampleNavigationController.m */,
F007633118DE626D00A99075 /* Date Tools */,
F007633518DE63AB00A99075 /* Time Periods */,
);
name = Controllers;
sourceTree = "";
};
F007633118DE626D00A99075 /* Date Tools */ = {
isa = PBXGroup;
children = (
F007631D18DE5F5E00A99075 /* DateToolsViewController.h */,
F007631E18DE5F5E00A99075 /* DateToolsViewController.m */,
F007631F18DE5F5E00A99075 /* DateToolsViewController.xib */,
);
name = "Date Tools";
sourceTree = "";
};
F007633518DE63AB00A99075 /* Time Periods */ = {
isa = PBXGroup;
children = (
F007633618DE63C400A99075 /* TimePeriodsViewController.h */,
F007633718DE63C400A99075 /* TimePeriodsViewController.m */,
F007633818DE63C400A99075 /* TimePeriodsViewController.xib */,
);
name = "Time Periods";
sourceTree = "";
};
F0F08D9218D9E80E00214C6B = {
isa = PBXGroup;
children = (
F0F08DA418D9E80E00214C6B /* DateToolsExample */,
F0F08DC318D9E80E00214C6B /* DateToolsExampleTests */,
908837CA1B637C240063096B /* DateTools */,
F0F08D9D18D9E80E00214C6B /* Frameworks */,
F0F08D9C18D9E80E00214C6B /* Products */,
);
sourceTree = "";
};
F0F08D9C18D9E80E00214C6B /* Products */ = {
isa = PBXGroup;
children = (
F0F08D9B18D9E80E00214C6B /* DateToolsExample.app */,
F0F08DBC18D9E80E00214C6B /* DateToolsExampleTests.xctest */,
908837C91B637C240063096B /* DateTools.framework */,
);
name = Products;
sourceTree = "";
};
F0F08D9D18D9E80E00214C6B /* Frameworks */ = {
isa = PBXGroup;
children = (
F0F08D9E18D9E80E00214C6B /* Foundation.framework */,
F0F08DA018D9E80E00214C6B /* CoreGraphics.framework */,
F0F08DA218D9E80E00214C6B /* UIKit.framework */,
F0F08DBD18D9E80E00214C6B /* XCTest.framework */,
);
name = Frameworks;
sourceTree = "";
};
F0F08DA418D9E80E00214C6B /* DateToolsExample */ = {
isa = PBXGroup;
children = (
F0F08DAD18D9E80E00214C6B /* AppDelegate.h */,
F0F08DAE18D9E80E00214C6B /* AppDelegate.m */,
F0F08DD318D9E81C00214C6B /* DateTools */,
F007633018DE626600A99075 /* Controllers */,
F0F08DB618D9E80E00214C6B /* Images.xcassets */,
F0F08DA518D9E80E00214C6B /* Supporting Files */,
);
path = DateToolsExample;
sourceTree = "";
};
F0F08DA518D9E80E00214C6B /* Supporting Files */ = {
isa = PBXGroup;
children = (
F007632618DE612D00A99075 /* Images */,
F007632218DE5F9E00A99075 /* Colours */,
F0F08DA618D9E80E00214C6B /* DateToolsExample-Info.plist */,
F0F08DA718D9E80E00214C6B /* InfoPlist.strings */,
F0F08DAA18D9E80E00214C6B /* main.m */,
F0F08DAC18D9E80E00214C6B /* DateToolsExample-Prefix.pch */,
);
name = "Supporting Files";
sourceTree = "";
};
F0F08DC318D9E80E00214C6B /* DateToolsExampleTests */ = {
isa = PBXGroup;
children = (
F0F08DC418D9E80E00214C6B /* Supporting Files */,
);
path = DateToolsExampleTests;
sourceTree = "";
};
F0F08DC418D9E80E00214C6B /* Supporting Files */ = {
isa = PBXGroup;
children = (
F0F08DC518D9E80E00214C6B /* DateToolsExampleTests-Info.plist */,
F0F08DC618D9E80E00214C6B /* InfoPlist.strings */,
);
name = "Supporting Files";
sourceTree = "";
};
F0F08DD318D9E81C00214C6B /* DateTools */ = {
isa = PBXGroup;
children = (
0AFD486418F0BBC0004D0FE1 /* DateTools.bundle */,
F0EE17E118DEB1A10010FAD8 /* DTError.h */,
F0EE17E218DEB1A10010FAD8 /* DTError.m */,
F0EE17E018DEAE190010FAD8 /* DateTools.h */,
F0A426D918DA358C00E236C0 /* DTConstants.h */,
D935DB431B567FBD00BAA4F0 /* DTConstants.m */,
F0F08DD718D9E94F00214C6B /* NSDate+DateTools.h */,
F0F08DD818D9E94F00214C6B /* NSDate+DateTools.m */,
F0A426D418D9FDB500E236C0 /* DTTimePeriod.h */,
F0A426D518D9FDB500E236C0 /* DTTimePeriod.m */,
F0EE17E518DEB1A10010FAD8 /* DTTimePeriodGroup.h */,
F0EE17E618DEB1A10010FAD8 /* DTTimePeriodGroup.m */,
F07A1A0618DCC76500B3E9FF /* DTTimePeriodCollection.h */,
F07A1A0718DCC76500B3E9FF /* DTTimePeriodCollection.m */,
F0EE17E318DEB1A10010FAD8 /* DTTimePeriodChain.h */,
F0EE17E418DEB1A10010FAD8 /* DTTimePeriodChain.m */,
);
name = DateTools;
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
908837C61B637C240063096B /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
901CF0EF1B6CA9FE00F6414B /* DTTimePeriodGroup.h in Headers */,
901CF0E91B6CA9FE00F6414B /* DTTimePeriod.h in Headers */,
901CF0E41B6CA9FE00F6414B /* DateTools.h in Headers */,
901CF0E71B6CA9FE00F6414B /* DTError.h in Headers */,
901CF0EB1B6CA9FE00F6414B /* DTTimePeriodChain.h in Headers */,
901CF0F11B6CA9FE00F6414B /* NSDate+DateTools.h in Headers */,
901CF0E51B6CA9FE00F6414B /* DTConstants.h in Headers */,
901CF0ED1B6CA9FE00F6414B /* DTTimePeriodCollection.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
908837C81B637C240063096B /* DateTools */ = {
isa = PBXNativeTarget;
buildConfigurationList = 908837E01B637C240063096B /* Build configuration list for PBXNativeTarget "DateTools" */;
buildPhases = (
908837C41B637C240063096B /* Sources */,
908837C51B637C240063096B /* Frameworks */,
908837C61B637C240063096B /* Headers */,
908837C71B637C240063096B /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = DateTools;
productName = DateTools;
productReference = 908837C91B637C240063096B /* DateTools.framework */;
productType = "com.apple.product-type.framework";
};
F0F08D9A18D9E80E00214C6B /* DateToolsExample */ = {
isa = PBXNativeTarget;
buildConfigurationList = F0F08DCD18D9E80E00214C6B /* Build configuration list for PBXNativeTarget "DateToolsExample" */;
buildPhases = (
F0F08D9718D9E80E00214C6B /* Sources */,
F0F08D9818D9E80E00214C6B /* Frameworks */,
F0F08D9918D9E80E00214C6B /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = DateToolsExample;
productName = DateToolsExample;
productReference = F0F08D9B18D9E80E00214C6B /* DateToolsExample.app */;
productType = "com.apple.product-type.application";
};
F0F08DBB18D9E80E00214C6B /* DateToolsExampleTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = F0F08DD018D9E80E00214C6B /* Build configuration list for PBXNativeTarget "DateToolsExampleTests" */;
buildPhases = (
F0F08DB818D9E80E00214C6B /* Sources */,
F0F08DB918D9E80E00214C6B /* Frameworks */,
F0F08DBA18D9E80E00214C6B /* Resources */,
);
buildRules = (
);
dependencies = (
F0F08DC218D9E80E00214C6B /* PBXTargetDependency */,
);
name = DateToolsExampleTests;
productName = DateToolsExampleTests;
productReference = F0F08DBC18D9E80E00214C6B /* DateToolsExampleTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
F0F08D9318D9E80E00214C6B /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0510;
TargetAttributes = {
908837C81B637C240063096B = {
CreatedOnToolsVersion = 6.4;
};
F0F08DBB18D9E80E00214C6B = {
TestTargetID = F0F08D9A18D9E80E00214C6B;
};
};
};
buildConfigurationList = F0F08D9618D9E80E00214C6B /* Build configuration list for PBXProject "DateToolsExample" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = F0F08D9218D9E80E00214C6B;
productRefGroup = F0F08D9C18D9E80E00214C6B /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
F0F08D9A18D9E80E00214C6B /* DateToolsExample */,
F0F08DBB18D9E80E00214C6B /* DateToolsExampleTests */,
908837C81B637C240063096B /* DateTools */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
908837C71B637C240063096B /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
901CF0E31B6CA9FE00F6414B /* DateTools.bundle in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F0F08D9918D9E80E00214C6B /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F007633F18DE647600A99075 /* Recents_filled.png in Resources */,
F007632118DE5F5E00A99075 /* DateToolsViewController.xib in Resources */,
F0F08DB718D9E80E00214C6B /* Images.xcassets in Resources */,
F007633A18DE63C400A99075 /* TimePeriodsViewController.xib in Resources */,
F0F08DA918D9E80E00214C6B /* InfoPlist.strings in Resources */,
F007634118DE647600A99075 /* Recents.png in Resources */,
0AFD486518F0BBC0004D0FE1 /* DateTools.bundle in Resources */,
F007632E18DE61EE00A99075 /* Calendar.png in Resources */,
F007632F18DE61EE00A99075 /* Calendar@2x.png in Resources */,
F007634018DE647600A99075 /* Recents_filled@2x.png in Resources */,
F007632C18DE61EE00A99075 /* Calendar_filled.png in Resources */,
F007632D18DE61EE00A99075 /* Calendar_filled@2x.png in Resources */,
F007634218DE647600A99075 /* Recents@2x.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F0F08DBA18D9E80E00214C6B /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F0F08DC818D9E80E00214C6B /* InfoPlist.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
908837C41B637C240063096B /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
901CF0EA1B6CA9FE00F6414B /* DTTimePeriod.m in Sources */,
901CF0F01B6CA9FE00F6414B /* DTTimePeriodGroup.m in Sources */,
901CF0E81B6CA9FE00F6414B /* DTError.m in Sources */,
901CF0EE1B6CA9FE00F6414B /* DTTimePeriodCollection.m in Sources */,
901CF0E61B6CA9FE00F6414B /* DTConstants.m in Sources */,
901CF0F21B6CA9FE00F6414B /* NSDate+DateTools.m in Sources */,
901CF0EC1B6CA9FE00F6414B /* DTTimePeriodChain.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F0F08D9718D9E80E00214C6B /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D935DB441B567FBD00BAA4F0 /* DTConstants.m in Sources */,
F0EE17E718DEB1A10010FAD8 /* DTError.m in Sources */,
F0EE17EB18DEB1A10010FAD8 /* DTTimePeriodGroup.m in Sources */,
F0A426D618D9FDB500E236C0 /* DTTimePeriod.m in Sources */,
F007633418DE628900A99075 /* ExampleNavigationController.m in Sources */,
F0EE17E918DEB1A10010FAD8 /* DTTimePeriodChain.m in Sources */,
F07A1A0818DCC76500B3E9FF /* DTTimePeriodCollection.m in Sources */,
F0F08DAF18D9E80E00214C6B /* AppDelegate.m in Sources */,
F007632518DE5FE300A99075 /* Colours.m in Sources */,
F007632018DE5F5E00A99075 /* DateToolsViewController.m in Sources */,
F0F08DD918D9E94F00214C6B /* NSDate+DateTools.m in Sources */,
F007633918DE63C400A99075 /* TimePeriodsViewController.m in Sources */,
F0F08DAB18D9E80E00214C6B /* main.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F0F08DB818D9E80E00214C6B /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F0EE17E818DEB1A10010FAD8 /* DTError.m in Sources */,
F0EE17EC18DEB1A10010FAD8 /* DTTimePeriodGroup.m in Sources */,
F0EE17EA18DEB1A10010FAD8 /* DTTimePeriodChain.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
F0F08DC218D9E80E00214C6B /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = F0F08D9A18D9E80E00214C6B /* DateToolsExample */;
targetProxy = F0F08DC118D9E80E00214C6B /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
F0F08DA718D9E80E00214C6B /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
F0F08DA818D9E80E00214C6B /* en */,
);
name = InfoPlist.strings;
sourceTree = "";
};
F0F08DC618D9E80E00214C6B /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
F0F08DC718D9E80E00214C6B /* en */,
);
name = InfoPlist.strings;
sourceTree = "";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
908837DC1B637C240063096B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_WARN_UNREACHABLE_CODE = YES;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = DateTools/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.4;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
908837DD1B637C240063096B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_WARN_UNREACHABLE_CODE = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
INFOPLIST_FILE = DateTools/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.4;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
F0F08DCB18D9E80E00214C6B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 7.1;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
F0F08DCC18D9E80E00214C6B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 7.1;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
F0F08DCE18D9E80E00214C6B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "DateToolsExample/DateToolsExample-Prefix.pch";
INFOPLIST_FILE = "DateToolsExample/DateToolsExample-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
name = Debug;
};
F0F08DCF18D9E80E00214C6B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "DateToolsExample/DateToolsExample-Prefix.pch";
INFOPLIST_FILE = "DateToolsExample/DateToolsExample-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
name = Release;
};
F0F08DD118D9E80E00214C6B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/DateToolsExample.app/DateToolsExample";
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
"$(DEVELOPER_FRAMEWORKS_DIR)",
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "DateToolsExample/DateToolsExample-Prefix.pch";
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = "DateToolsExampleTests/DateToolsExampleTests-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUNDLE_LOADER)";
WRAPPER_EXTENSION = xctest;
};
name = Debug;
};
F0F08DD218D9E80E00214C6B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/DateToolsExample.app/DateToolsExample";
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
"$(DEVELOPER_FRAMEWORKS_DIR)",
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "DateToolsExample/DateToolsExample-Prefix.pch";
INFOPLIST_FILE = "DateToolsExampleTests/DateToolsExampleTests-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUNDLE_LOADER)";
WRAPPER_EXTENSION = xctest;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
908837E01B637C240063096B /* Build configuration list for PBXNativeTarget "DateTools" */ = {
isa = XCConfigurationList;
buildConfigurations = (
908837DC1B637C240063096B /* Debug */,
908837DD1B637C240063096B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F0F08D9618D9E80E00214C6B /* Build configuration list for PBXProject "DateToolsExample" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F0F08DCB18D9E80E00214C6B /* Debug */,
F0F08DCC18D9E80E00214C6B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F0F08DCD18D9E80E00214C6B /* Build configuration list for PBXNativeTarget "DateToolsExample" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F0F08DCE18D9E80E00214C6B /* Debug */,
F0F08DCF18D9E80E00214C6B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F0F08DD018D9E80E00214C6B /* Build configuration list for PBXNativeTarget "DateToolsExampleTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F0F08DD118D9E80E00214C6B /* Debug */,
F0F08DD218D9E80E00214C6B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = F0F08D9318D9E80E00214C6B /* Project object */;
}
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExample.xcodeproj/xcshareddata/xcschemes/DateTools.xcscheme
================================================
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExampleTests/DateToolsExampleTests-Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleExecutable
${EXECUTABLE_NAME}
CFBundleIdentifier
com.mattyork.${PRODUCT_NAME:rfc1034identifier}
CFBundleInfoDictionaryVersion
6.0
CFBundlePackageType
BNDL
CFBundleShortVersionString
1.0
CFBundleSignature
????
CFBundleVersion
1
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Examples/DateToolsExample/DateToolsExampleTests/en.lproj/InfoPlist.strings
================================================
/* Localized versions of Info.plist keys */
================================================
FILE: archive/bitbar/App/Vendor/DateTools/LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2014 Matthew York
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: archive/bitbar/App/Vendor/DateTools/README.md
================================================

## DateTools
DateTools was written to streamline date and time handling in Objective-C. Classes and concepts from other languages served as an inspiration for DateTools, especially the [DateTime](http://msdn.microsoft.com/en-us/library/system.datetime(v=vs.110).aspx) structure and [Time Period Library](Time Period Library) for .NET. Through these classes and others, DateTools removes the boilerplate required to access date components, handles more nuanced date comparisons, and serves as the foundation for entirely new concepts like Time Periods and their collections.
[](https://travis-ci.org/MatthewYork/DateTools)
[](http://cocoapods.org/?q=datetools)
####Featured In
Yahoo! Livetext
My Disney Experience
ALDI
Guidebook
Pitch Locator Pro
## Installation
**Cocoapods**
pod 'DateTools'
**Manual Installation**
All the classes required for DateTools are located in the DateTools folder in the root of this repository. They are listed below:
* DateTools.h
* NSDate+DateTools.{h,m}
* DTConstants.h
* DTError.{h,m}
* DTTimePeriod.{h,m}
* DTTimePeriodGroup.{h,m}
* DTTimePeriodCollection.{h,m}
* DTTimePeriodChain.{h,m}
The following bundle is necessary if you would like to support internationalization or would like to use the "Time Ago" functionality. You can add localizations at the `Localizations` subheading under `Info` in the `Project` menu.
* DateTools.bundle
DateTools.h contains the headers for all the other files. Import this if you want to link to the entire framework.
## Table of Contents
* [**NSDate+DateTools**](#nsdate-datetools)
* [Time Ago](#time-ago)
* [Date Components](#date-components)
* [Date Editing](#date-editing)
* [Date Comparison](#date-comparison)
* [Formatted Date Strings](#formatted-date-strings)
* [**Time Periods**](#time-periods)
* [Initialization](#initialization)
* [Time Period Info](#time-period-info)
* [Manipulation](#manipulation)
* [Relationships](#relationships)
* [**Time Period Groups**](#time-period-groups)
* [Time Period Collections](#time-period-collections)
* [Time Period Chains](#time-period-chains)
* [**Unit Tests**](#unit-tests)
* [**Credits**](#credits)
* [**License**](#license)
##NSDate+DateTools
One of the missions of DateTools was to make NSDate feel more complete. There are many other languages that allow direct access to information about dates from their date classes, but NSDate (sadly) does not. It safely works only in the Unix time offsets through the timeIntervalSince... methods for building dates and remains calendar agnostic. But that's not always what we want to do. Sometimes, we want to work with dates based on their date components (like year, month, day, etc) at a more abstract level. This is where DateTools comes in.
####Time Ago
No date library would be complete without the ability to quickly make an NSString based on how much earlier a date is than now. DateTools has you covered. These "time ago" strings come in a long and short form, with the latter closely resembling Twitter. You can get these strings like so:
```objc
NSDate *timeAgoDate = [NSDate dateWithTimeIntervalSinceNow:-4];
NSLog(@"Time Ago: %@", timeAgoDate.timeAgoSinceNow);
NSLog(@"Time Ago: %@", timeAgoDate.shortTimeAgoSinceNow);
//Output:
//Time Ago: 4 seconds ago
//Time Ago: 4s
```
Assuming you have added the localization to your project, `DateTools` currently supports the following languages:
- ar (Arabic)
- bg (Bulgarian)
- ca (Catalan)
- zh_Hans (Chinese Simplified)
- zh_Hant (Chinese Traditional)
- cs (Czech)
- da (Danish)
- nl (Dutch)
- en (English)
- fi (Finnish)
- fr (French)
- de (German)
- gre (Greek)
- gu (Gujarati)
- he (Hebrew)
- hi (Hindi)
- hu (Hungarian)
- is (Icelandic)
- id (Indonesian)
- it (Italian)
- ja (Japanese)
- ko (Korean)
- lv (Latvian)
- ms (Malay)
- nb (Norwegian)
- pl (Polish)
- pt (Portuguese)
- ro (Romanian)
- ru (Russian)
- sl (Slovenian)
- es (Spanish)
- sv (Swedish)
- th (Thai)
- tr (Turkish)
- uk (Ukrainian)
- vi (Vietnamese)
- cy (Welsh)
- hr (Croatian)
If you know a language not listed here, please consider submitting a translation. [Localization codes by language](http://stackoverflow.com/questions/3040677/locale-codes-for-iphone-lproj-folders).
This project is user driven (by people like you). Pull requests close faster than issues (merged or rejected).
Thanks to Kevin Lawler for his work on [NSDate+TimeAgo](https://github.com/kevinlawler/NSDate-TimeAgo), which has been officially merged into this library.
####Date Components
There is a lot of boilerplate associated with getting date components from an NSDate. You have to set up a calendar, use the desired flags for the components you want, and finally extract them out of the calendar.
With DateTools, this:
```objc
//Create calendar
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit;
NSDateComponents *dateComponents = [calendar components:unitFlags fromDate:date];
//Get components
NSInteger year = dateComponents.year;
NSInteger month = dateComponents.month;
```
...becomes this:
```objc
NSInteger year = date.year;
NSInteger month = date.month;
```
And if you would like to use a non-Gregorian calendar, that option is available as well.
```objc
NSInteger day = [date dayWithCalendar:calendar];
```
If you would like to override the default calendar that DateTools uses, simply change it in the defaultCalendar method of NSDate+DateTools.m.
####Date Editing
The date editing methods in NSDate+DateTools makes it easy to shift a date earlier or later by adding and subtracting date components. For instance, if you would like a date that is 1 year later from a given date, simply call the method dateByAddingYears.
With DateTools, this:
```objc
//Create calendar
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:[NSDate defaultCalendar]];
NSDateComponents *components = [[NSDateComponents alloc] init];
//Make changes
[components setYear:1];
//Get new date with updated year
NSDate *newDate = [calendar dateByAddingComponents:components toDate:date options:0];
```
...becomes this:
```objc
NSDate *newDate = [date dateByAddingYears:1];
```
Subtraction of date components is also fully supported through the dateBySubtractingYears
####Date Comparison
Another mission of the DateTools category is to greatly increase the flexibility of date comparisons. NSDate gives you four basic methods:
* isEqualToDate:
* earlierDate:
* laterDate:
* compare:
earlierDate: and laterDate: are great, but it would be nice to have a boolean response to help when building logic in code; to easily ask "is this date earlier than that one?". DateTools has a set of proxy methods that do just that as well as a few other methods for extended flexibility. The new methods are:
* isEarlierThan
* isEarlierThanOrEqualTo
* isLaterThan
* isLaterThanOrEqualTo
These methods are great for comparing dates in a boolean fashion, but what if we want to compare the dates and return some meaningful information about how far they are apart? NSDate comes with two methods timeIntervalSinceDate: and timeIntervalSinceNow which gives you a double offset representing the number of seconds between the two dates. This is great and all, but there are times when one wants to know how many years or days are between two dates. For this, DateTools goes back to the ever-trusty NSCalendar and abstracts out all the necessary code for you.
With Date Tools, this:
```objc
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:[NSDate defaultCalendar]];
NSDate *earliest = [firstDate earlierDate:secondDate];
NSDate *latest = (secondDate == firstDate) ? secondDate : firstDate;
NSInteger multiplier = (secondDate == firstDate) ? -1 : 1;
NSDateComponents *components = [calendar components:allCalendarUnitFlags fromDate:earliest toDate:latest options:0];
NSInteger yearsApart = multiplier*(components.month + 12*components.year);
```
..becomes this:
```objc
NSInteger yearsApart = [firstDate yearsFrom:secondDate];
```
Methods for comparison in this category include:
* yearsFrom:, yearsUntil, yearsAgo, yearsEarlierThan:, yearsLaterThan:
* monthsFrom:, monthsUntil, monthsAgo, monthsEarlierThan:, monthsLaterThan:
* weeksFrom:, weeksUntil, weeksAgo, weeksEarlierThan:, weeksLaterThan:
* daysFrom:, daysUntil, daysAgo, daysEarlierThan:, daysLaterThan:
* hoursFrom:, hoursUntil, hoursAgo, hoursEarlierThan:, hoursLaterThan:
* minutesFrom:, minutesUntil, minutesAgo, minutesEarlierThan:, minutesLaterThan:
* secondsFrom:, secondsUntil, secondsAgo, secondsEarlierThan:, secondsLaterThan:
####Formatted Date Strings
Just for kicks, DateTools has a few convenience methods for quickly creating strings from dates. Those two methods are formattedDateWithStyle: and formattedDateWithFormat:. The current locale is used unless otherwise specified by additional method parameters. Again, just for kicks, really.
##Time Periods
Dates are important, but the real world is a little less discrete than that. Life is made up of spans of time, like an afternoon appointment or a weeklong vacation. In DateTools, time periods are represented by the DTTimePeriod class and come with a suite of initializaiton, manipulation, and comparison methods to make working with them a breeze.
####Initialization
Time peroids consist of an NSDate start date and end date. To initialize a time period, call the init function.
```objc
DTTimePeriod *timePeriod = [[DTTimePeriod alloc] initWithStartDate:startDate endDate:endDate];
```
or, if you would like to create a time period of a known length that starts or ends at a certain time, try out a few other init methods. The method below, for example, creates a time period starting at the current time that is exactly 5 hours long.
```objc
DTTimePeriod *timePeriod = [DTTimePeriod timePeriodWithSize:DTTimePeriodSizeHour amount:5 startingAt:[NSDate date]];
```
####Time Period Info
A host of methods have been extended to give information about an instance of DTTimePeriod. A few are listed below
* hasStartDate - Returns true if the period has a start date
* hasEndDate - Returns true if the period has an end date
* isMoment - Returns true if the period has the same start and end date
* durationIn.... - Returns the length of the time period in the requested units
####Manipulation
Time periods may also be manipulated. They may be shifted earlier or later as well as expanded and contracted.
**Shifting**
When a time period is shifted, the start dates and end dates are both moved earlier or later by the amounts requested.
To shift a time period earlier, call shiftEarlierWithSize:amount: and to shift it later, call shiftLaterWithSize:amount:. The amount field serves as a multipler, just like in the above initializaion method.
**Lengthening/Shortening**
When a time periods is lengthened or shortened, it does so anchoring one date of the time period and then changing the other one. There is also an option to anchor the centerpoint of the time period, changing both the start and end dates.
An example of lengthening a time period is shown below:
```objc
DTTimePeriod *timePeriod = [DTTimePeriod timePeriodWithSize:DTTimePeriodSizeMinute endingAt:[NSDate date]];
[timePeriod lengthenWithAnchorDate:DTTimePeriodAnchorEnd size:DTTimePeriodSizeMinute amount:1];
```
This doubles a time period of duration 1 minute to duration 2 minutes. The end date of "now" is retained and only the start date is shifted 1 minute earlier.
####Relationships
There may come a need, say when you are making a scheduling app, when it might be good to know how two time periods relate to one another. Are they the same? Is one inside of another? All these questions may be asked using the relationship methods of DTTimePeriod.
**The Basics**
Below is a chart of all the possible relationships between two time periods:

A suite of methods have been extended to check for the basic relationships. They are listed below:
* isEqualToPeriod:
* isInside:
* contains:
* overlapsWith:
* intersects:
You can also check for the official relationship (like those shown in the chart) with the following method:
```objc
-(DTTimePeriodRelation)relationToPeriod:(DTTimePeriod *)period;
```
All of the possible relationships have been enumerated in the DTTimePeriodRelation enum.
**For a better grasp on how time periods relate to one another, check out the "Time Periods" tab in the example application. Here you can slide a few time periods around and watch their relationships change.**

##Time Period Groups
Time period groups are the final abstraction of date and time in DateTools. Here, time periods are gathered and organized into something useful. There are two main types of time period groups, DTTimePeriodCollection and DTTimePeriodChain. At a high level, think about a collection as a loose group where overlaps may occur and a chain a more linear, tight group where overlaps are not allowed.
Both collections and chains operate like an NSArray. You may add,insert and remove DTTimePeriod objects from them just as you would objects in an array. The difference is how these periods are handled under the hood.
###Time Period Collections
Time period collections serve as loose sets of time periods. They are unorganized unless you decide to sort them, and have their own characteristics like a StartDate and EndDate that are extrapolated from the time periods within. Time period collections allow overlaps within their set of time periods.

To make a new collection, call the class method like so:
```objc
//Create collection
DTTimePeriodCollection *collection = [DTTimePeriodCollection collection];
//Create a few time periods
DTTimePeriod *firstPeriod = [DTTimePeriod timePeriodWithStartDate:[dateFormatter dateFromString:@"2014 11 05 18:15:12.000"] endDate:[dateFormatter dateFromString:@"2015 11 05 18:15:12.000"]];
DTTimePeriod *secondPeriod = [DTTimePeriod timePeriodWithStartDate:[dateFormatter dateFromString:@"2015 11 05 18:15:12.000"] endDate:[dateFormatter dateFromString:@"2016 11 05 18:15:12.000"]];
//Add time periods to the colleciton
[collection addTimePeriod:firstPeriod];
[collection addTimePeriod:secondPeriod];
//Retreive collection items
DTTimePeriod *firstPeriod = collection[0];
```
**Sorting**
Sorting time periods in a collection is easy, just call one of the sort methods. There are a total of three sort options, listed below:
* **Start Date** - sortByStartAscending, sortByStartDescending
* **End Date** - sortByEndAscending, sortByEndDescending
* **Time Period Duration** - sortByDurationAscending, sortByDurationDescending
**Operations**
It is also possible to check an NSDate's or DTTimePeriod's relationship to the collection. For instance, if you would like to see all the time periods that intersect with a certain date, you can call the periodsIntersectedByDate: method. The result is a new DTTimePeriodCollection with all those periods that intersect the provided date. There are a host of other methods to try out as well, including a full equality check between two collections.

###Time Period Chains
Time period chains serve as a tightly coupled set of time periods. They are always organized by start and end date, and have their own characteristics like a StartDate and EndDate that are extrapolated from the time periods within. Time period chains do not allow overlaps within their set of time periods. This type of group is ideal for modeling schedules like sequential meetings or appointments.

To make a new chain, call the class method like so:
```objc
//Create chain
DTTimePeriodChain *chain = [DTTimePeriodChain chain];
//Create a few time periods
DTTimePeriod *firstPeriod = [DTTimePeriod timePeriodWithStartDate:[dateFormatter dateFromString:@"2014 11 05 18:15:12.000"] endDate:[dateFormatter dateFromString:@"2015 11 05 18:15:12.000"]];
DTTimePeriod *secondPeriod = [DTTimePeriod timePeriodWithStartDate:[dateFormatter dateFromString:@"2015 11 05 18:15:12.000"] endDate:[dateFormatter dateFromString:@"2016 11 05 18:15:12.000"]];
//Add test periods
[chain addTimePeriod:firstPeriod];
[chain addTimePeriod:secondPeriod];
//Retreive chain items
DTTimePeriod *firstPeriod = chain[0];
```
Any time a date is added to the time chain, it retains its duration, but is modified to have its StartDate be the same as the latest period in the chain's EndDate. This helps keep the tightly coupled structure of the chain's time periods. Inserts (besides those at index 0) shift dates after insertion index by the duration of the new time period while leaving those at indexes before untouched. Insertions at index 0 shift the start date of the collection by the duration of the new time period. A full list of operations can be seen below.
**Operations**
Like collections, chains have an equality check and the ability to be shifted earlier and later. Here is a short list of other operations.

##Documentation
All methods and variables have been documented and are available for option+click inspection, just like the SDK classes. This includes an explanation of the methods as well as what their input and output parameters are for. Please raise an issue if you ever feel documentation is confusing or misleading and we will get it fixed up!
##Unit Tests
Unit tests were performed on all the major classes in the library for quality assurance. You can find theses under the "Tests" folder at the top of the library. There are over 300 test cases in all!
If you ever find a test case that is incomplete, please open an issue so we can get it fixed.
Continuous integration testing is performed by Travis CI: [](https://travis-ci.org/MatthewYork/DateTools)
##Credits
Thanks to [Kevin Lawler](https://github.com/kevinlawler) for his initial work on NSDate+TimeAgo. It laid the foundation for DateTools' timeAgo methods. You can find this great project [here](https://github.com/kevinlawler/NSDate-TimeAgo).
Many thanks to the .NET team for their DateTime class and a major thank you to [Jani Giannoudis](http://www.codeproject.com/Members/Jani-Giannoudis) for his work on ITimePeriod.
Images were first published through itenso.com through [Code Project](http://www.codeproject.com/Articles/168662/Time-Period-Library-for-NET)
I would also like to thank **God** through whom all things live and move and have their being. [Acts 17:28](http://www.biblegateway.com/passage/?search=Acts+17%3A16-34&version=NIV)
##License
The MIT License (MIT)
Copyright (c) 2014 Matthew York
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Tests/DateToolsTests/DateToolsTests/AppDelegate.h
================================================
//
// AppDelegate.h
// DateToolsTests
//
// Created by Matthew York on 3/22/14.
//
//
#import
@interface AppDelegate : UIResponder
@property (strong, nonatomic) UIWindow *window;
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Tests/DateToolsTests/DateToolsTests/AppDelegate.m
================================================
//
// AppDelegate.m
// DateToolsTests
//
// Created by Matthew York on 3/22/14.
//
//
#import "AppDelegate.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Tests/DateToolsTests/DateToolsTests/Base.lproj/Main.storyboard
================================================
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Tests/DateToolsTests/DateToolsTests/DateToolsTests-Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleDisplayName
${PRODUCT_NAME}
CFBundleExecutable
${EXECUTABLE_NAME}
CFBundleIdentifier
com.mattyork.${PRODUCT_NAME:rfc1034identifier}
CFBundleInfoDictionaryVersion
6.0
CFBundleName
${PRODUCT_NAME}
CFBundlePackageType
APPL
CFBundleShortVersionString
1.0
CFBundleSignature
????
CFBundleVersion
1.0
LSRequiresIPhoneOS
UIMainStoryboardFile
Main
UIRequiredDeviceCapabilities
armv7
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Tests/DateToolsTests/DateToolsTests/DateToolsTests-Prefix.pch
================================================
//
// Prefix header
//
// The contents of this file are implicitly included at the beginning of every source file.
//
#import
#ifndef __IPHONE_5_0
#warning "This project uses features only available in iOS SDK 5.0 and later."
#endif
#ifdef __OBJC__
#import
#import
#endif
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Tests/DateToolsTests/DateToolsTests/Images.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Tests/DateToolsTests/DateToolsTests/Images.xcassets/LaunchImage.launchimage/Contents.json
================================================
{
"images" : [
{
"orientation" : "portrait",
"idiom" : "iphone",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"subtype" : "retina4",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Tests/DateToolsTests/DateToolsTests/ViewController.h
================================================
//
// ViewController.h
// DateToolsTests
//
// Created by Matthew York on 3/22/14.
//
//
#import
@interface ViewController : UIViewController
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Tests/DateToolsTests/DateToolsTests/ViewController.m
================================================
//
// ViewController.m
// DateToolsTests
//
// Created by Matthew York on 3/22/14.
//
//
#import "ViewController.h"
#import "NSDate+DateTools.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//Time ago test
NSLog(@"10 months Ago: %@", [[NSDate date] dateBySubtractingMonths:10].timeAgoSinceNow);
NSLog(@"8 weeks Ago: %@", [[NSDate date] dateBySubtractingWeeks:8].timeAgoSinceNow);
NSLog(@"3 days Ago: %@", [[NSDate date] dateBySubtractingDays:3].timeAgoSinceNow);
NSLog(@"2 hours Ago: %@", [[NSDate date] dateBySubtractingHours:2].timeAgoSinceNow);
NSLog(@"5 minutes Ago: %@", [[NSDate date] dateBySubtractingMinutes:5].timeAgoSinceNow);
NSLog(@"1 second Ago: %@", [[NSDate date] dateBySubtractingSeconds:1].timeAgoSinceNow);
NSLog(@"now Ago: %@", [NSDate date].timeAgoSinceNow);
//Short time ago test
NSLog(@"10 months Ago: %@", [[NSDate date] dateBySubtractingMonths:10].shortTimeAgoSinceNow);
NSLog(@"8 weeks Ago: %@", [[NSDate date] dateBySubtractingWeeks:8].shortTimeAgoSinceNow);
NSLog(@"3 days Ago: %@", [[NSDate date] dateBySubtractingDays:3].shortTimeAgoSinceNow);
NSLog(@"2 hours Ago: %@", [[NSDate date] dateBySubtractingHours:2].shortTimeAgoSinceNow);
NSLog(@"5 minutes Ago: %@", [[NSDate date] dateBySubtractingMinutes:5].shortTimeAgoSinceNow);
NSLog(@"1 second Ago: %@", [[NSDate date] dateBySubtractingSeconds:1].shortTimeAgoSinceNow);
NSLog(@"now Ago: %@", [NSDate date].timeAgoSinceNow);
//Test formatters
NSString *dateStringFormatTest = [[NSDate date] formattedDateWithFormat:@"dd MMM, yyyy"];
NSString *dateStringStyleTest = [[NSDate date] formattedDateWithStyle:NSDateFormatterLongStyle timeZone:[NSTimeZone localTimeZone] locale:[NSLocale currentLocale]];
NSString *dateStringStyleTest2 = [[NSDate date] formattedDateWithStyle:NSDateFormatterShortStyle timeZone:[NSTimeZone localTimeZone] locale:[NSLocale currentLocale]];
NSLog(@"%@", dateStringFormatTest);
NSLog(@"%@", dateStringStyleTest);
NSLog(@"%@", dateStringStyleTest2);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Tests/DateToolsTests/DateToolsTests/en.lproj/InfoPlist.strings
================================================
/* Localized versions of Info.plist keys */
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Tests/DateToolsTests/DateToolsTests/es.lproj/InfoPlist.strings
================================================
/* Localized versions of Info.plist keys */
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Tests/DateToolsTests/DateToolsTests/es.lproj/Main.strings
================================================
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Tests/DateToolsTests/DateToolsTests/ja.lproj/InfoPlist.strings
================================================
/* Localized versions of Info.plist keys */
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Tests/DateToolsTests/DateToolsTests/ja.lproj/Main.strings
================================================
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Tests/DateToolsTests/DateToolsTests/main.m
================================================
//
// main.m
// DateToolsTests
//
// Created by Matthew York on 3/22/14.
//
//
#import
#import "AppDelegate.h"
int main(int argc, char * argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
================================================
FILE: archive/bitbar/App/Vendor/DateTools/Tests/DateToolsTests/DateToolsTests.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
0AFD485E18F082FE004D0FE1 /* DateTools.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 0AFD485D18F082FE004D0FE1 /* DateTools.bundle */; };
0AFD486018F08640004D0FE1 /* DTTimeAgoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0AFD485F18F08640004D0FE1 /* DTTimeAgoTests.m */; };
F00762C218DE5D7500A99075 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F00762C118DE5D7500A99075 /* Foundation.framework */; };
F00762C418DE5D7500A99075 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F00762C318DE5D7500A99075 /* CoreGraphics.framework */; };
F00762C618DE5D7500A99075 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F00762C518DE5D7500A99075 /* UIKit.framework */; };
F00762CC18DE5D7500A99075 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F00762CA18DE5D7500A99075 /* InfoPlist.strings */; };
F00762CE18DE5D7500A99075 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F00762CD18DE5D7500A99075 /* main.m */; };
F00762D218DE5D7500A99075 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F00762D118DE5D7500A99075 /* AppDelegate.m */; };
F00762D518DE5D7500A99075 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F00762D318DE5D7500A99075 /* Main.storyboard */; };
F00762D818DE5D7500A99075 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F00762D718DE5D7500A99075 /* ViewController.m */; };
F00762DA18DE5D7500A99075 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F00762D918DE5D7500A99075 /* Images.xcassets */; };
F00762E118DE5D7500A99075 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F00762E018DE5D7500A99075 /* XCTest.framework */; };
F00762E218DE5D7500A99075 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F00762C118DE5D7500A99075 /* Foundation.framework */; };
F00762E318DE5D7500A99075 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F00762C518DE5D7500A99075 /* UIKit.framework */; };
F00762EB18DE5D7500A99075 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F00762E918DE5D7500A99075 /* InfoPlist.strings */; };
F00762FB18DE5D9900A99075 /* DateToolsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F00762F618DE5D9900A99075 /* DateToolsTests.m */; };
F00762FC18DE5D9900A99075 /* DTTimePeriodTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F00762F718DE5D9900A99075 /* DTTimePeriodTests.m */; };
F00762FD18DE5D9900A99075 /* DTTimePeriodGroupTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F00762F818DE5D9900A99075 /* DTTimePeriodGroupTests.m */; };
F00762FE18DE5D9900A99075 /* DTTimePeriodChainTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F00762F918DE5D9900A99075 /* DTTimePeriodChainTests.m */; };
F00762FF18DE5D9900A99075 /* DTTimePeriodCollectionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F00762FA18DE5D9900A99075 /* DTTimePeriodCollectionTests.m */; };
F007631018DE5DC400A99075 /* NSDate+DateTools.m in Sources */ = {isa = PBXBuildFile; fileRef = F007630518DE5DC400A99075 /* NSDate+DateTools.m */; };
F007631218DE5DC400A99075 /* DTTimePeriod.m in Sources */ = {isa = PBXBuildFile; fileRef = F007630718DE5DC400A99075 /* DTTimePeriod.m */; };
F007631618DE5DC400A99075 /* DTTimePeriodCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = F007630B18DE5DC400A99075 /* DTTimePeriodCollection.m */; };
F075ABC91B9A52DA00AC95C8 /* DTConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = F075ABC81B9A52DA00AC95C8 /* DTConstants.m */; };
F0EE17F318DEB1C20010FAD8 /* DTError.m in Sources */ = {isa = PBXBuildFile; fileRef = F0EE17EE18DEB1C20010FAD8 /* DTError.m */; };
F0EE17F518DEB1C20010FAD8 /* DTTimePeriodChain.m in Sources */ = {isa = PBXBuildFile; fileRef = F0EE17F018DEB1C20010FAD8 /* DTTimePeriodChain.m */; };
F0EE17F718DEB1C20010FAD8 /* DTTimePeriodGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = F0EE17F218DEB1C20010FAD8 /* DTTimePeriodGroup.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
F00762E418DE5D7500A99075 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = F00762B618DE5D7500A99075 /* Project object */;
proxyType = 1;
remoteGlobalIDString = F00762BD18DE5D7500A99075;
remoteInfo = DateToolsTests;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
0AFD485D18F082FE004D0FE1 /* DateTools.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = DateTools.bundle; path = ../../../DateTools/DateTools.bundle; sourceTree = ""; };
0AFD485F18F08640004D0FE1 /* DTTimeAgoTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTTimeAgoTests.m; sourceTree = ""; };
0AFD486118F0AB99004D0FE1 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Main.strings; sourceTree = ""; };
0AFD486218F0AB99004D0FE1 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/InfoPlist.strings; sourceTree = ""; };
0AFD486318F0AB99004D0FE1 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/InfoPlist.strings; sourceTree = ""; };
F00762BE18DE5D7500A99075 /* DateToolsTests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DateToolsTests.app; sourceTree = BUILT_PRODUCTS_DIR; };
F00762C118DE5D7500A99075 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
F00762C318DE5D7500A99075 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
F00762C518DE5D7500A99075 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
F00762C918DE5D7500A99075 /* DateToolsTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "DateToolsTests-Info.plist"; sourceTree = ""; };
F00762CB18DE5D7500A99075 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
F00762CD18DE5D7500A99075 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
F00762CF18DE5D7500A99075 /* DateToolsTests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "DateToolsTests-Prefix.pch"; sourceTree = ""; };
F00762D018DE5D7500A99075 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
F00762D118DE5D7500A99075 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "