Project import
diff --git a/._cocoalumberjack b/._cocoalumberjack
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/._cocoalumberjack
Binary files differ
diff --git a/cocoalumberjack/._.gitignore b/cocoalumberjack/._.gitignore
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/._.gitignore
Binary files differ
diff --git a/cocoalumberjack/._.travis.yml b/cocoalumberjack/._.travis.yml
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/._.travis.yml
Binary files differ
diff --git a/cocoalumberjack/._Benchmarking b/cocoalumberjack/._Benchmarking
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/._Benchmarking
Binary files differ
diff --git a/cocoalumberjack/._CHANGELOG.md b/cocoalumberjack/._CHANGELOG.md
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/._CHANGELOG.md
Binary files differ
diff --git a/cocoalumberjack/._Classes b/cocoalumberjack/._Classes
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/._Classes
Binary files differ
diff --git a/cocoalumberjack/._CocoaLumberjack.podspec b/cocoalumberjack/._CocoaLumberjack.podspec
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/._CocoaLumberjack.podspec
Binary files differ
diff --git a/cocoalumberjack/._Demos b/cocoalumberjack/._Demos
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/._Demos
Binary files differ
diff --git a/cocoalumberjack/._Documentation b/cocoalumberjack/._Documentation
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/._Documentation
Binary files differ
diff --git a/cocoalumberjack/._Framework b/cocoalumberjack/._Framework
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/._Framework
Binary files differ
diff --git a/cocoalumberjack/._LICENSE.txt b/cocoalumberjack/._LICENSE.txt
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/._LICENSE.txt
Binary files differ
diff --git a/cocoalumberjack/._Lumberjack.xcodeproj b/cocoalumberjack/._Lumberjack.xcodeproj
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/._Lumberjack.xcodeproj
Binary files differ
diff --git a/cocoalumberjack/._LumberjackLogo.png b/cocoalumberjack/._LumberjackLogo.png
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/._LumberjackLogo.png
Binary files differ
diff --git a/cocoalumberjack/._README.md b/cocoalumberjack/._README.md
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/._README.md
Binary files differ
diff --git a/cocoalumberjack/._Tests b/cocoalumberjack/._Tests
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/._Tests
Binary files differ
diff --git a/cocoalumberjack/._uncrustify.cfg b/cocoalumberjack/._uncrustify.cfg
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/._uncrustify.cfg
Binary files differ
diff --git a/cocoalumberjack/.gitignore b/cocoalumberjack/.gitignore
new file mode 100644
index 0000000..d1bc424
--- /dev/null
+++ b/cocoalumberjack/.gitignore
@@ -0,0 +1,31 @@
+# Xcode
+#
+build/
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+project.xcworkspace
+!default.xcworkspace
+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/
+Podfile.lock
+LumberjackUser*.h
+.DS_Store
diff --git a/cocoalumberjack/.travis.yml b/cocoalumberjack/.travis.yml
new file mode 100644
index 0000000..ce65b53
--- /dev/null
+++ b/cocoalumberjack/.travis.yml
@@ -0,0 +1,100 @@
+

+osx_image: xcode7.1

+language: objective-c

+

+before_install:

+

+    - export LANG=en_US.UTF-8

+    - env

+    - locale

+    - gem install cocoapods --quiet

+    - pod --version

+    - pod setup --silent

+    - pod repo update --silent

+

+script:

+

+    - pod lib lint

+

+    - xctool -project Lumberjack.xcodeproj -scheme 'CocoaLumberjack'

+    - xctool -project Lumberjack.xcodeproj -scheme 'CocoaLumberjack-iOS' -configuration Release -sdk iphonesimulator build

+    - xctool -project Lumberjack.xcodeproj -scheme 'CocoaLumberjack-watchOS' -configuration Release -sdk watchsimulator build

+    - xctool -project Lumberjack.xcodeproj -scheme 'CocoaLumberjack-tvOS' -configuration Release -sdk appletvsimulator build

+    - xctool -project Lumberjack.xcodeproj -scheme 'FmwkTest'

+    - xctool -project Lumberjack.xcodeproj -scheme 'iOSLibStaticTest' -configuration Release -sdk iphonesimulator build

+    - xctool -project Lumberjack.xcodeproj -scheme 'watchOSSwiftTest' -configuration Release -sdk watchsimulator build

+    - xctool -project Lumberjack.xcodeproj -scheme 'tvOSSwiftTest' -configuration Release -sdk appletvsimulator build

+

+    - pod install --project-directory=Tests

+    - xctool -workspace Framework/Lumberjack.xcworkspace -scheme 'iOS Tests' -sdk iphonesimulator -arch i386 test

+    - xctool -workspace Framework/Lumberjack.xcworkspace -scheme 'OS X Tests' test

+

+    - cd Demos

+    - pod install --project-directory=ContextFilter

+    - xctool -workspace Demos.xcworkspace -scheme 'ContextFilter'

+

+    - pod install --project-directory=CoreDataLogger

+    - xctool -workspace Demos.xcworkspace -scheme 'CoreDataLogger'

+

+    - pod install --project-directory=CustomFormatters

+    - xctool -workspace Demos.xcworkspace -scheme 'CustomFormatters'

+

+    - pod install --project-directory=CustomLogLevels

+    - xctool -workspace Demos.xcworkspace -scheme 'CustomLogLevels'

+

+    - pod install --project-directory=DispatchQueueLogger

+    - xctool -workspace Demos.xcworkspace -scheme 'DispatchQueueLogger'

+

+    - pod install --project-directory=FineGrainedLogging

+    - xctool -workspace Demos.xcworkspace -scheme 'FineGrainedLogging'

+

+    - pod install --project-directory=GlobalLogLevel

+    - xctool -workspace Demos.xcworkspace -scheme 'GlobalLogLevel'

+

+    - pod install --project-directory=LogFileCompressor

+    - xctool -workspace Demos.xcworkspace -scheme 'LogFileCompressor'

+

+    - pod install --project-directory=NonArcTest

+    - xctool -workspace Demos.xcworkspace -scheme 'NonArcTest'

+

+    - pod install --project-directory=OverflowTestMac

+    - xctool -workspace Demos.xcworkspace -scheme 'OverflowTestMac'

+

+    - pod install --project-directory=PerUserLogLevels

+    - xctool -workspace Demos.xcworkspace -scheme 'PerUserLogLevels'

+

+    - pod install --project-directory=RegisteredDynamicLogging/Mobile

+    - xctool -workspace Demos.xcworkspace -scheme 'RegisteredLoggingTest (Mobile)' -configuration Release -sdk iphonesimulator -arch i386 build

+

+    - pod install --project-directory=RegisteredDynamicLogging/Desktop

+    - xctool -workspace Demos.xcworkspace -scheme 'RegisteredLoggingTest (Desktop)'

+

+    - pod install --project-directory=RollingTestMac

+    - xctool -workspace Demos.xcworkspace -scheme 'RollingTestMac'

+

+    - pod install --project-directory=TestXcodeColors/Desktop

+    - xctool -workspace Demos.xcworkspace -scheme 'TestXcodeColors (Desktop)'

+

+    - pod install --project-directory=TestXcodeColors/Mobile

+    - xctool -workspace Demos.xcworkspace -scheme 'TextXcodeColors (Mobile)' -configuration Release -sdk iphonesimulator -arch i386 build

+

+    - pod install --project-directory=WebServerIPhone

+    - xctool -workspace Demos.xcworkspace  -scheme 'WebServerIPhone' -configuration Release -sdk iphonesimulator -arch i386 build

+

+    - pod install --project-directory=Benchmark/Desktop

+    - xctool -workspace Demos.xcworkspace -scheme 'BenchmarkMac'

+

+    - pod install --project-directory=Benchmark/Mobile

+    - xctool -workspace Demos.xcworkspace -scheme 'BenchmarkIPhone' -configuration Release -sdk iphonesimulator -arch i386 build

+

+    - pod install --project-directory=SQLiteLogger

+    - xctool -workspace Demos.xcworkspace -scheme 'SQLiteLogger'

+

+    - pod install --project-directory=UniversalApp

+    - xctool -workspace Demos.xcworkspace -scheme 'UniversalApp' -configuration Release -sdk iphonesimulator -arch i386 build

+

+    - pod install --project-directory=CLI

+    - xctool -workspace Demos.xcworkspace -scheme 'CLI'

+

+    - pod install --project-directory=CaptureASL

+    - xctool -workspace Demos.xcworkspace -scheme 'CaptureASL' -configuration Release -sdk iphonesimulator -arch i386 build

diff --git a/cocoalumberjack/Benchmarking/._BaseNSLogging.h b/cocoalumberjack/Benchmarking/._BaseNSLogging.h
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/._BaseNSLogging.h
Binary files differ
diff --git a/cocoalumberjack/Benchmarking/._BaseNSLogging.m b/cocoalumberjack/Benchmarking/._BaseNSLogging.m
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/._BaseNSLogging.m
Binary files differ
diff --git a/cocoalumberjack/Benchmarking/._DynamicLogging.h b/cocoalumberjack/Benchmarking/._DynamicLogging.h
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/._DynamicLogging.h
Binary files differ
diff --git a/cocoalumberjack/Benchmarking/._DynamicLogging.m b/cocoalumberjack/Benchmarking/._DynamicLogging.m
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/._DynamicLogging.m
Binary files differ
diff --git a/cocoalumberjack/Benchmarking/._PerformanceTesting.h b/cocoalumberjack/Benchmarking/._PerformanceTesting.h
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/._PerformanceTesting.h
Binary files differ
diff --git a/cocoalumberjack/Benchmarking/._PerformanceTesting.m b/cocoalumberjack/Benchmarking/._PerformanceTesting.m
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/._PerformanceTesting.m
Binary files differ
diff --git a/cocoalumberjack/Benchmarking/._Results b/cocoalumberjack/Benchmarking/._Results
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/._Results
Binary files differ
diff --git a/cocoalumberjack/Benchmarking/._StaticLogging.h b/cocoalumberjack/Benchmarking/._StaticLogging.h
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/._StaticLogging.h
Binary files differ
diff --git a/cocoalumberjack/Benchmarking/._StaticLogging.m b/cocoalumberjack/Benchmarking/._StaticLogging.m
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/._StaticLogging.m
Binary files differ
diff --git a/cocoalumberjack/Benchmarking/BaseNSLogging.h b/cocoalumberjack/Benchmarking/BaseNSLogging.h
new file mode 100644
index 0000000..0d8aa57
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/BaseNSLogging.h
@@ -0,0 +1,12 @@
+#import <Foundation/Foundation.h>
+
+
+@interface BaseNSLogging : NSObject
+
++ (void)speedTest0;
++ (void)speedTest1;
++ (void)speedTest2;
++ (void)speedTest3;
++ (void)speedTest4;
+
+@end
diff --git a/cocoalumberjack/Benchmarking/BaseNSLogging.m b/cocoalumberjack/Benchmarking/BaseNSLogging.m
new file mode 100644
index 0000000..f8af514
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/BaseNSLogging.m
@@ -0,0 +1,92 @@
+#import "BaseNSLogging.h"
+#import "PerformanceTesting.h"
+
+#define DDLogVerbose NSLog
+#define DDLogInfo    NSLog
+#define DDLogWarn    NSLog
+#define DDLogError   NSLog
+
+#define FILENAME @"BaseNSLogging " // Trailing space to match exactly the others in length
+
+
+@implementation BaseNSLogging
+
++ (void)speedTest0
+{
+	// Log statements that will not be executed due to log level
+	
+	for (NSUInteger i = 0; i < SPEED_TEST_0_COUNT; i++)
+	{
+		DDLogVerbose(@"%@: SpeedTest0 - %lu", FILENAME, (unsigned long)i);
+	}
+}
+
++ (void)speedTest1
+{
+	// Log statements that will be executed asynchronously
+	
+	for (NSUInteger i = 0; i < SPEED_TEST_1_COUNT; i++)
+	{
+		DDLogWarn(@"%@: SpeedTest1 - %lu", FILENAME, (unsigned long)i);
+	}
+}
+
++ (void)speedTest2
+{
+	// Log statements that will be executed synchronously
+	
+	for (NSUInteger i = 0; i < SPEED_TEST_2_COUNT; i++)
+	{
+		DDLogError(@"%@: SpeedTest2 - %lu", FILENAME, (unsigned long)i);
+	}
+}
+
++ (void)speedTest3
+{
+	// Even Spread:
+	// 
+	// 25% - Not executed due to log level
+	// 50% - Executed asynchronously
+	// 25% - Executed synchronously
+	
+	for (NSUInteger i = 0; i < SPEED_TEST_3_COUNT; i++)
+	{
+		DDLogError(@"%@: SpeedTest3A - %lu", FILENAME, (unsigned long)i);
+	}
+	for (NSUInteger i = 0; i < SPEED_TEST_3_COUNT; i++)
+	{
+		DDLogWarn(@"%@: SpeedTest3B - %lu", FILENAME, (unsigned long)i);
+	}
+	for (NSUInteger i = 0; i < SPEED_TEST_3_COUNT; i++)
+	{
+		DDLogInfo(@"%@: SpeedTest3C - %lu", FILENAME, (unsigned long)i);
+	}
+	for (NSUInteger i = 0; i < SPEED_TEST_3_COUNT; i++)
+	{
+		DDLogVerbose(@"%@: SpeedTest3D - %lu", FILENAME, (unsigned long)i);
+	}
+}
+
++ (void)speedTest4
+{
+	// Custom Spread
+	
+	for (NSUInteger i = 0; i < SPEED_TEST_4_ERROR_COUNT; i++)
+	{
+		DDLogError(@"%@: SpeedTest4A - %lu", FILENAME, (unsigned long)i);
+	}
+	for (NSUInteger i = 0; i < SPEED_TEST_4_WARN_COUNT; i++)
+	{
+		DDLogWarn(@"%@: SpeedTest4B - %lu", FILENAME, (unsigned long)i);
+	}
+	for (NSUInteger i = 0; i < SPEED_TEST_4_INFO_COUNT; i++)
+	{
+		DDLogInfo(@"%@: SpeedTest4C - %lu", FILENAME, (unsigned long)i);
+	}
+	for (NSUInteger i = 0; i < SPEED_TEST_4_VERBOSE_COUNT; i++)
+	{
+		DDLogVerbose(@"%@: SpeedTest4D - %lu", FILENAME, (unsigned long)i);
+	}
+}
+
+@end
diff --git a/cocoalumberjack/Benchmarking/DynamicLogging.h b/cocoalumberjack/Benchmarking/DynamicLogging.h
new file mode 100644
index 0000000..e39e5de
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/DynamicLogging.h
@@ -0,0 +1,12 @@
+#import <Foundation/Foundation.h>
+
+
+@interface DynamicLogging : NSObject
+
++ (void)speedTest0;
++ (void)speedTest1;
++ (void)speedTest2;
++ (void)speedTest3;
++ (void)speedTest4;
+
+@end
diff --git a/cocoalumberjack/Benchmarking/DynamicLogging.m b/cocoalumberjack/Benchmarking/DynamicLogging.m
new file mode 100644
index 0000000..0b10a60
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/DynamicLogging.m
@@ -0,0 +1,101 @@
+#import "DynamicLogging.h"
+#import "PerformanceTesting.h"
+#import "DDLogMacros.h"
+
+#define FILENAME @"DynamicLogging"
+
+// Debug levels: off, error, warn, info, verbose
+static DDLogLevel ddLogLevel = DDLogLevelWarning; // NOT CONST
+
+
+@implementation DynamicLogging
+
++ (DDLogLevel)ddLogLevel
+{
+	return ddLogLevel;
+}
+
++ (void)ddSetLogLevel:(DDLogLevel)logLevel
+{
+	ddLogLevel = logLevel;
+}
+
++ (void)speedTest0
+{
+	// Log statements that will not be executed due to log level
+	
+	for (NSUInteger i = 0; i < SPEED_TEST_0_COUNT; i++)
+	{
+		DDLogVerbose(@"%@: SpeedTest0 - %lu", FILENAME, (unsigned long)i);
+	}
+}
+
++ (void)speedTest1
+{
+	// Log statements that will be executed asynchronously
+	
+	for (NSUInteger i = 0; i < SPEED_TEST_1_COUNT; i++)
+	{
+		DDLogWarn(@"%@: SpeedTest1 - %lu", FILENAME, (unsigned long)i);
+	}
+}
+
++ (void)speedTest2
+{
+	// Log statements that will be executed synchronously
+	
+	for (NSUInteger i = 0; i < SPEED_TEST_2_COUNT; i++)
+	{
+		DDLogError(@"%@: SpeedTest2 - %lu", FILENAME, (unsigned long)i);
+	}
+}
+
++ (void)speedTest3
+{
+	// Even Spread:
+	// 
+	// 25% - Not executed due to log level
+	// 50% - Executed asynchronously
+	// 25% - Executed synchronously
+	
+	for (NSUInteger i = 0; i < SPEED_TEST_3_COUNT; i++)
+	{
+		DDLogError(@"%@: SpeedTest3A - %lu", FILENAME, (unsigned long)i);
+	}
+	for (NSUInteger i = 0; i < SPEED_TEST_3_COUNT; i++)
+	{
+		DDLogWarn(@"%@: SpeedTest3B - %lu", FILENAME, (unsigned long)i);
+	}
+	for (NSUInteger i = 0; i < SPEED_TEST_3_COUNT; i++)
+	{
+		DDLogInfo(@"%@: SpeedTest3C - %lu", FILENAME, (unsigned long)i);
+	}
+	for (NSUInteger i = 0; i < SPEED_TEST_3_COUNT; i++)
+	{
+		DDLogVerbose(@"%@: SpeedTest3D - %lu", FILENAME, (unsigned long)i);
+	}
+}
+
++ (void)speedTest4
+{
+	// Custom Spread
+	
+	for (NSUInteger i = 0; i < SPEED_TEST_4_ERROR_COUNT; i++)
+	{
+		DDLogError(@"%@: SpeedTest4A - %lu", FILENAME, (unsigned long)i);
+	}
+	for (NSUInteger i = 0; i < SPEED_TEST_4_WARN_COUNT; i++)
+	{
+		DDLogWarn(@"%@: SpeedTest4B - %lu", FILENAME, (unsigned long)i);
+	}
+	for (NSUInteger i = 0; i < SPEED_TEST_4_INFO_COUNT; i++)
+	{
+		DDLogInfo(@"%@: SpeedTest4C - %lu", FILENAME, (unsigned long)i);
+	}
+	for (NSUInteger i = 0; i < SPEED_TEST_4_VERBOSE_COUNT; i++)
+	{
+		DDLogVerbose(@"%@: SpeedTest4D - %lu", FILENAME, (unsigned long)i);
+	}
+}
+
+@end
diff --git a/cocoalumberjack/Benchmarking/PerformanceTesting.h b/cocoalumberjack/Benchmarking/PerformanceTesting.h
new file mode 100644
index 0000000..1851ffa
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/PerformanceTesting.h
@@ -0,0 +1,19 @@
+#import <Foundation/Foundation.h>
+
+#define SPEED_TEST_0_COUNT 1000 // Total log statements
+#define SPEED_TEST_1_COUNT 1000 // Total log statements
+#define SPEED_TEST_2_COUNT 1000 // Total log statements
+#define SPEED_TEST_3_COUNT  250 // Per log level (multiply by 4 to get total)
+
+#define SPEED_TEST_4_VERBOSE_COUNT 900
+#define SPEED_TEST_4_INFO_COUNT    000
+#define SPEED_TEST_4_WARN_COUNT    000
+#define SPEED_TEST_4_ERROR_COUNT   100
+
+// Further documentation on these tests may be found in the implementation file.
+
+@interface PerformanceTesting : NSObject
+
++ (void)startPerformanceTests;
+
+@end
diff --git a/cocoalumberjack/Benchmarking/PerformanceTesting.m b/cocoalumberjack/Benchmarking/PerformanceTesting.m
new file mode 100644
index 0000000..a6c5b59
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/PerformanceTesting.m
@@ -0,0 +1,416 @@
+#import "PerformanceTesting.h"
+#import "DDLog.h"
+#import "DDASLLogger.h"
+#import "DDTTYLogger.h"
+#import "DDFileLogger.h"
+
+
+#import "BaseNSLogging.h"
+#import "StaticLogging.h"
+#import "DynamicLogging.h"
+
+// Define the number of times each test is performed.
+// Due to various factors, the execution time of each test run may vary quite a bit.
+// Each test should be executed several times in order to arrive at a stable average.
+#define NUMBER_OF_RUNS 20
+
+/**
+ * The idea behind the benchmark tests is simple:
+ * How does the logging framework compare to basic NSLog statements?
+ * 
+ * However, due to the complexity of the logging framework and its various configuration options,
+ * it is more complicated than a single test.  Thus the testing is broken up as follows:
+ * 
+ * - 3 Suites, each representing a different configuration of the logging framework
+ * - 5 Tests, run within each suite.
+ * 
+ * The suites are described below in the configureLoggingForSuiteX methods.
+ * The tests are described in the various logging files, such as StaticLogging or DynamicLogging.
+ * Notice that these file are almost exactly the same.
+ * 
+ * BaseNSLogging defines the log methods to use NSLog (the base we are comparing against).
+ * StaticLogging uses a 'const' log level, meaning the compiler will prune log statements (in release mode).
+ * DynamicLogging use a non-const log level, meaning each log statement will incur an integer comparison penalty.
+**/
+
+@implementation PerformanceTesting
+
+static NSTimeInterval base[5][3]; // [test][min,avg,max]
+
+static NSTimeInterval fmwk[3][2][5][3]; // [suite][file][test][min,avg,max]
+
+static DDFileLogger *fileLogger = nil;
+
++ (void)initialize
+{
+	bzero(&base, sizeof(base));
+	bzero(&fmwk, sizeof(fmwk));
+}
+
++ (DDFileLogger *)fileLogger
+{
+	if (fileLogger == nil)
+	{
+		fileLogger = [[DDFileLogger alloc] init];
+		
+		fileLogger.maximumFileSize = (1024 * 1024 * 1); //  1 MB
+		fileLogger.rollingFrequency = (60 * 60 * 24);   // 24 Hours
+		
+		fileLogger.logFileManager.maximumNumberOfLogFiles = 4;
+	}
+	
+	return fileLogger;
+}
+
+/**
+ * Suite 1 - Logging to Console only.
+**/
++ (void)configureLoggingForSuite1
+{
+	[DDLog removeAllLoggers];
+	
+	[DDLog addLogger:[DDASLLogger sharedInstance]];
+	[DDLog addLogger:[DDTTYLogger sharedInstance]];
+}
+
+/**
+ * Suite 2 - Logging to File only.
+ * 
+ * We attempt to configure the logging so it will be forced to roll the log files during the test.
+ * Rolling the log files requires creating and opening a new file.
+ * This could be a performance hit, so we want our benchmark to take this into account.
+**/
++ (void)configureLoggingForSuite2
+{
+	[DDLog removeAllLoggers];
+	
+	[DDLog addLogger:[self fileLogger]];
+}
+
+/**
+ * Suite 3 - Logging to Console & File.
+**/
++ (void)configureLoggingForSuite3
+{
+	[DDLog removeAllLoggers];
+	
+	[DDLog addLogger:[DDASLLogger sharedInstance]];
+	[DDLog addLogger:[DDTTYLogger sharedInstance]];
+	[DDLog addLogger:[self fileLogger]];
+}
+
++ (void)executeTestsWithBase:(BOOL)exeBase framework:(BOOL)exeFramework frameworkSuite:(int)suiteNum
+{
+	if (!exeBase && !exeFramework) return;
+	
+	int sn = suiteNum - 1; // Zero-indexed for array
+	
+	int i, j, k;
+	
+	int start = exeBase ? 0 : 1;
+	int finish = exeFramework ? 3 : 1;
+	
+	for (i = start; i < finish; i++)
+	{
+		Class class;
+		switch (i)
+		{
+			case 0  : class = [BaseNSLogging  class]; break;
+			case 1  : class = [StaticLogging  class]; break;
+			default : class = [DynamicLogging class]; break;
+		}
+		
+		for (j = 0; j < 5; j++)
+		{
+			NSTimeInterval min = DBL_MAX;
+			NSTimeInterval max = DBL_MIN;
+			
+			NSTimeInterval total = 0.0;
+			
+			for (k = 0; k < NUMBER_OF_RUNS; k++)
+			{
+				@autoreleasepool {
+				
+					NSDate *start = [NSDate date];
+					
+					switch (j)
+					{
+						case 0  : [class performSelector:@selector(speedTest0)]; break;
+						case 1  : [class performSelector:@selector(speedTest1)]; break;
+						case 2  : [class performSelector:@selector(speedTest2)]; break;
+						case 3  : [class performSelector:@selector(speedTest3)]; break;
+						default : [class performSelector:@selector(speedTest4)]; break;
+					}
+					
+					NSTimeInterval result = [start timeIntervalSinceNow] * -1.0;
+					
+					min = MIN(min, result);
+					max = MAX(max, result);
+					
+					total += result;
+				
+				}
+				[DDLog flushLog];
+			}
+			
+			if (i == 0)
+			{
+				// Base
+				base[j][0] = min;
+				base[j][1] = total / (double)NUMBER_OF_RUNS;
+				base[j][2] = max;
+			}
+			else
+			{
+				// Framework
+				fmwk[sn][i-1][j][0] = min;
+				fmwk[sn][i-1][j][1] = total / (double)NUMBER_OF_RUNS;
+				fmwk[sn][i-1][j][2] = max;
+			}
+		}
+	}
+}
+
++ (NSString *)printableResultsForSuite:(int)suiteNum
+{
+	int sn = suiteNum - 1; // Zero-indexed for array
+	
+	NSMutableString *str = [NSMutableString stringWithCapacity:2000];
+	
+	[str appendFormat:@"Results are given as [min][avg][max] calculated over the course of %i runs.", NUMBER_OF_RUNS];
+	[str appendString:@"\n\n"];
+	
+	[str appendString:@"Test 0:\n"];
+	[str appendFormat:@"Execute %i log statements.\n", SPEED_TEST_0_COUNT];
+	[str appendString:@"The log statement is above the log level threshold, and will not execute.\n"];
+	[str appendString:@"The StaticLogging class will compile it out (in release mode).\n"];
+	[str appendString:@"The DynamicLogging class will require a single integer comparison.\n"];
+	[str appendString:@"\n"];
+	[str appendFormat:@"BaseNSLogging :[%.4f][%.4f][%.4f]\n", base[0][0], base[0][1], base[0][2]];
+	[str appendFormat:@"StaticLogging :[%.4f][%.4f][%.4f]\n", fmwk[sn][0][0][0], fmwk[sn][0][0][1], fmwk[sn][0][0][2]];
+	[str appendFormat:@"DynamicLogging:[%.4f][%.4f][%.4f]\n", fmwk[sn][1][0][0], fmwk[sn][1][0][1], fmwk[sn][1][0][2]];
+	[str appendString:@"\n\n\n"];
+	
+	[str appendString:@"Test 1:\n"];
+	[str appendFormat:@"Execute %i log statements.\n", SPEED_TEST_1_COUNT];
+	[str appendString:@"The log statement is at or below the log level threshold, and will execute.\n"];
+	[str appendString:@"The logging framework will execute the statements Asynchronously.\n"];
+	[str appendString:@"\n"];
+	[str appendFormat:@"BaseNSLogging :[%.4f][%.4f][%.4f]\n", base[1][0], base[1][1], base[1][2]];
+	[str appendFormat:@"StaticLogging :[%.4f][%.4f][%.4f]\n", fmwk[sn][0][1][0], fmwk[sn][0][1][1], fmwk[sn][0][1][2]];
+	[str appendFormat:@"DynamicLogging:[%.4f][%.4f][%.4f]\n", fmwk[sn][1][1][0], fmwk[sn][1][1][1], fmwk[sn][1][1][2]];
+	[str appendString:@"\n\n\n"];
+	
+	[str appendString:@"Test 2:\n"];
+	[str appendFormat:@"Execute %i log statements.\n", SPEED_TEST_2_COUNT];
+	[str appendString:@"The log statement is at or below the log level threshold, and will execute.\n"];
+	[str appendString:@"The logging framework will execute the statements Synchronously.\n"];
+	[str appendString:@"\n"];
+	[str appendFormat:@"BaseNSLogging :[%.4f][%.4f][%.4f]\n", base[2][0], base[2][1], base[2][2]];
+	[str appendFormat:@"StaticLogging :[%.4f][%.4f][%.4f]\n", fmwk[sn][0][2][0], fmwk[sn][0][2][1], fmwk[sn][0][2][2]];
+	[str appendFormat:@"DynamicLogging:[%.4f][%.4f][%.4f]\n", fmwk[sn][1][2][0], fmwk[sn][1][2][1], fmwk[sn][1][2][2]];
+	[str appendString:@"\n\n\n"];
+	
+	[str appendString:@"Test 3:"];
+	[str appendFormat:@"Execute %i log statements per level.\n", SPEED_TEST_3_COUNT];
+	[str appendString:@"This is designed to mimic what might happen in a regular application.\n"];
+	[str appendString:@"25% will be above log level threshold and will be filtered out.\n"];
+	[str appendString:@"50% will execute Asynchronously.\n"];
+	[str appendString:@"25% will execute Synchronously.\n"];
+	[str appendString:@"\n"];
+	[str appendFormat:@"BaseNSLogging :[%.4f][%.4f][%.4f]\n", base[3][0], base[3][1], base[3][2]];
+	[str appendFormat:@"StaticLogging :[%.4f][%.4f][%.4f]\n", fmwk[sn][0][3][0], fmwk[sn][0][3][1], fmwk[sn][0][3][2]];
+	[str appendFormat:@"DynamicLogging:[%.4f][%.4f][%.4f]\n", fmwk[sn][1][3][0], fmwk[sn][1][3][1], fmwk[sn][1][3][2]];
+	[str appendString:@"\n\n\n"];
+	
+	float total = 0.0F;
+	total += SPEED_TEST_4_VERBOSE_COUNT;
+	total += SPEED_TEST_4_INFO_COUNT;
+	total += SPEED_TEST_4_WARN_COUNT;
+	total += SPEED_TEST_4_ERROR_COUNT;
+	
+	float verbose = (float)SPEED_TEST_4_VERBOSE_COUNT / total * 100.0F;
+	float info    = (float)SPEED_TEST_4_INFO_COUNT    / total * 100.0F;
+	float warn    = (float)SPEED_TEST_4_WARN_COUNT    / total * 100.0F;
+	float error   = (float)SPEED_TEST_4_ERROR_COUNT   / total * 100.0F;
+	
+	[str appendString:@"Test 4:\n"];
+	[str appendString:@"Similar to test 3, designed to mimic a real application\n"];
+	[str appendFormat:@"Execute %i log statements in total.\n", (int)total];
+	[str appendFormat:@"%04.1f%% will be above log level threshold and will be filtered out.\n", verbose];
+	[str appendFormat:@"%04.1f%% will execute Asynchronously.\n", (info + warn)];
+	[str appendFormat:@"%04.1f%% will execute Synchronously.\n", error];
+	[str appendString:@"\n"];
+	[str appendFormat:@"BaseNSLogging :[%.4f][%.4f][%.4f]\n", base[4][0], base[4][1], base[4][2]];
+	[str appendFormat:@"StaticLogging :[%.4f][%.4f][%.4f]\n", fmwk[sn][0][4][0], fmwk[sn][0][4][1], fmwk[sn][0][4][2]];
+	[str appendFormat:@"DynamicLogging:[%.4f][%.4f][%.4f]\n", fmwk[sn][1][4][0], fmwk[sn][1][4][1], fmwk[sn][1][4][2]];
+	[str appendString:@"\n\n\n"];
+	
+	return str;
+}
+
++ (NSString *)csvResults
+{
+	NSMutableString *str = [NSMutableString stringWithCapacity:1000];
+	
+	// What are we trying to do here?
+	// 
+	// What we ultimately want is to compare the performance of the framework against the baseline.
+	// This means we want to see the performance of the baseline for test 1,
+	// and then right next to it we want to see the performance of the framework with each various configuration.
+	// 
+	// So we want it to kinda look like this for Test 1:
+	// 
+	// Base, [min], [avg], [max]
+	// Suite 1 - Static, [min], [avg], [max]
+	// Suite 1 - Dynamic, [min], [avg], [max]
+	// Suite 2 - Static, [min], [avg], [max]
+	// Suite 2 - Dynamic, [min], [avg], [max]
+	// Suite 3 - Static, [min], [avg], [max]
+	// Suite 3 - Dynamic, [min], [avg], [max]
+	// 
+	// This will import into Excel just fine.
+	// However, I couldn't get Excel to make a decent looking graph with the data.
+	// Perhaps I'm just not familiar enough with Excel.
+	// But I was able to download OmniGraphSketcher,
+	// and figure out how to create an awesome looking graph in less than 15 minutes.
+	// And thus OmniGraphSketcher wins for me.
+	// The only catch is that it wants to import the data with numbers instead of names.
+	// So I need to convert the output to look like this:
+	// 
+	// 0, [min], [avg], [max]
+	// 1, [min], [avg], [max]
+	// 2, [min], [avg], [max]
+	// 3, [min], [avg], [max]
+	// 4, [min], [avg], [max]
+	// 5, [min], [avg], [max]
+	// 6, [min], [avg], [max]
+	// 
+	// I can then import the data into OmniGraphSketcher, and rename the X-axis points.
+	
+	// static NSTimeInterval base[5][3]; // [test][min,avg,max]
+	// 
+	// static NSTimeInterval fmwk[3][2][5][3]; // [suite][file][test][min,avg,max]
+	
+	int row = 0;
+	int suite, file, test;
+	
+	for (test = 0; test < 5; test++)
+	{
+		[str appendFormat:@"%i, %.4f, %.4f, %.4f\n", row++, base[test][0], base[test][1], base[test][2]];
+		
+		for (suite = 0; suite < 3; suite++)
+		{
+			for (file = 0; file < 2; file++)
+			{
+				[str appendFormat:@"%i, %.4f, %.4f, %.4f\n", row++,
+				       fmwk[suite][file][test][0], fmwk[suite][file][test][1], fmwk[suite][file][test][2]];
+			}
+		}
+		
+		row += 3;
+	}
+	
+	return str;
+}
+
++ (void)startPerformanceTests
+{
+	BOOL runBase   = YES;
+	BOOL runSuite1 = YES;
+	BOOL runSuite2 = YES;
+	BOOL runSuite3 = YES;
+	
+	if (!runBase && !runSuite1 && !runSuite2 && !runSuite3)
+	{
+		// Nothing to do, all suites disabled
+		return;
+	}
+	
+	NSLog(@"Preparing to start performance tests...");
+	NSLog(@"The results will be printed nicely when all logging has completed.\n\n");
+	
+	[NSThread sleepForTimeInterval:3.0];
+	
+	if (runBase)
+	{
+		[self executeTestsWithBase:YES framework:NO frameworkSuite:0];
+	}
+	
+	NSString *printableResults1 = nil;
+	NSString *printableResults2 = nil;
+	NSString *printableResults3 = nil;
+	
+	if (runSuite1)
+	{
+		[self configureLoggingForSuite1];
+		[self executeTestsWithBase:NO framework:YES frameworkSuite:1];
+		
+		printableResults1 = [self printableResultsForSuite:1];
+		
+		NSLog(@"\n\n\n\n");
+	}
+	if (runSuite2)
+	{
+		[self configureLoggingForSuite2];
+		[self executeTestsWithBase:NO framework:YES frameworkSuite:2];
+		
+		printableResults2 = [self printableResultsForSuite:2];
+		
+		NSLog(@"\n\n\n\n");
+	}
+	if (runSuite3)
+	{
+		[self configureLoggingForSuite3];
+		[self executeTestsWithBase:NO framework:YES frameworkSuite:3];
+		
+		printableResults3 = [self printableResultsForSuite:3];
+		
+		NSLog(@"\n\n\n\n");
+	}
+	
+	if (runSuite1)
+	{
+		NSLog(@"======================================================================");
+		NSLog(@"Benchmark Suite 1:");
+		NSLog(@"Logging framework configured to log to console only.");
+		NSLog(@"\n\n%@", printableResults1);
+		NSLog(@"======================================================================");
+	}
+	if (runSuite2)
+	{
+		NSLog(@"======================================================================");
+		NSLog(@"Benchmark Suite 2:");
+		NSLog(@"Logging framework configured to log to file only.");
+		NSLog(@"\n\n%@", printableResults2);
+		NSLog(@"======================================================================");
+	}
+	if (runSuite3)
+	{
+		NSLog(@"======================================================================");
+		NSLog(@"Benchmark Suite 3:");
+		NSLog(@"Logging framework configured to log to console & file.");
+		NSLog(@"\n\n%@", printableResults3);
+		NSLog(@"======================================================================");
+	}
+	
+#if TARGET_OS_IPHONE
+	NSString *csvResultsPath = [@"~/Documents/LumberjackBenchmark.csv" stringByExpandingTildeInPath];
+#else
+	NSString *csvResultsPath = [@"~/Desktop/LumberjackBenchmark.csv" stringByExpandingTildeInPath];
+#endif
+	
+	if (![[NSFileManager defaultManager] fileExistsAtPath:csvResultsPath])
+	{
+		[[NSFileManager defaultManager] createFileAtPath:csvResultsPath contents:nil attributes:nil];
+	}
+	
+	NSFileHandle *csvResultsFile = [NSFileHandle fileHandleForWritingAtPath:csvResultsPath];
+	
+	NSString *csvRsults = [self csvResults];
+	[csvResultsFile writeData:[csvRsults dataUsingEncoding:NSUTF8StringEncoding]];
+	
+	NSLog(@"CSV results file written to:\n%@", csvResultsPath);
+}
+
+@end
diff --git a/cocoalumberjack/Benchmarking/Results/._Benchmark PowerMac.csv b/cocoalumberjack/Benchmarking/Results/._Benchmark PowerMac.csv
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/Results/._Benchmark PowerMac.csv
Binary files differ
diff --git a/cocoalumberjack/Benchmarking/Results/._Benchmark iMac.csv b/cocoalumberjack/Benchmarking/Results/._Benchmark iMac.csv
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/Results/._Benchmark iMac.csv
Binary files differ
diff --git a/cocoalumberjack/Benchmarking/Results/._Benchmark iPad.csv b/cocoalumberjack/Benchmarking/Results/._Benchmark iPad.csv
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/Results/._Benchmark iPad.csv
Binary files differ
diff --git a/cocoalumberjack/Benchmarking/Results/._Benchmark iPhone 3GS.csv b/cocoalumberjack/Benchmarking/Results/._Benchmark iPhone 3GS.csv
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/Results/._Benchmark iPhone 3GS.csv
Binary files differ
diff --git a/cocoalumberjack/Benchmarking/Results/._Benchmark iPodTouch3 GCD.csv b/cocoalumberjack/Benchmarking/Results/._Benchmark iPodTouch3 GCD.csv
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/Results/._Benchmark iPodTouch3 GCD.csv
Binary files differ
diff --git "a/cocoalumberjack/Benchmarking/Results/._Lumberjack Benchmark \050PowerMac\051.ograph" "b/cocoalumberjack/Benchmarking/Results/._Lumberjack Benchmark \050PowerMac\051.ograph"
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ "b/cocoalumberjack/Benchmarking/Results/._Lumberjack Benchmark \050PowerMac\051.ograph"
Binary files differ
diff --git "a/cocoalumberjack/Benchmarking/Results/._Lumberjack Benchmark \050iMac\051.ograph" "b/cocoalumberjack/Benchmarking/Results/._Lumberjack Benchmark \050iMac\051.ograph"
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ "b/cocoalumberjack/Benchmarking/Results/._Lumberjack Benchmark \050iMac\051.ograph"
Binary files differ
diff --git "a/cocoalumberjack/Benchmarking/Results/._Lumberjack Benchmark \050iPad\051.ograph" "b/cocoalumberjack/Benchmarking/Results/._Lumberjack Benchmark \050iPad\051.ograph"
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ "b/cocoalumberjack/Benchmarking/Results/._Lumberjack Benchmark \050iPad\051.ograph"
Binary files differ
diff --git "a/cocoalumberjack/Benchmarking/Results/._Lumberjack Benchmark \050iPhone 3GS\051.ograph" "b/cocoalumberjack/Benchmarking/Results/._Lumberjack Benchmark \050iPhone 3GS\051.ograph"
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ "b/cocoalumberjack/Benchmarking/Results/._Lumberjack Benchmark \050iPhone 3GS\051.ograph"
Binary files differ
diff --git a/cocoalumberjack/Benchmarking/Results/Benchmark PowerMac.csv b/cocoalumberjack/Benchmarking/Results/Benchmark PowerMac.csv
new file mode 100644
index 0000000..b560dff
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/Results/Benchmark PowerMac.csv
@@ -0,0 +1,35 @@
+0, 0.2724, 0.2816, 0.3198
+1, 0.0000, 0.0000, 0.0000
+2, 0.0000, 0.0000, 0.0000
+3, 0.0000, 0.0000, 0.0000
+4, 0.0000, 0.0000, 0.0000
+5, 0.0000, 0.0000, 0.0000
+6, 0.0000, 0.0000, 0.0000
+10, 0.2710, 0.2757, 0.2826
+11, 0.0032, 0.0035, 0.0043
+12, 0.0032, 0.0036, 0.0066
+13, 0.0032, 0.0032, 0.0033
+14, 0.0032, 0.0032, 0.0033
+15, 0.0032, 0.0035, 0.0054
+16, 0.0032, 0.0037, 0.0065
+20, 0.2715, 0.2804, 0.3601
+21, 0.0996, 0.1037, 0.1090
+22, 0.0984, 0.1042, 0.1265
+23, 0.0296, 0.0311, 0.0370
+24, 0.0294, 0.0301, 0.0314
+25, 0.1118, 0.1523, 0.8192
+26, 0.1089, 0.1138, 0.1204
+30, 0.2720, 0.2760, 0.2842
+31, 0.0251, 0.0269, 0.0287
+32, 0.0260, 0.0273, 0.0298
+33, 0.0080, 0.0084, 0.0089
+34, 0.0079, 0.0084, 0.0091
+35, 0.0278, 0.0298, 0.0322
+36, 0.0277, 0.0299, 0.0319
+40, 0.2707, 0.2797, 0.3354
+41, 0.0095, 0.0103, 0.0112
+42, 0.0096, 0.0104, 0.0113
+43, 0.0028, 0.0030, 0.0034
+44, 0.0028, 0.0029, 0.0031
+45, 0.0098, 0.0112, 0.0120
+46, 0.0104, 0.0114, 0.0122
diff --git a/cocoalumberjack/Benchmarking/Results/Benchmark iMac.csv b/cocoalumberjack/Benchmarking/Results/Benchmark iMac.csv
new file mode 100644
index 0000000..c749ef1
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/Results/Benchmark iMac.csv
@@ -0,0 +1,35 @@
+0, 0.6169, 0.6700, 0.7403
+1, 0.0000, 0.0000, 0.0000
+2, 0.0000, 0.0000, 0.0000
+3, 0.0000, 0.0000, 0.0000
+4, 0.0000, 0.0000, 0.0000
+5, 0.0000, 0.0000, 0.0000
+6, 0.0000, 0.0000, 0.0000
+10, 0.6106, 0.6640, 0.7329
+11, 0.0184, 0.0268, 0.0466
+12, 0.0185, 0.0243, 0.0477
+13, 0.0183, 0.0213, 0.0234
+14, 0.0213, 0.0223, 0.0246
+15, 0.0182, 0.0231, 0.0426
+16, 0.0182, 0.0207, 0.0286
+20, 0.6167, 0.6651, 0.7365
+21, 0.2614, 0.3090, 0.3966
+22, 0.2672, 0.3121, 0.3805
+23, 0.0541, 0.0675, 0.0834
+24, 0.0541, 0.0576, 0.0824
+25, 0.2795, 0.3334, 0.4408
+26, 0.2847, 0.3438, 0.4951
+30, 0.6077, 0.6560, 0.7029
+31, 0.0676, 0.0997, 0.2275
+32, 0.0723, 0.0945, 0.1568
+33, 0.0188, 0.0191, 0.0203
+34, 0.0187, 0.0192, 0.0233
+35, 0.0723, 0.0886, 0.1579
+36, 0.0774, 0.0934, 0.1095
+40, 0.6101, 0.6597, 0.7372
+41, 0.0189, 0.0308, 0.0484
+42, 0.0237, 0.0322, 0.0468
+43, 0.0053, 0.0054, 0.0056
+44, 0.0053, 0.0055, 0.0057
+45, 0.0233, 0.0347, 0.0780
+46, 0.0223, 0.0316, 0.0559
diff --git a/cocoalumberjack/Benchmarking/Results/Benchmark iPad.csv b/cocoalumberjack/Benchmarking/Results/Benchmark iPad.csv
new file mode 100644
index 0000000..9760c6d
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/Results/Benchmark iPad.csv
@@ -0,0 +1,35 @@
+0, 2.4968, 2.5606, 2.7525
+1, 0.0001, 0.0001, 0.0001
+2, 0.0000, 0.0000, 0.0000
+3, 0.0000, 0.0000, 0.0000
+4, 0.0000, 0.0014, 0.0285
+5, 0.0000, 0.0000, 0.0001
+6, 0.0000, 0.0000, 0.0000
+10, 2.5016, 2.5982, 2.7952
+11, 0.2299, 0.5288, 1.2570
+12, 0.2845, 0.5943, 0.8713
+13, 0.3455, 0.3955, 0.5355
+14, 0.2955, 0.3814, 0.4431
+15, 0.2304, 0.5469, 0.9735
+16, 0.2761, 0.4723, 0.7460
+20, 2.5067, 2.5589, 2.6211
+21, 1.5797, 1.8261, 2.1204
+22, 1.8572, 1.9808, 2.1686
+23, 0.4198, 0.4877, 0.5202
+24, 0.4220, 0.4873, 0.5729
+25, 2.0504, 2.2492, 2.4038
+26, 2.1307, 2.3070, 2.4938
+30, 2.5003, 2.5565, 2.6215
+31, 0.5118, 0.6478, 0.8476
+32, 0.5157, 0.6690, 0.8628
+33, 0.1525, 0.2119, 0.2614
+34, 0.1407, 0.2039, 0.2715
+35, 0.5535, 0.6758, 0.8734
+36, 0.5397, 0.6877, 0.8979
+40, 2.4872, 2.5404, 2.5948
+41, 0.1454, 0.2044, 0.3307
+42, 0.1604, 0.2122, 0.2885
+43, 0.0287, 0.0484, 0.0962
+44, 0.0286, 0.0480, 0.1025
+45, 0.1542, 0.2173, 0.3335
+46, 0.1521, 0.2266, 0.3015
diff --git a/cocoalumberjack/Benchmarking/Results/Benchmark iPhone 3GS.csv b/cocoalumberjack/Benchmarking/Results/Benchmark iPhone 3GS.csv
new file mode 100644
index 0000000..8364ae0
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/Results/Benchmark iPhone 3GS.csv
@@ -0,0 +1,35 @@
+0, 4.2598, 4.3660, 4.6588
+1, 0.0000, 0.0000, 0.0000
+2, 0.0000, 0.0000, 0.0000
+3, 0.0000, 0.0000, 0.0000
+4, 0.0000, 0.0000, 0.0000
+5, 0.0000, 0.0000, 0.0000
+6, 0.0000, 0.0000, 0.0000
+10, 4.1986, 4.3513, 4.5088
+11, 0.5951, 1.5768, 2.3934
+12, 1.0329, 1.5809, 2.1354
+13, 0.2904, 0.3407, 0.4357
+14, 0.2413, 0.3309, 0.3610
+15, 0.6748, 1.2716, 1.6643
+16, 0.7571, 1.3473, 2.3276
+20, 4.2224, 4.3516, 4.5251
+21, 3.1635, 3.2748, 3.5510
+22, 3.2119, 3.2817, 3.4837
+23, 0.4739, 0.4894, 0.6311
+24, 0.4719, 0.4800, 0.5312
+25, 3.4027, 3.5172, 3.7449
+26, 3.3843, 3.4736, 3.7347
+30, 4.1721, 4.3516, 4.5596
+31, 0.9029, 1.2367, 1.5529
+32, 0.9005, 1.2779, 1.5703
+33, 0.1541, 0.1928, 0.2365
+34, 0.1533, 0.1986, 0.2383
+35, 0.8691, 1.1347, 1.5500
+36, 0.8477, 1.1970, 1.6069
+40, 4.1914, 4.3369, 4.6224
+41, 0.3008, 0.3281, 0.4669
+42, 0.2909, 0.3252, 0.4046
+43, 0.0470, 0.0478, 0.0488
+44, 0.0471, 0.0481, 0.0527
+45, 0.3151, 0.3484, 0.4229
+46, 0.3111, 0.3480, 0.4136
diff --git a/cocoalumberjack/Benchmarking/Results/Benchmark iPodTouch3 GCD.csv b/cocoalumberjack/Benchmarking/Results/Benchmark iPodTouch3 GCD.csv
new file mode 100644
index 0000000..caaa839
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/Results/Benchmark iPodTouch3 GCD.csv
@@ -0,0 +1,35 @@
+0, 4.7533, 4.8965, 5.1468
+1, 0.0000, 0.0000, 0.0000
+2, 0.0000, 0.0000, 0.0000
+3, 0.0000, 0.0000, 0.0000
+4, 0.0000, 0.0000, 0.0000
+5, 0.0000, 0.0000, 0.0000
+6, 0.0000, 0.0000, 0.0000
+10, 4.7739, 4.8658, 5.0876
+11, 0.1744, 0.7295, 1.3352
+12, 0.2169, 0.7354, 1.4760
+13, 0.1846, 0.2992, 0.4073
+14, 0.1816, 0.2980, 0.3568
+15, 0.1840, 0.8697, 1.5107
+16, 0.0834, 0.7477, 1.1599
+20, 4.7807, 4.9025, 5.1423
+21, 3.1918, 3.3175, 3.5093
+22, 3.1522, 3.2813, 3.5148
+23, 0.3052, 0.3182, 0.3852
+24, 0.3061, 0.3171, 0.3410
+25, 3.5837, 3.7104, 3.9758
+26, 3.5487, 3.6969, 3.9776
+30, 4.7613, 4.8927, 5.1026
+31, 0.8053, 1.0718, 1.3799
+32, 0.8069, 1.0888, 1.3447
+33, 0.1194, 0.1577, 0.1813
+34, 0.1249, 0.1523, 0.1777
+35, 0.9295, 1.2310, 1.4301
+36, 0.9240, 1.2278, 1.5636
+40, 4.8084, 4.8773, 5.0500
+41, 0.2822, 0.3202, 0.3642
+42, 0.3091, 0.3291, 0.3686
+43, 0.0302, 0.0313, 0.0341
+44, 0.0295, 0.0308, 0.0328
+45, 0.3281, 0.3669, 0.4102
+46, 0.3359, 0.3710, 0.3960
diff --git "a/cocoalumberjack/Benchmarking/Results/Lumberjack Benchmark \050PowerMac\051.ograph" "b/cocoalumberjack/Benchmarking/Results/Lumberjack Benchmark \050PowerMac\051.ograph"
new file mode 100644
index 0000000..8d5b3c7
--- /dev/null
+++ "b/cocoalumberjack/Benchmarking/Results/Lumberjack Benchmark \050PowerMac\051.ograph"
Binary files differ
diff --git "a/cocoalumberjack/Benchmarking/Results/Lumberjack Benchmark \050iMac\051.ograph" "b/cocoalumberjack/Benchmarking/Results/Lumberjack Benchmark \050iMac\051.ograph"
new file mode 100644
index 0000000..062c3c9
--- /dev/null
+++ "b/cocoalumberjack/Benchmarking/Results/Lumberjack Benchmark \050iMac\051.ograph"
Binary files differ
diff --git "a/cocoalumberjack/Benchmarking/Results/Lumberjack Benchmark \050iPad\051.ograph" "b/cocoalumberjack/Benchmarking/Results/Lumberjack Benchmark \050iPad\051.ograph"
new file mode 100644
index 0000000..267f5d0
--- /dev/null
+++ "b/cocoalumberjack/Benchmarking/Results/Lumberjack Benchmark \050iPad\051.ograph"
Binary files differ
diff --git "a/cocoalumberjack/Benchmarking/Results/Lumberjack Benchmark \050iPhone 3GS\051.ograph" "b/cocoalumberjack/Benchmarking/Results/Lumberjack Benchmark \050iPhone 3GS\051.ograph"
new file mode 100644
index 0000000..c797bfd
--- /dev/null
+++ "b/cocoalumberjack/Benchmarking/Results/Lumberjack Benchmark \050iPhone 3GS\051.ograph"
Binary files differ
diff --git a/cocoalumberjack/Benchmarking/StaticLogging.h b/cocoalumberjack/Benchmarking/StaticLogging.h
new file mode 100644
index 0000000..2a8c481
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/StaticLogging.h
@@ -0,0 +1,12 @@
+#import <Foundation/Foundation.h>
+
+
+@interface StaticLogging : NSObject
+
++ (void)speedTest0;
++ (void)speedTest1;
++ (void)speedTest2;
++ (void)speedTest3;
++ (void)speedTest4;
+
+@end
diff --git a/cocoalumberjack/Benchmarking/StaticLogging.m b/cocoalumberjack/Benchmarking/StaticLogging.m
new file mode 100644
index 0000000..2d0e3ca
--- /dev/null
+++ b/cocoalumberjack/Benchmarking/StaticLogging.m
@@ -0,0 +1,91 @@
+#import "StaticLogging.h"
+#import "PerformanceTesting.h"
+#import "DDLogMacros.h"
+
+#define FILENAME @"StaticLogging " // Trailing space to match exactly the others in length
+
+// Debug levels: off, error, warn, info, verbose
+static const DDLogLevel ddLogLevel = DDLogLevelWarning; // CONST
+
+
+@implementation StaticLogging
+
++ (void)speedTest0
+{
+	// Log statements that will not be executed due to log level
+	
+	for (NSUInteger i = 0; i < SPEED_TEST_0_COUNT; i++)
+	{
+		DDLogVerbose(@"%@: SpeedTest0 - %lu", FILENAME, (unsigned long)i);
+	}
+}
+
++ (void)speedTest1
+{
+	// Log statements that will be executed asynchronously
+	
+	for (NSUInteger i = 0; i < SPEED_TEST_1_COUNT; i++)
+	{
+		DDLogWarn(@"%@: SpeedTest1 - %lu", FILENAME, (unsigned long)i);
+	}
+}
+
++ (void)speedTest2
+{
+	// Log statements that will be executed synchronously
+	
+	for (NSUInteger i = 0; i < SPEED_TEST_2_COUNT; i++)
+	{
+		DDLogError(@"%@: SpeedTest2 - %lu", FILENAME, (unsigned long)i);
+	}
+}
+
++ (void)speedTest3
+{
+	// Even Spread:
+	// 
+	// 25% - Not executed due to log level
+	// 50% - Executed asynchronously
+	// 25% - Executed synchronously
+	
+	for (NSUInteger i = 0; i < SPEED_TEST_3_COUNT; i++)
+	{
+		DDLogError(@"%@: SpeedTest3A - %lu", FILENAME, (unsigned long)i);
+	}
+	for (NSUInteger i = 0; i < SPEED_TEST_3_COUNT; i++)
+	{
+		DDLogWarn(@"%@: SpeedTest3B - %lu", FILENAME, (unsigned long)i);
+	}
+	for (NSUInteger i = 0; i < SPEED_TEST_3_COUNT; i++)
+	{
+		DDLogInfo(@"%@: SpeedTest3C - %lu", FILENAME, (unsigned long)i);
+	}
+	for (NSUInteger i = 0; i < SPEED_TEST_3_COUNT; i++)
+	{
+		DDLogVerbose(@"%@: SpeedTest3D - %lu", FILENAME, (unsigned long)i);
+	}
+}
+
++ (void)speedTest4
+{
+	// Custom Spread
+	
+	for (NSUInteger i = 0; i < SPEED_TEST_4_ERROR_COUNT; i++)
+	{
+		DDLogError(@"%@: SpeedTest4A - %lu", FILENAME, (unsigned long)i);
+	}
+	for (NSUInteger i = 0; i < SPEED_TEST_4_WARN_COUNT; i++)
+	{
+		DDLogWarn(@"%@: SpeedTest4B - %lu", FILENAME, (unsigned long)i);
+	}
+	for (NSUInteger i = 0; i < SPEED_TEST_4_INFO_COUNT; i++)
+	{
+		DDLogInfo(@"%@: SpeedTest4C - %lu", FILENAME, (unsigned long)i);
+	}
+	for (NSUInteger i = 0; i < SPEED_TEST_4_VERBOSE_COUNT; i++)
+	{
+		DDLogVerbose(@"%@: SpeedTest4D - %lu", FILENAME, (unsigned long)i);
+	}
+}
+
+@end
diff --git a/cocoalumberjack/CHANGELOG.md b/cocoalumberjack/CHANGELOG.md
new file mode 100644
index 0000000..c3833dd
--- /dev/null
+++ b/cocoalumberjack/CHANGELOG.md
@@ -0,0 +1,274 @@
+## [2.2.0 - TVOS, Xcode7.1 on Oct 28th, 2015](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.2.0)
+- added `tvOS` support (thanks [@sinoru](https://github.com/sinoru)) - [#634](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/634) [#640](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/640) [#630](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/630) [#628](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/628) [#618](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/618) [#611](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/611)
+- Remove `(escaping)` from the Swift `@autoclosure` parameters - [#642](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/642)
+
+## [2.1.0 - Swift 2.0, WatchOS, Xcode7 on Oct 23rd, 2015](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.1.0)
+- Fixed the version for the Carthage builds - see [#633](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/633)
+- Improved documentation
+
+## [2.1.0 RC - Swift 2.0, WatchOS, Xcode7 on Oct 22nd, 2015](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.1.0-rc)
+- Refactored the `NSDateFormatter` related code to fix a bunch of issues: [#621](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/621)
+- Fix Issue [#488](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/488): Support `DDLog` without `AppKit Dependency` (`#define DD_CLI`): [#627](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/627)
+- Re-add `NS_DESIGNATED_INITIALIZER` [#619](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/619)
+
+## [2.1.0 Beta - Swift 2.0, WatchOS, Xcode7 on Oct 12th, 2015](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.1.0-beta)
+- Updated the library to use Swift 2.0 and Xcode 7 [#617](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/617) [#545](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/545) [#534](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/534)
+- WatchOS support (2.0) [#583](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/583) [#581](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/581) [#579](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/579) 
+
+## [2.0.3 Patch for 2.0.0 on Oct 13th, 2015](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.0.3)
+
+- Compatibility with Xcode 6 that was broken by the 2.0.2 patch - [f042fd3](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/f042fd3)
+
+## [2.0.2 Patch for 2.0.0 on Oct 12th, 2015](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.0.2)
+
+- Swift 1.2 fixes [#546](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/546) [#578](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/578) plus and update to Swift 2.0 [5627dff](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/5627dff) imported from our swift_2.0 branch
+- Make build work on `tvOS` [#597](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/597) 
+- Make `CocoaLumberjackSwift-iOS` target depends on `CocoaLumberjack-iOS` [#575](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/575) 
+- `APPLICATION_EXTENSION_API_ONLY` to `YES` for Extensions [#576](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/576) 
+- Remove unnecessary `NS_DESIGNATED_INITIALIZER`s [#593](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/593) fixes [#592](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/592)  
+- Add ignore warning mark for `DDMakeColor` [#553](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/553) 
+- Kill unused function warnings from `DDTTYLogger.h` [#613](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/613) 
+- Flag unused parameters as being unused to silence strict warnings [#566](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/566) 
+- Extend ignore unused warning pragma to cover all platforms [#559](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/559) 
+- Removed images.xcassets from Mobile project [#580](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/580) 
+- Silence the Xcode 7 upgrade check - [#595](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/595) 
+- Fix import for when CL framework files are manually imported into project [#560](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/560) 
+- Don't override defines in case they're already set at project level [#551](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/551) 
+- log full filepath when failing to set attribute [#550](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/550) 
+- Fix issue in standalone build with `DDLegacyMacros.h` [#552](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/552) 
+- Update `CustomFormatters.md` with proper thread-safe blurb [#555](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/555) 
+- typo in parameter's variable name fixed [#568](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/568) 
+- Typo: minor fix [#571](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/571) 
+- Surely we should be adding 1, not 0 for `OSAtomicAdd32` ? [#587](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/587) 
+- `rollLogFileWithCompletionBlock` calls back on background queue instead of main queue [#589](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/589) 
+- Removing extraneous `\` on line 55 [#600](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/600) 
+- Updated `GettingStarted.md` to include `ddLogLevel` [#602](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/602) 
+- Remove redundant check for `processorCount` availability [#604](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/604) 
+
+## [2.0.1 Patch for 2.0.0 on Jun 25th, 2015](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.0.1)
+
+- **Carthage support** [#521](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/521) [#526](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/526) 
+- fixed crash on `DDASLLogCapture` when `TIME` or `TIME_NSEC` is `NULL` [#484](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/484) 
+- **Swift** fixes and improvements: [#483](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/483) [#509](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/509) [#518](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/518) [#522](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/522) [5eafceb](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/5eafceb)
+- Unit tests: [#500](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/500) [#498](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/498) [#499](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/499) 
+- Fix [#478](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/478) by reverting [#473](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/473) 
+- Add `armv7s` to static library [#538](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/538)
+- Fix `NSLog` `threadid` mismatch with iOS 8+/OSX 10.10+ [#514](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/514) 
+- Fixed the `LogV` macros so that avalist is no longer undefined [#511](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/511) 
+- Using type safe `DDColor` alias instead of #define directive [#506](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/506) 
+- Several fixes/tweaks to `DDASLLogCapture` [#512](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/512) 
+- Prevent duplicate log entries when both `DDASLLogCapture` and `DDASLLogger` are used [#515](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/515) 
+- Fix memory leaks in `DDTTYLogger`, add self annotations to blocks [#536](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/536) 
+- Update older syntax to modern subscripting for array access [#482](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/482) 
+- Remove execute permission on non-executable files [#517](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/517) 
+- Change code samples to use `DDLogFlagWarning` [#520](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/520) 
+- Fix seemingly obvious typo in the `toLogLevel` function [#508](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/508) 
+
+## [CocoaLumberjack 2.0.0 on Mar 13th, 2015](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.0.0)
+
+The library was strongly refactored, with a few goals in mind:
+- Swift support - that we will release in a separate milestone, since CocoaPods 0.36.0 just got out
+- Unit tests support
+- reorganised things (on disk)
+- better coding style
+
+See [Migration from 1.x to 2.x](https://github.com/CocoaLumberjack/CocoaLumberjack#migrating-to-2x)
+
+## [2.0.0-rc2 on Feb 20th, 2015](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.0.0-rc2)
+
+- Bucket of Swift improvements - [#434](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/434) [#437](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/437) [#449](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/449) [#440](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/440) 
+- Fixed [#433](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/433) (build issue due to dispatch_queue properties) - [#455](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/455) 
+- Enable codesign for iOS device framework builds - [#444](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/444)
+- Declare `automaticallyAppendNewlineForCustomFormatters` properties as `nonatomic` - [#443](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/443) 
+- Warning fixes & type standardization - [#419](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/419) 
+- Legacy checks updated - [#424](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/424) 
+- Documentation updates
+
+## [2.0.0-rc on Dec 11th, 2014](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.0.0-rc)
+
+- Fix `dispatch_queue_t` properties.
+- Fix `registeredClasses` crashes at launch.
+
+## [2.0.0-beta4 on Nov 7th, 2014](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.0.0-beta4)
+
+- Major refactoring and clean up.
+- Remove superfluous `log` from property names and use underscore for direct variable access.
+- Preliminar Swift support through `CocoaLumberjack.swift`.
+- Automatic 1.9.x legacy support when `DDLog.h` is imported instead of the new `CocoaLumberjack.h`.
+
+## [2.0.0-beta3 on Oct 21st, 2014](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.0.0-beta3)
+
+- Modernize flag variables to be `NS_OPTIONS`/`NS_ENUM`.
+- Change the log flags and levels to `NSUInteger`.
+- Fix warning when compiled with assertions blocked.
+- Crash fixes.
+
+## [2.0.0-beta2 on Sep 30th, 2014](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.0.0-beta2)
+
+- Cleanup code.
+- Match `NSLog` read UID functionality in `DDASLLogger`.
+- Update framework and static libraries.
+
+## [2.0.0 Beta on Aug 12th, 2014](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.0.0-beta)
+
+See [Migrate from 1.x to 2.x](https://github.com/CocoaLumberjack/CocoaLumberjack#migrating-to-2x)
+
+## [1.9.2 Updated patch release for 1.9.0 on Aug 11th, 2014](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.9.2)
+
+- Fixed `NSCalendar components:fromDate:` crash - [#140](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/140) [#307](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/307) [#216](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/216) 
+- New `DDAssert` macros - [#306](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/306) 
+- Limit log growth by disk space only, not the number of files - [#195](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/195) [#303](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/303) 
+- Change the mechanism for adding new line character (i.e. '\n\) to log messages in some logger - [#308](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/308) [#310](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/310) 
+- Fixed deprecations - [#320](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/320) [#312](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/312) [#317](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/317) 
+- `aslmsg` not freed and causing memory leak - [#314](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/314) 
+- Fixed `CompresingLogFileManager` compression bug - [#315](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/315) 
+- Remove unnecessary `NULL` check before `free()` - [#316](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/316) 
+
+## [1.9.1 Patch release for 1.9.0 on Jun 30th, 2014](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.9.1)
+
+- Fixed issues in rolling frequency - [#243](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/243) [#295](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/295) [@georgekola](https://github.com/georgekola)
+- Fixed critical issue, `addLogger` method should use a full bit mask instead of `LOG_LEVEL_VERBOSE`, otherwise extended logs or extra flags are ignored [fe6824c](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/fe6824c) [@robbiehanson](https://github.com/robbiehanson) 
+- Performance optimisation: use compiler macros to skip iOS version checks - [4656d3b](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/4656d3b) [#298](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/298) [#291](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/291) [@robbiehanson](https://github.com/robbiehanson) [@liviur](https://github.com/liviur)
+- Changed the `Build Active Architecture Only` to `NO` [#294](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/294) [#293](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/293) 
+- Optimisation by reusing `NSDateFormatter` instances [#296](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/296) [#301](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/301) 
+
+## [1.9.0 New ASL capture module, several File logger fixes on May 23rd, 2014](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.9.0)
+
+- New ASL capture module [#242](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/242) [#263](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/263) 
+- Override default `NSFileProtection` handling [#285](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/285) 
+- Replaced warnings when ARC was not enabled with errors [#284](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/284) 
+- Fix for issue [#278](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/278) where really large log files can keep growing [#280](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/280) 
+- Fixed Xcode warnings [#279](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/279) 
+- Update `calendarUnitFlags` with new iOS SDK values [#277](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/277) 
+- Fix possible crash in `[NSCalendar components:fromDate:]` [#277](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/277) 
+- Fix [#262](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/262) inverted ifs when renaming log [#264](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/264) 
+- Proper way of doing singletons (via `dispatch_once`) [#259](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/259) 
+- Explicitly declare `DDFileLogger` and `DDDispatchQueueLogFormatter ` properties as atomic to avoid Xcode warnings [#258](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/258)
+- Set `NSFileProtectionKey` on the temporary file created during compression [#256](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/256) 
+- Fix a rare crash in `CompressingLogFileManager` caused by an unchecked result from read [#255](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/255) 
+- Add explicit casts for integer conversion [#253](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/253) 
+- Replace use of `NSThread.detachNewThreadSelector` [#251](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/251) 
+- Add a constructor override for `initWithLogsDirectory:` [#252](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/252) 
+- Check and log the streamError whenever we fail to write during compression and log any failures when removing the original file or cleaning up the temporary file after compression failed [#250](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/250) 
+- Following Apple's guidelines for iOS Static Libraries [#249](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/249) 
+- Some extra warnings for the mobile framework xcode project [a2e5666](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/a2e5666)
+- Update `FineGrainedLoggingAppDelegate.m` [#244](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/244) 
+- New `[DDLog log:message:]` primitive [7f8af2e](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/7f8af2e)
+- Fixed issue [#181](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/181) when logging messages in iOS7 devices aren't properly retrieved by `asl_search` [#240](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/240) 
+- Allow prevention of log file reuse [#238](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/238) 
+- `DDTTYLogger`: Favour XcodeColors environment variable [#237](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/237) 
+- `DDLog`: calling `atexit_b` in CLI applications, that use Foundation framework [#234](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/234) 
+
+## [1.8.1 AllLoggers and bugfixes on Feb 14th, 2014](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.8.1)
+
+- read access to all loggers - [#217](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/217) [#219](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/219) 
+- fixed bug with archived logs not being handled correctly on iOS simulator - [#218](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/218) 
+- log the `strerror(errno)` value when `setxattr()` fails - [#211](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/211) 
+- Add a check for an archived log before overwriting - [#214](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/214) 
+- improved safety by using assertions instead of comments (`DDLog` in the core) - [#221](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/221) 
+- added Lumberjack logo :)
+
+## [1.8.0 Better CL support, custom logfile name format, bugfixes on Jan 21st, 2014](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.8.0)
+
+- `DDFileLogger` custom logfile (name) format - [#208](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/208) 
+- Security static analysis fix - [#202](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/202) 
+- `DDFileLogger`: using `CFBundleIdentifier` as a log filename prefix on OSX and iOS - [#206](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/206) 
+- Allow disabling of specific levels per-logger - [#204](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/204) 
+- Improve support for OS X command line tools - [#194](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/194) 
+- `DDFileLogger`: fixed crash that occurred in case if application name == nil - [#198](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/198) 
+- `DDFileLogger`: fixed comment - [#199](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/199) 
+- Fix Travis - [#205](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/205) 
+
+## [1.7.0 New log file naming convention and CocoaLumberjack organisation on Dec 10th, 2013](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.7.0)
+
+- new log file naming convention - [#191](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/191)
+- completed transition to **CocoaLumberjack** organisation - [#188](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/188)
+
+## [1.6.5.1 Patch release for Xcode 4.4+ compatibility on Dec 4th, 2013](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.6.5.1)
+
+- fixed compatibility with Xcode 4.4+ [#187](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/187)
+
+## [1.6.5 File Logger refactoring, Multi Formatter, preffixed extension classes on Dec 3rd, 2013](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.6.5)
+
+`DDFileLogger` refactoring and fixes (thanks [@dvor](https://github.com/dvor) and [@an0](https://github.com/an0)):
+- Fixed [#63](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/63) Loggers don't flush in Command Line Tool [#184](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/184) 
+- Fixed [#52](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/52) Force log rotation [#183](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/183)
+- Fixed [#55](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/55) After deleting log file or log dir they aren't created again without relaunching the app [#183](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/183)
+- Fixed [#129](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/129) [iOS] `DDFileLogger` causes crash when logging from background app [#183](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/183)
+- Fixed [#153](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/153) Log file on iPhone only contains a single line [#177](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/177)
+- Fixed [#155](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/155) How do I combine all my log levels into one file? [#177](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/177)
+- Fixed [#175](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/175) `DFileLogger` `creationDate` bug on 64-bit iOS system [#177](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/177)
+- Allow customizing the naming convention for log files to use timestamps [#174](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/174)
+
+Other:
+- Implemented multiple formatter (`DDMultiFormatter` - alows chaining of formatters) [#178](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/178)
+- Added DD preffix to extension classes (`ContextFilterLogFormatter` and `DispatchQueueLogFormatter`) [#178](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/178)
+- Updated code indentation: Tabs changed to spaces [#180](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/180)
+- Included `DDLog+LOGV.h` in Cocoapods sources [d253bd7](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/d253bd7)
+- other fixes/improvements
+
+## [1.6.4 Fix compatibility with 3rd party frameworks on Nov 21st, 2013](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.6.4)
+
+* "Fix" conflicts with 3rd party libraries using `CocoaLumberjack` [#172](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/172) 
+* Ignore deprecated warning for `dispatch_get_current_queue` [#167](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/167) 
+* Add new `DEBUG` log level support to included loggers [#166](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/166) 
+* Method declarations that make it easier to extend/modify `DispatchQueueLogFormatter` [#164](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/164) 
+
+## [1.6.3 New macros, updated podspec and bug fixes on Apr 2nd, 2013](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.6.3)
+
+* Add `LOGV`-style macros [#161](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/161) 
+* Fix getting queue's label [#159](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/159)  
+* New log level `DEBUG` [#145](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/145) 
+* Use `DISPATCH_CURRENT_QUEUE_LABEL` if available [#159](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/159) 
+* Different `logLevel` per each logger [#151](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/151) 
+* Created 2 subspecs, `Core` and `Extensions` [#152](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/152) 
+* Updated observer for keypath using `NSStringFromSelector` + `@selector` [38e5da3](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/38e5da3)
+* Replaced `id` return type with `instancetype` [ebee454](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/ebee454)
+* Remove implicit conversion warnings [#149](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/149) 
+* `DDTTYLogger`: Allow to set default color profiles for all contexts at once [#146](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/146) [#158](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/158) 
+* `DDTTYLogger`: By default apply `setForegroundColor:backgroundColor:forFlag:` to `LOG_CONTEXT_ALL` [#154](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/154) 
+* `DispatchQueueLogFormatter`: Use modern Objective-C [#142](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/142) 
+* `DispatchQueueLogFormatter`: Make sure to always use a `NSGregorianCalendar` for date formatter [#142](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/142) 
+* Replaced explicit reference to class name in `logFileWithPath` factory method [#131](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/131) 
+* Catch exceptions in `logMessage:` [#130](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/130) 
+* Fix enum type conversion warnings [#124](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/124) 
+* Add deployment target condition for workaround [#121](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/121) 
+* Fix static analyzer warnings about `nil` values in dictionary [#122](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/122) 
+* Fix `dispatch_get_current_queue` crash [#121](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/121) 
+* Fixing colors in greyscale color-space not working [d019cfd](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/d019cfd)
+* Guard around `dispatch_resume()` being called with null pointer [#107](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/107) 
+* `NULL` safety checks [#107](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/107)
+
+## [1.6.2 on Apr 2nd, 2013](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.6.2)
+
+## [1.6.1 on Apr 2nd, 2013](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.6.1)
+
+## [1.6 on Jul 3rd, 2012](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.6)
+
+## [1.5.1 on Jul 3rd, 2012](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.5.1)
+
+## [1.5 on Jul 3rd, 2012](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.5)
+
+## [1.4.1 on Jul 3rd, 2012](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.4.1)
+
+## [1.4 on Jul 3rd, 2012](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.4)
+
+## [1.3.3 on Mar 30th, 2012](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.3.3)
+
+## [1.3.2 on Dec 23rd, 2011](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.3.2)
+
+## [1.3.1 on Dec 9th, 2011](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.3.1)
+
+## [1.3 on Dec 9th, 2011](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.3)
+
+## [1.2.3 on Dec 9th, 2011](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.2.3)
+
+## [1.2.2 on Dec 9th, 2011](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.2.2)
+
+## [1.2.1 on Oct 13th, 2011](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.2.1)
+
+## [1.2 on Oct 13th, 2011](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.2)
+
+## [1.1 on Oct 13th, 2011](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.1)
+
+## [1.0 on Oct 13th, 2011](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.0)
diff --git a/cocoalumberjack/Classes/._CLI b/cocoalumberjack/Classes/._CLI
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/._CLI
Binary files differ
diff --git a/cocoalumberjack/Classes/._CocoaLumberjack.h b/cocoalumberjack/Classes/._CocoaLumberjack.h
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/._CocoaLumberjack.h
Binary files differ
diff --git a/cocoalumberjack/Classes/._CocoaLumberjack.swift b/cocoalumberjack/Classes/._CocoaLumberjack.swift
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/._CocoaLumberjack.swift
Binary files differ
diff --git a/cocoalumberjack/Classes/._DDASLLogCapture.h b/cocoalumberjack/Classes/._DDASLLogCapture.h
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/._DDASLLogCapture.h
Binary files differ
diff --git a/cocoalumberjack/Classes/._DDASLLogCapture.m b/cocoalumberjack/Classes/._DDASLLogCapture.m
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/._DDASLLogCapture.m
Binary files differ
diff --git a/cocoalumberjack/Classes/._DDASLLogger.h b/cocoalumberjack/Classes/._DDASLLogger.h
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/._DDASLLogger.h
Binary files differ
diff --git a/cocoalumberjack/Classes/._DDASLLogger.m b/cocoalumberjack/Classes/._DDASLLogger.m
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/._DDASLLogger.m
Binary files differ
diff --git a/cocoalumberjack/Classes/._DDAbstractDatabaseLogger.h b/cocoalumberjack/Classes/._DDAbstractDatabaseLogger.h
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/._DDAbstractDatabaseLogger.h
Binary files differ
diff --git a/cocoalumberjack/Classes/._DDAbstractDatabaseLogger.m b/cocoalumberjack/Classes/._DDAbstractDatabaseLogger.m
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/._DDAbstractDatabaseLogger.m
Binary files differ
diff --git a/cocoalumberjack/Classes/._DDAssertMacros.h b/cocoalumberjack/Classes/._DDAssertMacros.h
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/._DDAssertMacros.h
Binary files differ
diff --git a/cocoalumberjack/Classes/._DDFileLogger.h b/cocoalumberjack/Classes/._DDFileLogger.h
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/._DDFileLogger.h
Binary files differ
diff --git a/cocoalumberjack/Classes/._DDFileLogger.m b/cocoalumberjack/Classes/._DDFileLogger.m
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/._DDFileLogger.m
Binary files differ
diff --git a/cocoalumberjack/Classes/._DDLegacyMacros.h b/cocoalumberjack/Classes/._DDLegacyMacros.h
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/._DDLegacyMacros.h
Binary files differ
diff --git a/cocoalumberjack/Classes/._DDLog+LOGV.h b/cocoalumberjack/Classes/._DDLog+LOGV.h
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/._DDLog+LOGV.h
Binary files differ
diff --git a/cocoalumberjack/Classes/._DDLog.h b/cocoalumberjack/Classes/._DDLog.h
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/._DDLog.h
Binary files differ
diff --git a/cocoalumberjack/Classes/._DDLog.m b/cocoalumberjack/Classes/._DDLog.m
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/._DDLog.m
Binary files differ
diff --git a/cocoalumberjack/Classes/._DDLogMacros.h b/cocoalumberjack/Classes/._DDLogMacros.h
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/._DDLogMacros.h
Binary files differ
diff --git a/cocoalumberjack/Classes/._DDTTYLogger.h b/cocoalumberjack/Classes/._DDTTYLogger.h
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/._DDTTYLogger.h
Binary files differ
diff --git a/cocoalumberjack/Classes/._DDTTYLogger.m b/cocoalumberjack/Classes/._DDTTYLogger.m
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/._DDTTYLogger.m
Binary files differ
diff --git a/cocoalumberjack/Classes/._Extensions b/cocoalumberjack/Classes/._Extensions
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/._Extensions
Binary files differ
diff --git a/cocoalumberjack/Classes/CLI/._CLIColor.h b/cocoalumberjack/Classes/CLI/._CLIColor.h
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/CLI/._CLIColor.h
Binary files differ
diff --git a/cocoalumberjack/Classes/CLI/._CLIColor.m b/cocoalumberjack/Classes/CLI/._CLIColor.m
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/CLI/._CLIColor.m
Binary files differ
diff --git a/cocoalumberjack/Classes/CLI/CLIColor.h b/cocoalumberjack/Classes/CLI/CLIColor.h
new file mode 100644
index 0000000..cfa0909
--- /dev/null
+++ b/cocoalumberjack/Classes/CLI/CLIColor.h
@@ -0,0 +1,44 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+#import <Foundation/Foundation.h>
+#import <QuartzCore/QuartzCore.h>
+
+/**
+ * This class represents an NSColor replacement for CLI projects that don't link with AppKit
+ **/
+@interface CLIColor : NSObject
+
+/**
+ *  Convenience method for creating a `CLIColor` instance from RGBA params
+ *
+ *  @param red   red channel, between 0 and 1
+ *  @param green green channel, between 0 and 1
+ *  @param blue  blue channel, between 0 and 1
+ *  @param alpha alpha channel, between 0 and 1
+ */
++ (CLIColor *)colorWithCalibratedRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha;
+
+/**
+ *  Get the RGBA components from a `CLIColor`
+ *
+ *  @param red   red channel, between 0 and 1
+ *  @param green green channel, between 0 and 1
+ *  @param blue  blue channel, between 0 and 1
+ *  @param alpha alpha channel, between 0 and 1
+ */
+- (void)getRed:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue alpha:(CGFloat *)alpha;
+
+@end
diff --git a/cocoalumberjack/Classes/CLI/CLIColor.m b/cocoalumberjack/Classes/CLI/CLIColor.m
new file mode 100644
index 0000000..c952c18
--- /dev/null
+++ b/cocoalumberjack/Classes/CLI/CLIColor.m
@@ -0,0 +1,55 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+#import "CLIColor.h"
+
+@interface CLIColor () {
+    CGFloat _red, _green, _blue, _alpha;
+}
+
+@end
+
+
+@implementation CLIColor
+
++ (CLIColor *)colorWithCalibratedRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha {
+    CLIColor *color = [CLIColor new];
+
+    color->_red     = red;
+    color->_green   = green;
+    color->_blue    = blue;
+    color->_alpha   = alpha;
+    return color;
+}
+
+- (void)getRed:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue alpha:(CGFloat *)alpha {
+    if (red) {
+        *red    = _red;
+    }
+
+    if (green) {
+        *green  = _green;
+    }
+
+    if (blue) {
+        *blue   = _blue;
+    }
+
+    if (alpha) {
+        *alpha  = _alpha;
+    }
+}
+
+@end
diff --git a/cocoalumberjack/Classes/CocoaLumberjack.h b/cocoalumberjack/Classes/CocoaLumberjack.h
new file mode 100644
index 0000000..0b568fb
--- /dev/null
+++ b/cocoalumberjack/Classes/CocoaLumberjack.h
@@ -0,0 +1,81 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+/**
+ * Welcome to CocoaLumberjack!
+ *
+ * The project page has a wealth of documentation if you have any questions.
+ * https://github.com/CocoaLumberjack/CocoaLumberjack
+ *
+ * If you're new to the project you may wish to read "Getting Started" at:
+ * Documentation/GettingStarted.md
+ *
+ * Otherwise, here is a quick refresher.
+ * There are three steps to using the macros:
+ *
+ * Step 1:
+ * Import the header in your implementation or prefix file:
+ *
+ * #import <CocoaLumberjack/CocoaLumberjack.h>
+ *
+ * Step 2:
+ * Define your logging level in your implementation file:
+ *
+ * // Log levels: off, error, warn, info, verbose
+ * static const DDLogLevel ddLogLevel = DDLogLevelVerbose;
+ *
+ * Step 2 [3rd party frameworks]:
+ *
+ * Define your LOG_LEVEL_DEF to a different variable/function than ddLogLevel:
+ *
+ * // #undef LOG_LEVEL_DEF // Undefine first only if needed
+ * #define LOG_LEVEL_DEF myLibLogLevel
+ *
+ * Define your logging level in your implementation file:
+ *
+ * // Log levels: off, error, warn, info, verbose
+ * static const DDLogLevel myLibLogLevel = DDLogLevelVerbose;
+ *
+ * Step 3:
+ * Replace your NSLog statements with DDLog statements according to the severity of the message.
+ *
+ * NSLog(@"Fatal error, no dohickey found!"); -> DDLogError(@"Fatal error, no dohickey found!");
+ *
+ * DDLog works exactly the same as NSLog.
+ * This means you can pass it multiple variables just like NSLog.
+ **/
+
+#import <Foundation/Foundation.h>
+
+// Disable legacy macros
+#ifndef DD_LEGACY_MACROS
+    #define DD_LEGACY_MACROS 0
+#endif
+
+// Core
+#import "DDLog.h"
+
+// Main macros
+#import "DDLogMacros.h"
+#import "DDAssertMacros.h"
+
+// Capture ASL
+#import "DDASLLogCapture.h"
+
+// Loggers
+#import "DDTTYLogger.h"
+#import "DDASLLogger.h"
+#import "DDFileLogger.h"
+
diff --git a/cocoalumberjack/Classes/CocoaLumberjack.swift b/cocoalumberjack/Classes/CocoaLumberjack.swift
new file mode 100644
index 0000000..5f022ce
--- /dev/null
+++ b/cocoalumberjack/Classes/CocoaLumberjack.swift
@@ -0,0 +1,91 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2014-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+import Foundation
+
+extension DDLogFlag {
+    public static func fromLogLevel(logLevel: DDLogLevel) -> DDLogFlag {
+        return DDLogFlag(rawValue: logLevel.rawValue)
+    }
+	
+	public init(_ logLevel: DDLogLevel) {
+        self = DDLogFlag(rawValue: logLevel.rawValue)
+	}
+    
+    ///returns the log level, or the lowest equivalant.
+    public func toLogLevel() -> DDLogLevel {
+        if let ourValid = DDLogLevel(rawValue: self.rawValue) {
+            return ourValid
+        } else {
+            let logFlag:DDLogFlag = self
+            
+            if logFlag.contains(.Verbose) {
+                return .Verbose
+            } else if logFlag.contains(.Debug) {
+                return .Debug
+            } else if logFlag.contains(.Info) {
+                return .Info
+            } else if logFlag.contains(.Warning) {
+                return .Warning
+            } else if logFlag.contains(.Error) {
+                return .Error
+            } else {
+                return .Off
+            }
+        }
+    }
+}
+
+public var defaultDebugLevel = DDLogLevel.Verbose
+
+public func resetDefaultDebugLevel() {
+    defaultDebugLevel = DDLogLevel.Verbose
+}
+
+public func SwiftLogMacro(isAsynchronous: Bool, level: DDLogLevel, flag flg: DDLogFlag, context: Int = 0, file: StaticString = __FILE__, function: StaticString = __FUNCTION__, line: UInt = __LINE__, tag: AnyObject? = nil, @autoclosure string: () -> String) {
+    if level.rawValue & flg.rawValue != 0 {
+        // Tell the DDLogMessage constructor to copy the C strings that get passed to it.
+        // Using string interpolation to prevent integer overflow warning when using StaticString.stringValue
+        let logMessage = DDLogMessage(message: string(), level: level, flag: flg, context: context, file: "\(file)", function: "\(function)", line: line, tag: tag, options: [.CopyFile, .CopyFunction], timestamp: nil)
+        DDLog.log(isAsynchronous, message: logMessage)
+    }
+}
+
+public func DDLogDebug(@autoclosure logText: () -> String, level: DDLogLevel = defaultDebugLevel, context: Int = 0, file: StaticString = __FILE__, function: StaticString = __FUNCTION__, line: UInt = __LINE__, tag: AnyObject? = nil, asynchronous async: Bool = true) {
+    SwiftLogMacro(async, level: level, flag: .Debug, context: context, file: file, function: function, line: line, tag: tag, string: logText)
+}
+
+public func DDLogInfo(@autoclosure logText: () -> String, level: DDLogLevel = defaultDebugLevel, context: Int = 0, file: StaticString = __FILE__, function: StaticString = __FUNCTION__, line: UInt = __LINE__, tag: AnyObject? = nil, asynchronous async: Bool = true) {
+    SwiftLogMacro(async, level: level, flag: .Info, context: context, file: file, function: function, line: line, tag: tag, string: logText)
+}
+
+public func DDLogWarn(@autoclosure logText: () -> String, level: DDLogLevel = defaultDebugLevel, context: Int = 0, file: StaticString = __FILE__, function: StaticString = __FUNCTION__, line: UInt = __LINE__, tag: AnyObject? = nil, asynchronous async: Bool = true) {
+    SwiftLogMacro(async, level: level, flag: .Warning, context: context, file: file, function: function, line: line, tag: tag, string: logText)
+}
+
+public func DDLogVerbose(@autoclosure logText: () -> String, level: DDLogLevel = defaultDebugLevel, context: Int = 0, file: StaticString = __FILE__, function: StaticString = __FUNCTION__, line: UInt = __LINE__, tag: AnyObject? = nil, asynchronous async: Bool = true) {
+    SwiftLogMacro(async, level: level, flag: .Verbose, context: context, file: file, function: function, line: line, tag: tag, string: logText)
+}
+
+public func DDLogError(@autoclosure logText: () -> String, level: DDLogLevel = defaultDebugLevel, context: Int = 0, file: StaticString = __FILE__, function: StaticString = __FUNCTION__, line: UInt = __LINE__, tag: AnyObject? = nil, asynchronous async: Bool = false) {
+    SwiftLogMacro(async, level: level, flag: .Error, context: context, file: file, function: function, line: line, tag: tag, string: logText)
+}
+
+/// Analogous to the C preprocessor macro `THIS_FILE`.
+public func CurrentFileName(fileName: StaticString = __FILE__) -> String {
+    // Using string interpolation to prevent integer overflow warning when using StaticString.stringValue
+    // This double-casting to NSString is necessary as changes to how Swift handles NSPathUtilities requres the string to be an NSString
+    return (("\(fileName)" as NSString).lastPathComponent as NSString).stringByDeletingPathExtension
+}
diff --git a/cocoalumberjack/Classes/DDASLLogCapture.h b/cocoalumberjack/Classes/DDASLLogCapture.h
new file mode 100644
index 0000000..f7fa79f
--- /dev/null
+++ b/cocoalumberjack/Classes/DDASLLogCapture.h
@@ -0,0 +1,48 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+#import "DDASLLogger.h"
+
+@protocol DDLogger;
+
+/**
+ *  This class provides the ability to capture the ASL (Apple System Logs)
+ */
+@interface DDASLLogCapture : NSObject
+
+/**
+ *  Start capturing logs
+ */
++ (void)start;
+
+/**
+ *  Stop capturing logs
+ */
++ (void)stop;
+
+/**
+ *  Returns the current capture level.
+ *  @note Default log level: DDLogLevelVerbose (i.e. capture all ASL messages).
+ */
++ (DDLogLevel)captureLevel;
+
+/**
+ *  Set the capture level
+ *
+ *  @param level new level
+ */
++ (void)setCaptureLevel:(DDLogLevel)level;
+
+@end
diff --git a/cocoalumberjack/Classes/DDASLLogCapture.m b/cocoalumberjack/Classes/DDASLLogCapture.m
new file mode 100644
index 0000000..98d5342
--- /dev/null
+++ b/cocoalumberjack/Classes/DDASLLogCapture.m
@@ -0,0 +1,230 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+#import "DDASLLogCapture.h"
+
+// Disable legacy macros
+#ifndef DD_LEGACY_MACROS
+    #define DD_LEGACY_MACROS 0
+#endif
+
+#import "DDLog.h"
+
+#include <asl.h>
+#include <notify.h>
+#include <notify_keys.h>
+#include <sys/time.h>
+
+static BOOL _cancel = YES;
+static DDLogLevel _captureLevel = DDLogLevelVerbose;
+
+#ifdef __IPHONE_8_0
+    #define DDASL_IOS_PIVOT_VERSION __IPHONE_8_0
+#endif
+#ifdef __MAC_10_10
+    #define DDASL_OSX_PIVOT_VERSION __MAC_10_10
+#endif
+
+@implementation DDASLLogCapture
+
+static aslmsg (*dd_asl_next)(aslresponse obj);
+static void (*dd_asl_release)(aslresponse obj);
+
++ (void)initialize
+{
+    #if (defined(DDASL_IOS_PIVOT_VERSION) && __IPHONE_OS_VERSION_MAX_ALLOWED >= DDASL_IOS_PIVOT_VERSION) || (defined(DDASL_OSX_PIVOT_VERSION) && __MAC_OS_X_VERSION_MAX_ALLOWED >= DDASL_OSX_PIVOT_VERSION)
+        #if __IPHONE_OS_VERSION_MIN_REQUIRED < DDASL_IOS_PIVOT_VERSION || __MAC_OS_X_VERSION_MIN_REQUIRED < DDASL_OSX_PIVOT_VERSION
+            #pragma GCC diagnostic push
+            #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+                // Building on falsely advertised SDK, targeting deprecated API
+                dd_asl_next    = &aslresponse_next;
+                dd_asl_release = &aslresponse_free;
+            #pragma GCC diagnostic pop
+        #else
+            // Building on lastest, correct SDK, targeting latest API
+            dd_asl_next    = &asl_next;
+            dd_asl_release = &asl_release;
+        #endif
+    #else
+        // Building on old SDKs, targeting deprecated API
+        dd_asl_next    = &aslresponse_next;
+        dd_asl_release = &aslresponse_free;
+    #endif
+}
+
++ (void)start {
+    // Ignore subsequent calls
+    if (!_cancel) {
+        return;
+    }
+    
+    _cancel = NO;
+    
+    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
+        [self captureAslLogs];
+    });
+}
+
++ (void)stop {
+    _cancel = YES;
+}
+
++ (DDLogLevel)captureLevel {
+    return _captureLevel;
+}
+
++ (void)setCaptureLevel:(DDLogLevel)level {
+    _captureLevel = level;
+}
+
+#pragma mark - Private methods
+
++ (void)configureAslQuery:(aslmsg)query {
+    const char param[] = "7";  // ASL_LEVEL_DEBUG, which is everything. We'll rely on regular DDlog log level to filter
+    
+    asl_set_query(query, ASL_KEY_LEVEL, param, ASL_QUERY_OP_LESS_EQUAL | ASL_QUERY_OP_NUMERIC);
+
+    // Don't retrieve logs from our own DDASLLogger
+    asl_set_query(query, kDDASLKeyDDLog, kDDASLDDLogValue, ASL_QUERY_OP_NOT_EQUAL);
+    
+#if !TARGET_OS_IPHONE || TARGET_SIMULATOR
+    int processId = [[NSProcessInfo processInfo] processIdentifier];
+    char pid[16];
+    sprintf(pid, "%d", processId);
+    asl_set_query(query, ASL_KEY_PID, pid, ASL_QUERY_OP_EQUAL | ASL_QUERY_OP_NUMERIC);
+#endif
+}
+
++ (void)aslMessageReceived:(aslmsg)msg {
+    const char* messageCString = asl_get( msg, ASL_KEY_MSG );
+    if ( messageCString == NULL )
+        return;
+
+    int flag;
+    BOOL async;
+
+    const char* levelCString = asl_get(msg, ASL_KEY_LEVEL);
+    switch (levelCString? atoi(levelCString) : 0) {
+        // By default all NSLog's with a ASL_LEVEL_WARNING level
+        case ASL_LEVEL_EMERG    :
+        case ASL_LEVEL_ALERT    :
+        case ASL_LEVEL_CRIT     : flag = DDLogFlagError;    async = NO;  break;
+        case ASL_LEVEL_ERR      : flag = DDLogFlagWarning;  async = YES; break;
+        case ASL_LEVEL_WARNING  : flag = DDLogFlagInfo;     async = YES; break;
+        case ASL_LEVEL_NOTICE   : flag = DDLogFlagDebug;    async = YES; break;
+        case ASL_LEVEL_INFO     :
+        case ASL_LEVEL_DEBUG    :
+        default                 : flag = DDLogFlagVerbose;  async = YES;  break;
+    }
+
+    if (!(_captureLevel & flag)) {
+        return;
+    }
+
+    //  NSString * sender = [NSString stringWithCString:asl_get(msg, ASL_KEY_SENDER) encoding:NSUTF8StringEncoding];
+    NSString *message = @(messageCString);
+
+    const char* secondsCString = asl_get( msg, ASL_KEY_TIME );
+    const char* nanoCString = asl_get( msg, ASL_KEY_TIME_NSEC );
+    NSTimeInterval seconds = secondsCString ? strtod(secondsCString, NULL) : [NSDate timeIntervalSinceReferenceDate] - NSTimeIntervalSince1970;
+    double nanoSeconds = nanoCString? strtod(nanoCString, NULL) : 0;
+    NSTimeInterval totalSeconds = seconds + (nanoSeconds / 1e9);
+
+    NSDate *timeStamp = [NSDate dateWithTimeIntervalSince1970:totalSeconds];
+
+    DDLogMessage *logMessage = [[DDLogMessage alloc]initWithMessage:message
+                                                              level:_captureLevel
+                                                               flag:flag
+                                                            context:0
+                                                               file:@"DDASLLogCapture"
+                                                           function:0
+                                                               line:0
+                                                                tag:nil
+                                                            options:0
+                                                          timestamp:timeStamp];
+    
+    [DDLog log:async message:logMessage];
+}
+
++ (void)captureAslLogs {
+    @autoreleasepool
+    {
+        /*
+           We use ASL_KEY_MSG_ID to see each message once, but there's no
+           obvious way to get the "next" ID. To bootstrap the process, we'll
+           search by timestamp until we've seen a message.
+         */
+
+        struct timeval timeval = {
+            .tv_sec = 0
+        };
+        gettimeofday(&timeval, NULL);
+        unsigned long long startTime = timeval.tv_sec;
+        __block unsigned long long lastSeenID = 0;
+
+        /*
+           syslogd posts kNotifyASLDBUpdate (com.apple.system.logger.message)
+           through the notify API when it saves messages to the ASL database.
+           There is some coalescing - currently it is sent at most twice per
+           second - but there is no documented guarantee about this. In any
+           case, there may be multiple messages per notification.
+
+           Notify notifications don't carry any payload, so we need to search
+           for the messages.
+         */
+        int notifyToken = 0;  // Can be used to unregister with notify_cancel().
+        notify_register_dispatch(kNotifyASLDBUpdate, &notifyToken, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(int token)
+        {
+            // At least one message has been posted; build a search query.
+            @autoreleasepool
+            {
+                aslmsg query = asl_new(ASL_TYPE_QUERY);
+                char stringValue[64];
+
+                if (lastSeenID > 0) {
+                    snprintf(stringValue, sizeof stringValue, "%llu", lastSeenID);
+                    asl_set_query(query, ASL_KEY_MSG_ID, stringValue, ASL_QUERY_OP_GREATER | ASL_QUERY_OP_NUMERIC);
+                } else {
+                    snprintf(stringValue, sizeof stringValue, "%llu", startTime);
+                    asl_set_query(query, ASL_KEY_TIME, stringValue, ASL_QUERY_OP_GREATER_EQUAL | ASL_QUERY_OP_NUMERIC);
+                }
+
+                [self configureAslQuery:query];
+
+                // Iterate over new messages.
+                aslmsg msg;
+                aslresponse response = asl_search(NULL, query);
+                
+                while ((msg = dd_asl_next(response)))
+                {
+                    [self aslMessageReceived:msg];
+
+                    // Keep track of which messages we've seen.
+                    lastSeenID = atoll(asl_get(msg, ASL_KEY_MSG_ID));
+                }
+                dd_asl_release(response);
+                asl_free(query);
+
+                if (_cancel) {
+                    notify_cancel(token);
+                    return;
+                }
+
+            }
+        });
+    }
+}
+
+@end
diff --git a/cocoalumberjack/Classes/DDASLLogger.h b/cocoalumberjack/Classes/DDASLLogger.h
new file mode 100644
index 0000000..24cc1c3
--- /dev/null
+++ b/cocoalumberjack/Classes/DDASLLogger.h
@@ -0,0 +1,58 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+#import <Foundation/Foundation.h>
+
+// Disable legacy macros
+#ifndef DD_LEGACY_MACROS
+    #define DD_LEGACY_MACROS 0
+#endif
+
+#import "DDLog.h"
+
+// Custom key set on messages sent to ASL
+extern const char* const kDDASLKeyDDLog;
+
+// Value set for kDDASLKeyDDLog
+extern const char* const kDDASLDDLogValue;
+
+/**
+ * This class provides a logger for the Apple System Log facility.
+ *
+ * As described in the "Getting Started" page,
+ * the traditional NSLog() function directs its output to two places:
+ *
+ * - Apple System Log
+ * - StdErr (if stderr is a TTY) so log statements show up in Xcode console
+ *
+ * To duplicate NSLog() functionality you can simply add this logger and a tty logger.
+ * However, if you instead choose to use file logging (for faster performance),
+ * you may choose to use a file logger and a tty logger.
+ **/
+@interface DDASLLogger : DDAbstractLogger <DDLogger>
+
+/**
+ *  Singleton method
+ *
+ *  @return the shared instance
+ */
++ (instancetype)sharedInstance;
+
+// Inherited from DDAbstractLogger
+
+// - (id <DDLogFormatter>)logFormatter;
+// - (void)setLogFormatter:(id <DDLogFormatter>)formatter;
+
+@end
diff --git a/cocoalumberjack/Classes/DDASLLogger.m b/cocoalumberjack/Classes/DDASLLogger.m
new file mode 100644
index 0000000..edce218
--- /dev/null
+++ b/cocoalumberjack/Classes/DDASLLogger.m
@@ -0,0 +1,121 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+#import "DDASLLogger.h"
+#import <asl.h>
+
+#if !__has_feature(objc_arc)
+#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
+#endif
+
+const char* const kDDASLKeyDDLog = "DDLog";
+
+const char* const kDDASLDDLogValue = "1";
+
+static DDASLLogger *sharedInstance;
+
+@interface DDASLLogger () {
+    aslclient _client;
+}
+
+@end
+
+
+@implementation DDASLLogger
+
++ (instancetype)sharedInstance {
+    static dispatch_once_t DDASLLoggerOnceToken;
+
+    dispatch_once(&DDASLLoggerOnceToken, ^{
+        sharedInstance = [[[self class] alloc] init];
+    });
+
+    return sharedInstance;
+}
+
+- (instancetype)init {
+    if (sharedInstance != nil) {
+        return nil;
+    }
+
+    if ((self = [super init])) {
+        // A default asl client is provided for the main thread,
+        // but background threads need to create their own client.
+
+        _client = asl_open(NULL, "com.apple.console", 0);
+    }
+
+    return self;
+}
+
+- (void)logMessage:(DDLogMessage *)logMessage {
+    // Skip captured log messages
+    if ([logMessage->_fileName isEqualToString:@"DDASLLogCapture"]) {
+        return;
+    }
+
+    NSString * message = _logFormatter ? [_logFormatter formatLogMessage:logMessage] : logMessage->_message;
+
+    if (message) {
+        const char *msg = [message UTF8String];
+
+        size_t aslLogLevel;
+        switch (logMessage->_flag) {
+            // Note: By default ASL will filter anything above level 5 (Notice).
+            // So our mappings shouldn't go above that level.
+            case DDLogFlagError     : aslLogLevel = ASL_LEVEL_CRIT;     break;
+            case DDLogFlagWarning   : aslLogLevel = ASL_LEVEL_ERR;      break;
+            case DDLogFlagInfo      : aslLogLevel = ASL_LEVEL_WARNING;  break; // Regular NSLog's level
+            case DDLogFlagDebug     :
+            case DDLogFlagVerbose   :
+            default                 : aslLogLevel = ASL_LEVEL_NOTICE;   break;
+        }
+
+        static char const *const level_strings[] = { "0", "1", "2", "3", "4", "5", "6", "7" };
+
+        // NSLog uses the current euid to set the ASL_KEY_READ_UID.
+        uid_t const readUID = geteuid();
+
+        char readUIDString[16];
+#ifndef NS_BLOCK_ASSERTIONS
+        int l = snprintf(readUIDString, sizeof(readUIDString), "%d", readUID);
+#else
+        snprintf(readUIDString, sizeof(readUIDString), "%d", readUID);
+#endif
+
+        NSAssert(l < sizeof(readUIDString),
+                 @"Formatted euid is too long.");
+        NSAssert(aslLogLevel < (sizeof(level_strings) / sizeof(level_strings[0])),
+                 @"Unhandled ASL log level.");
+
+        aslmsg m = asl_new(ASL_TYPE_MSG);
+        if (m != NULL) {
+            if (asl_set(m, ASL_KEY_LEVEL, level_strings[aslLogLevel]) == 0 &&
+                asl_set(m, ASL_KEY_MSG, msg) == 0 &&
+                asl_set(m, ASL_KEY_READ_UID, readUIDString) == 0 &&
+                asl_set(m, kDDASLKeyDDLog, kDDASLDDLogValue) == 0) {
+                asl_send(_client, m);
+            }
+            asl_free(m);
+        }
+        //TODO handle asl_* failures non-silently?
+    }
+}
+
+- (NSString *)loggerName {
+    return @"cocoa.lumberjack.aslLogger";
+}
+
+@end
diff --git a/cocoalumberjack/Classes/DDAbstractDatabaseLogger.h b/cocoalumberjack/Classes/DDAbstractDatabaseLogger.h
new file mode 100644
index 0000000..aad3666
--- /dev/null
+++ b/cocoalumberjack/Classes/DDAbstractDatabaseLogger.h
@@ -0,0 +1,123 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+// Disable legacy macros
+#ifndef DD_LEGACY_MACROS
+    #define DD_LEGACY_MACROS 0
+#endif
+
+#import "DDLog.h"
+
+/**
+ * This class provides an abstract implementation of a database logger.
+ *
+ * That is, it provides the base implementation for a database logger to build atop of.
+ * All that is needed for a concrete database logger is to extend this class
+ * and override the methods in the implementation file that are prefixed with "db_".
+ **/
+@interface DDAbstractDatabaseLogger : DDAbstractLogger {
+    
+@protected
+    NSUInteger _saveThreshold;
+    NSTimeInterval _saveInterval;
+    NSTimeInterval _maxAge;
+    NSTimeInterval _deleteInterval;
+    BOOL _deleteOnEverySave;
+    
+    BOOL _saveTimerSuspended;
+    NSUInteger _unsavedCount;
+    dispatch_time_t _unsavedTime;
+    dispatch_source_t _saveTimer;
+    dispatch_time_t _lastDeleteTime;
+    dispatch_source_t _deleteTimer;
+}
+
+/**
+ * Specifies how often to save the data to disk.
+ * Since saving is an expensive operation (disk io) it is not done after every log statement.
+ * These properties allow you to configure how/when the logger saves to disk.
+ *
+ * A save is done when either (whichever happens first):
+ *
+ * - The number of unsaved log entries reaches saveThreshold
+ * - The amount of time since the oldest unsaved log entry was created reaches saveInterval
+ *
+ * You can optionally disable the saveThreshold by setting it to zero.
+ * If you disable the saveThreshold you are entirely dependent on the saveInterval.
+ *
+ * You can optionally disable the saveInterval by setting it to zero (or a negative value).
+ * If you disable the saveInterval you are entirely dependent on the saveThreshold.
+ *
+ * It's not wise to disable both saveThreshold and saveInterval.
+ *
+ * The default saveThreshold is 500.
+ * The default saveInterval is 60 seconds.
+ **/
+@property (assign, readwrite) NSUInteger saveThreshold;
+
+/**
+ *  See the description for the `saveThreshold` property
+ */
+@property (assign, readwrite) NSTimeInterval saveInterval;
+
+/**
+ * It is likely you don't want the log entries to persist forever.
+ * Doing so would allow the database to grow infinitely large over time.
+ *
+ * The maxAge property provides a way to specify how old a log statement can get
+ * before it should get deleted from the database.
+ *
+ * The deleteInterval specifies how often to sweep for old log entries.
+ * Since deleting is an expensive operation (disk io) is is done on a fixed interval.
+ *
+ * An alternative to the deleteInterval is the deleteOnEverySave option.
+ * This specifies that old log entries should be deleted during every save operation.
+ *
+ * You can optionally disable the maxAge by setting it to zero (or a negative value).
+ * If you disable the maxAge then old log statements are not deleted.
+ *
+ * You can optionally disable the deleteInterval by setting it to zero (or a negative value).
+ *
+ * If you disable both deleteInterval and deleteOnEverySave then old log statements are not deleted.
+ *
+ * It's not wise to enable both deleteInterval and deleteOnEverySave.
+ *
+ * The default maxAge is 7 days.
+ * The default deleteInterval is 5 minutes.
+ * The default deleteOnEverySave is NO.
+ **/
+@property (assign, readwrite) NSTimeInterval maxAge;
+
+/**
+ *  See the description for the `maxAge` property
+ */
+@property (assign, readwrite) NSTimeInterval deleteInterval;
+
+/**
+ *  See the description for the `maxAge` property
+ */
+@property (assign, readwrite) BOOL deleteOnEverySave;
+
+/**
+ * Forces a save of any pending log entries (flushes log entries to disk).
+ **/
+- (void)savePendingLogEntries;
+
+/**
+ * Removes any log entries that are older than maxAge.
+ **/
+- (void)deleteOldLogEntries;
+
+@end
diff --git a/cocoalumberjack/Classes/DDAbstractDatabaseLogger.m b/cocoalumberjack/Classes/DDAbstractDatabaseLogger.m
new file mode 100644
index 0000000..c8782de
--- /dev/null
+++ b/cocoalumberjack/Classes/DDAbstractDatabaseLogger.m
@@ -0,0 +1,660 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+#import "DDAbstractDatabaseLogger.h"
+#import <math.h>
+
+
+#if !__has_feature(objc_arc)
+#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
+#endif
+
+@interface DDAbstractDatabaseLogger ()
+
+- (void)destroySaveTimer;
+- (void)destroyDeleteTimer;
+
+@end
+
+#pragma mark -
+
+@implementation DDAbstractDatabaseLogger
+
+- (instancetype)init {
+    if ((self = [super init])) {
+        _saveThreshold = 500;
+        _saveInterval = 60;           // 60 seconds
+        _maxAge = (60 * 60 * 24 * 7); //  7 days
+        _deleteInterval = (60 * 5);   //  5 minutes
+    }
+
+    return self;
+}
+
+- (void)dealloc {
+    [self destroySaveTimer];
+    [self destroyDeleteTimer];
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Override Me
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+- (BOOL)db_log:(DDLogMessage *)logMessage {
+    // Override me and add your implementation.
+    //
+    // Return YES if an item was added to the buffer.
+    // Return NO if the logMessage was ignored.
+
+    return NO;
+}
+
+- (void)db_save {
+    // Override me and add your implementation.
+}
+
+- (void)db_delete {
+    // Override me and add your implementation.
+}
+
+- (void)db_saveAndDelete {
+    // Override me and add your implementation.
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Private API
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+- (void)performSaveAndSuspendSaveTimer {
+    if (_unsavedCount > 0) {
+        if (_deleteOnEverySave) {
+            [self db_saveAndDelete];
+        } else {
+            [self db_save];
+        }
+    }
+
+    _unsavedCount = 0;
+    _unsavedTime = 0;
+
+    if (_saveTimer && !_saveTimerSuspended) {
+        dispatch_suspend(_saveTimer);
+        _saveTimerSuspended = YES;
+    }
+}
+
+- (void)performDelete {
+    if (_maxAge > 0.0) {
+        [self db_delete];
+
+        _lastDeleteTime = dispatch_time(DISPATCH_TIME_NOW, 0);
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Timers
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+- (void)destroySaveTimer {
+    if (_saveTimer) {
+        dispatch_source_cancel(_saveTimer);
+
+        if (_saveTimerSuspended) {
+            // Must resume a timer before releasing it (or it will crash)
+            dispatch_resume(_saveTimer);
+            _saveTimerSuspended = NO;
+        }
+
+        #if !OS_OBJECT_USE_OBJC
+        dispatch_release(_saveTimer);
+        #endif
+        _saveTimer = NULL;
+    }
+}
+
+- (void)updateAndResumeSaveTimer {
+    if ((_saveTimer != NULL) && (_saveInterval > 0.0) && (_unsavedTime > 0.0)) {
+        uint64_t interval = (uint64_t)(_saveInterval * NSEC_PER_SEC);
+        dispatch_time_t startTime = dispatch_time(_unsavedTime, interval);
+
+        dispatch_source_set_timer(_saveTimer, startTime, interval, 1.0);
+
+        if (_saveTimerSuspended) {
+            dispatch_resume(_saveTimer);
+            _saveTimerSuspended = NO;
+        }
+    }
+}
+
+- (void)createSuspendedSaveTimer {
+    if ((_saveTimer == NULL) && (_saveInterval > 0.0)) {
+        _saveTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.loggerQueue);
+
+        dispatch_source_set_event_handler(_saveTimer, ^{ @autoreleasepool {
+                                                            [self performSaveAndSuspendSaveTimer];
+                                                        } });
+
+        _saveTimerSuspended = YES;
+    }
+}
+
+- (void)destroyDeleteTimer {
+    if (_deleteTimer) {
+        dispatch_source_cancel(_deleteTimer);
+        #if !OS_OBJECT_USE_OBJC
+        dispatch_release(_deleteTimer);
+        #endif
+        _deleteTimer = NULL;
+    }
+}
+
+- (void)updateDeleteTimer {
+    if ((_deleteTimer != NULL) && (_deleteInterval > 0.0) && (_maxAge > 0.0)) {
+        uint64_t interval = (uint64_t)(_deleteInterval * NSEC_PER_SEC);
+        dispatch_time_t startTime;
+
+        if (_lastDeleteTime > 0) {
+            startTime = dispatch_time(_lastDeleteTime, interval);
+        } else {
+            startTime = dispatch_time(DISPATCH_TIME_NOW, interval);
+        }
+
+        dispatch_source_set_timer(_deleteTimer, startTime, interval, 1.0);
+    }
+}
+
+- (void)createAndStartDeleteTimer {
+    if ((_deleteTimer == NULL) && (_deleteInterval > 0.0) && (_maxAge > 0.0)) {
+        _deleteTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.loggerQueue);
+
+        if (_deleteTimer != NULL) {
+            dispatch_source_set_event_handler(_deleteTimer, ^{ @autoreleasepool {
+                                                                  [self performDelete];
+                                                              } });
+
+            [self updateDeleteTimer];
+
+            if (_deleteTimer != NULL) {
+                dispatch_resume(_deleteTimer);
+            }
+        }
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Configuration
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+- (NSUInteger)saveThreshold {
+    // The design of this method is taken from the DDAbstractLogger implementation.
+    // For extensive documentation please refer to the DDAbstractLogger implementation.
+
+    // Note: The internal implementation MUST access the colorsEnabled variable directly,
+    // This method is designed explicitly for external access.
+    //
+    // Using "self." syntax to go through this method will cause immediate deadlock.
+    // This is the intended result. Fix it by accessing the ivar directly.
+    // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
+
+    NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+    NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
+
+    dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+
+    __block NSUInteger result;
+
+    dispatch_sync(globalLoggingQueue, ^{
+        dispatch_sync(self.loggerQueue, ^{
+            result = _saveThreshold;
+        });
+    });
+
+    return result;
+}
+
+- (void)setSaveThreshold:(NSUInteger)threshold {
+    dispatch_block_t block = ^{
+        @autoreleasepool {
+            if (_saveThreshold != threshold) {
+                _saveThreshold = threshold;
+
+                // Since the saveThreshold has changed,
+                // we check to see if the current unsavedCount has surpassed the new threshold.
+                //
+                // If it has, we immediately save the log.
+
+                if ((_unsavedCount >= _saveThreshold) && (_saveThreshold > 0)) {
+                    [self performSaveAndSuspendSaveTimer];
+                }
+            }
+        }
+    };
+
+    // The design of the setter logic below is taken from the DDAbstractLogger implementation.
+    // For documentation please refer to the DDAbstractLogger implementation.
+
+    if ([self isOnInternalLoggerQueue]) {
+        block();
+    } else {
+        dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+        NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+
+        dispatch_async(globalLoggingQueue, ^{
+            dispatch_async(self.loggerQueue, block);
+        });
+    }
+}
+
+- (NSTimeInterval)saveInterval {
+    // The design of this method is taken from the DDAbstractLogger implementation.
+    // For extensive documentation please refer to the DDAbstractLogger implementation.
+
+    // Note: The internal implementation MUST access the colorsEnabled variable directly,
+    // This method is designed explicitly for external access.
+    //
+    // Using "self." syntax to go through this method will cause immediate deadlock.
+    // This is the intended result. Fix it by accessing the ivar directly.
+    // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
+
+    NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+    NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
+
+    dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+
+    __block NSTimeInterval result;
+
+    dispatch_sync(globalLoggingQueue, ^{
+        dispatch_sync(self.loggerQueue, ^{
+            result = _saveInterval;
+        });
+    });
+
+    return result;
+}
+
+- (void)setSaveInterval:(NSTimeInterval)interval {
+    dispatch_block_t block = ^{
+        @autoreleasepool {
+            // C99 recommended floating point comparison macro
+            // Read: isLessThanOrGreaterThan(floatA, floatB)
+
+            if (/* saveInterval != interval */ islessgreater(_saveInterval, interval)) {
+                _saveInterval = interval;
+
+                // There are several cases we need to handle here.
+                //
+                // 1. If the saveInterval was previously enabled and it just got disabled,
+                //    then we need to stop the saveTimer. (And we might as well release it.)
+                //
+                // 2. If the saveInterval was previously disabled and it just got enabled,
+                //    then we need to setup the saveTimer. (Plus we might need to do an immediate save.)
+                //
+                // 3. If the saveInterval increased, then we need to reset the timer so that it fires at the later date.
+                //
+                // 4. If the saveInterval decreased, then we need to reset the timer so that it fires at an earlier date.
+                //    (Plus we might need to do an immediate save.)
+
+                if (_saveInterval > 0.0) {
+                    if (_saveTimer == NULL) {
+                        // Handles #2
+                        //
+                        // Since the saveTimer uses the unsavedTime to calculate it's first fireDate,
+                        // if a save is needed the timer will fire immediately.
+
+                        [self createSuspendedSaveTimer];
+                        [self updateAndResumeSaveTimer];
+                    } else {
+                        // Handles #3
+                        // Handles #4
+                        //
+                        // Since the saveTimer uses the unsavedTime to calculate it's first fireDate,
+                        // if a save is needed the timer will fire immediately.
+
+                        [self updateAndResumeSaveTimer];
+                    }
+                } else if (_saveTimer) {
+                    // Handles #1
+
+                    [self destroySaveTimer];
+                }
+            }
+        }
+    };
+
+    // The design of the setter logic below is taken from the DDAbstractLogger implementation.
+    // For documentation please refer to the DDAbstractLogger implementation.
+
+    if ([self isOnInternalLoggerQueue]) {
+        block();
+    } else {
+        dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+        NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+
+        dispatch_async(globalLoggingQueue, ^{
+            dispatch_async(self.loggerQueue, block);
+        });
+    }
+}
+
+- (NSTimeInterval)maxAge {
+    // The design of this method is taken from the DDAbstractLogger implementation.
+    // For extensive documentation please refer to the DDAbstractLogger implementation.
+
+    // Note: The internal implementation MUST access the colorsEnabled variable directly,
+    // This method is designed explicitly for external access.
+    //
+    // Using "self." syntax to go through this method will cause immediate deadlock.
+    // This is the intended result. Fix it by accessing the ivar directly.
+    // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
+
+    NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+    NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
+
+    dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+
+    __block NSTimeInterval result;
+
+    dispatch_sync(globalLoggingQueue, ^{
+        dispatch_sync(self.loggerQueue, ^{
+            result = _maxAge;
+        });
+    });
+
+    return result;
+}
+
+- (void)setMaxAge:(NSTimeInterval)interval {
+    dispatch_block_t block = ^{
+        @autoreleasepool {
+            // C99 recommended floating point comparison macro
+            // Read: isLessThanOrGreaterThan(floatA, floatB)
+
+            if (/* maxAge != interval */ islessgreater(_maxAge, interval)) {
+                NSTimeInterval oldMaxAge = _maxAge;
+                NSTimeInterval newMaxAge = interval;
+
+                _maxAge = interval;
+
+                // There are several cases we need to handle here.
+                //
+                // 1. If the maxAge was previously enabled and it just got disabled,
+                //    then we need to stop the deleteTimer. (And we might as well release it.)
+                //
+                // 2. If the maxAge was previously disabled and it just got enabled,
+                //    then we need to setup the deleteTimer. (Plus we might need to do an immediate delete.)
+                //
+                // 3. If the maxAge was increased,
+                //    then we don't need to do anything.
+                //
+                // 4. If the maxAge was decreased,
+                //    then we should do an immediate delete.
+
+                BOOL shouldDeleteNow = NO;
+
+                if (oldMaxAge > 0.0) {
+                    if (newMaxAge <= 0.0) {
+                        // Handles #1
+
+                        [self destroyDeleteTimer];
+                    } else if (oldMaxAge > newMaxAge) {
+                        // Handles #4
+                        shouldDeleteNow = YES;
+                    }
+                } else if (newMaxAge > 0.0) {
+                    // Handles #2
+                    shouldDeleteNow = YES;
+                }
+
+                if (shouldDeleteNow) {
+                    [self performDelete];
+
+                    if (_deleteTimer) {
+                        [self updateDeleteTimer];
+                    } else {
+                        [self createAndStartDeleteTimer];
+                    }
+                }
+            }
+        }
+    };
+
+    // The design of the setter logic below is taken from the DDAbstractLogger implementation.
+    // For documentation please refer to the DDAbstractLogger implementation.
+
+    if ([self isOnInternalLoggerQueue]) {
+        block();
+    } else {
+        dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+        NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+
+        dispatch_async(globalLoggingQueue, ^{
+            dispatch_async(self.loggerQueue, block);
+        });
+    }
+}
+
+- (NSTimeInterval)deleteInterval {
+    // The design of this method is taken from the DDAbstractLogger implementation.
+    // For extensive documentation please refer to the DDAbstractLogger implementation.
+
+    // Note: The internal implementation MUST access the colorsEnabled variable directly,
+    // This method is designed explicitly for external access.
+    //
+    // Using "self." syntax to go through this method will cause immediate deadlock.
+    // This is the intended result. Fix it by accessing the ivar directly.
+    // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
+
+    NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+    NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
+
+    dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+
+    __block NSTimeInterval result;
+
+    dispatch_sync(globalLoggingQueue, ^{
+        dispatch_sync(self.loggerQueue, ^{
+            result = _deleteInterval;
+        });
+    });
+
+    return result;
+}
+
+- (void)setDeleteInterval:(NSTimeInterval)interval {
+    dispatch_block_t block = ^{
+        @autoreleasepool {
+            // C99 recommended floating point comparison macro
+            // Read: isLessThanOrGreaterThan(floatA, floatB)
+
+            if (/* deleteInterval != interval */ islessgreater(_deleteInterval, interval)) {
+                _deleteInterval = interval;
+
+                // There are several cases we need to handle here.
+                //
+                // 1. If the deleteInterval was previously enabled and it just got disabled,
+                //    then we need to stop the deleteTimer. (And we might as well release it.)
+                //
+                // 2. If the deleteInterval was previously disabled and it just got enabled,
+                //    then we need to setup the deleteTimer. (Plus we might need to do an immediate delete.)
+                //
+                // 3. If the deleteInterval increased, then we need to reset the timer so that it fires at the later date.
+                //
+                // 4. If the deleteInterval decreased, then we need to reset the timer so that it fires at an earlier date.
+                //    (Plus we might need to do an immediate delete.)
+
+                if (_deleteInterval > 0.0) {
+                    if (_deleteTimer == NULL) {
+                        // Handles #2
+                        //
+                        // Since the deleteTimer uses the lastDeleteTime to calculate it's first fireDate,
+                        // if a delete is needed the timer will fire immediately.
+
+                        [self createAndStartDeleteTimer];
+                    } else {
+                        // Handles #3
+                        // Handles #4
+                        //
+                        // Since the deleteTimer uses the lastDeleteTime to calculate it's first fireDate,
+                        // if a save is needed the timer will fire immediately.
+
+                        [self updateDeleteTimer];
+                    }
+                } else if (_deleteTimer) {
+                    // Handles #1
+
+                    [self destroyDeleteTimer];
+                }
+            }
+        }
+    };
+
+    // The design of the setter logic below is taken from the DDAbstractLogger implementation.
+    // For documentation please refer to the DDAbstractLogger implementation.
+
+    if ([self isOnInternalLoggerQueue]) {
+        block();
+    } else {
+        dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+        NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+
+        dispatch_async(globalLoggingQueue, ^{
+            dispatch_async(self.loggerQueue, block);
+        });
+    }
+}
+
+- (BOOL)deleteOnEverySave {
+    // The design of this method is taken from the DDAbstractLogger implementation.
+    // For extensive documentation please refer to the DDAbstractLogger implementation.
+
+    // Note: The internal implementation MUST access the colorsEnabled variable directly,
+    // This method is designed explicitly for external access.
+    //
+    // Using "self." syntax to go through this method will cause immediate deadlock.
+    // This is the intended result. Fix it by accessing the ivar directly.
+    // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
+
+    NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+    NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
+
+    dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+
+    __block BOOL result;
+
+    dispatch_sync(globalLoggingQueue, ^{
+        dispatch_sync(self.loggerQueue, ^{
+            result = _deleteOnEverySave;
+        });
+    });
+
+    return result;
+}
+
+- (void)setDeleteOnEverySave:(BOOL)flag {
+    dispatch_block_t block = ^{
+        _deleteOnEverySave = flag;
+    };
+
+    // The design of the setter logic below is taken from the DDAbstractLogger implementation.
+    // For documentation please refer to the DDAbstractLogger implementation.
+
+    if ([self isOnInternalLoggerQueue]) {
+        block();
+    } else {
+        dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+        NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+
+        dispatch_async(globalLoggingQueue, ^{
+            dispatch_async(self.loggerQueue, block);
+        });
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Public API
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+- (void)savePendingLogEntries {
+    dispatch_block_t block = ^{
+        @autoreleasepool {
+            [self performSaveAndSuspendSaveTimer];
+        }
+    };
+
+    if ([self isOnInternalLoggerQueue]) {
+        block();
+    } else {
+        dispatch_async(self.loggerQueue, block);
+    }
+}
+
+- (void)deleteOldLogEntries {
+    dispatch_block_t block = ^{
+        @autoreleasepool {
+            [self performDelete];
+        }
+    };
+
+    if ([self isOnInternalLoggerQueue]) {
+        block();
+    } else {
+        dispatch_async(self.loggerQueue, block);
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark DDLogger
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+- (void)didAddLogger {
+    // If you override me be sure to invoke [super didAddLogger];
+
+    [self createSuspendedSaveTimer];
+
+    [self createAndStartDeleteTimer];
+}
+
+- (void)willRemoveLogger {
+    // If you override me be sure to invoke [super willRemoveLogger];
+
+    [self performSaveAndSuspendSaveTimer];
+
+    [self destroySaveTimer];
+    [self destroyDeleteTimer];
+}
+
+- (void)logMessage:(DDLogMessage *)logMessage {
+    if ([self db_log:logMessage]) {
+        BOOL firstUnsavedEntry = (++_unsavedCount == 1);
+
+        if ((_unsavedCount >= _saveThreshold) && (_saveThreshold > 0)) {
+            [self performSaveAndSuspendSaveTimer];
+        } else if (firstUnsavedEntry) {
+            _unsavedTime = dispatch_time(DISPATCH_TIME_NOW, 0);
+            [self updateAndResumeSaveTimer];
+        }
+    }
+}
+
+- (void)flush {
+    // This method is invoked by DDLog's flushLog method.
+    //
+    // It is called automatically when the application quits,
+    // or if the developer invokes DDLog's flushLog method prior to crashing or something.
+
+    [self performSaveAndSuspendSaveTimer];
+}
+
+@end
diff --git a/cocoalumberjack/Classes/DDAssertMacros.h b/cocoalumberjack/Classes/DDAssertMacros.h
new file mode 100644
index 0000000..870d31f
--- /dev/null
+++ b/cocoalumberjack/Classes/DDAssertMacros.h
@@ -0,0 +1,26 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+/**
+ * NSAsset replacement that will output a log message even when assertions are disabled.
+ **/
+#define DDAssert(condition, frmt, ...)                                                \
+        if (!(condition)) {                                                           \
+            NSString *description = [NSString stringWithFormat:frmt, ## __VA_ARGS__]; \
+            DDLogError(@"%@", description);                                           \
+            NSAssert(NO, description);                                                \
+        }
+#define DDAssertCondition(condition) DDAssert(condition, @"Condition not satisfied: %s", #condition)
+
diff --git a/cocoalumberjack/Classes/DDFileLogger.h b/cocoalumberjack/Classes/DDFileLogger.h
new file mode 100644
index 0000000..f0bfdb6
--- /dev/null
+++ b/cocoalumberjack/Classes/DDFileLogger.h
@@ -0,0 +1,487 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+// Disable legacy macros
+#ifndef DD_LEGACY_MACROS
+    #define DD_LEGACY_MACROS 0
+#endif
+
+#import "DDLog.h"
+
+@class DDLogFileInfo;
+
+/**
+ * This class provides a logger to write log statements to a file.
+ **/
+
+
+// Default configuration and safety/sanity values.
+//
+// maximumFileSize         -> kDDDefaultLogMaxFileSize
+// rollingFrequency        -> kDDDefaultLogRollingFrequency
+// maximumNumberOfLogFiles -> kDDDefaultLogMaxNumLogFiles
+// logFilesDiskQuota       -> kDDDefaultLogFilesDiskQuota
+//
+// You should carefully consider the proper configuration values for your application.
+
+extern unsigned long long const kDDDefaultLogMaxFileSize;
+extern NSTimeInterval     const kDDDefaultLogRollingFrequency;
+extern NSUInteger         const kDDDefaultLogMaxNumLogFiles;
+extern unsigned long long const kDDDefaultLogFilesDiskQuota;
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ *  The LogFileManager protocol is designed to allow you to control all aspects of your log files.
+ *
+ *  The primary purpose of this is to allow you to do something with the log files after they have been rolled.
+ *  Perhaps you want to compress them to save disk space.
+ *  Perhaps you want to upload them to an FTP server.
+ *  Perhaps you want to run some analytics on the file.
+ *
+ *  A default LogFileManager is, of course, provided.
+ *  The default LogFileManager simply deletes old log files according to the maximumNumberOfLogFiles property.
+ *
+ *  This protocol provides various methods to fetch the list of log files.
+ *
+ *  There are two variants: sorted and unsorted.
+ *  If sorting is not necessary, the unsorted variant is obviously faster.
+ *  The sorted variant will return an array sorted by when the log files were created,
+ *  with the most recently created log file at index 0, and the oldest log file at the end of the array.
+ *
+ *  You can fetch only the log file paths (full path including name), log file names (name only),
+ *  or an array of `DDLogFileInfo` objects.
+ *  The `DDLogFileInfo` class is documented below, and provides a handy wrapper that
+ *  gives you easy access to various file attributes such as the creation date or the file size.
+ */
+@protocol DDLogFileManager <NSObject>
+@required
+
+// Public properties
+
+/**
+ * The maximum number of archived log files to keep on disk.
+ * For example, if this property is set to 3,
+ * then the LogFileManager will only keep 3 archived log files (plus the current active log file) on disk.
+ * Once the active log file is rolled/archived, then the oldest of the existing 3 rolled/archived log files is deleted.
+ *
+ * You may optionally disable this option by setting it to zero.
+ **/
+@property (readwrite, assign, atomic) NSUInteger maximumNumberOfLogFiles;
+
+/**
+ * The maximum space that logs can take. On rolling logfile all old logfiles that exceed logFilesDiskQuota will
+ * be deleted.
+ *
+ * You may optionally disable this option by setting it to zero.
+ **/
+@property (readwrite, assign, atomic) unsigned long long logFilesDiskQuota;
+
+// Public methods
+
+/**
+ *  Returns the logs directory (path)
+ */
+- (NSString *)logsDirectory;
+
+/**
+ * Returns an array of `NSString` objects,
+ * each of which is the filePath to an existing log file on disk.
+ **/
+- (NSArray *)unsortedLogFilePaths;
+
+/**
+ * Returns an array of `NSString` objects,
+ * each of which is the fileName of an existing log file on disk.
+ **/
+- (NSArray *)unsortedLogFileNames;
+
+/**
+ * Returns an array of `DDLogFileInfo` objects,
+ * each representing an existing log file on disk,
+ * and containing important information about the log file such as it's modification date and size.
+ **/
+- (NSArray *)unsortedLogFileInfos;
+
+/**
+ * Just like the `unsortedLogFilePaths` method, but sorts the array.
+ * The items in the array are sorted by creation date.
+ * The first item in the array will be the most recently created log file.
+ **/
+- (NSArray *)sortedLogFilePaths;
+
+/**
+ * Just like the `unsortedLogFileNames` method, but sorts the array.
+ * The items in the array are sorted by creation date.
+ * The first item in the array will be the most recently created log file.
+ **/
+- (NSArray *)sortedLogFileNames;
+
+/**
+ * Just like the `unsortedLogFileInfos` method, but sorts the array.
+ * The items in the array are sorted by creation date.
+ * The first item in the array will be the most recently created log file.
+ **/
+- (NSArray *)sortedLogFileInfos;
+
+// Private methods (only to be used by DDFileLogger)
+
+/**
+ * Generates a new unique log file path, and creates the corresponding log file.
+ **/
+- (NSString *)createNewLogFile;
+
+@optional
+
+// Notifications from DDFileLogger
+
+/**
+ *  Called when a log file was archieved
+ */
+- (void)didArchiveLogFile:(NSString *)logFilePath;
+
+/**
+ *  Called when the roll action was executed and the log was archieved
+ */
+- (void)didRollAndArchiveLogFile:(NSString *)logFilePath;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Default log file manager.
+ *
+ * All log files are placed inside the logsDirectory.
+ * If a specific logsDirectory isn't specified, the default directory is used.
+ * On Mac, this is in `~/Library/Logs/<Application Name>`.
+ * On iPhone, this is in `~/Library/Caches/Logs`.
+ *
+ * Log files are named `"<bundle identifier> <date> <time>.log"`
+ * Example: `com.organization.myapp 2013-12-03 17-14.log`
+ *
+ * Archived log files are automatically deleted according to the `maximumNumberOfLogFiles` property.
+ **/
+@interface DDLogFileManagerDefault : NSObject <DDLogFileManager>
+
+/**
+ *  Default initializer
+ */
+- (instancetype)init;
+
+/**
+ *  Designated initialized, requires the logs directory
+ */
+- (instancetype)initWithLogsDirectory:(NSString *)logsDirectory NS_DESIGNATED_INITIALIZER;
+
+#if TARGET_OS_IPHONE
+/*
+ * Calling this constructor you can override the default "automagically" chosen NSFileProtection level.
+ * Useful if you are writing a command line utility / CydiaSubstrate addon for iOS that has no NSBundle
+ * or like SpringBoard no BackgroundModes key in the NSBundle:
+ *    iPhone:~ root# cycript -p SpringBoard
+ *    cy# [NSBundle mainBundle]
+ *    #"NSBundle </System/Library/CoreServices/SpringBoard.app> (loaded)"
+ *    cy# [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"];
+ *    null
+ *    cy#
+ **/
+- (instancetype)initWithLogsDirectory:(NSString *)logsDirectory defaultFileProtectionLevel:(NSString *)fileProtectionLevel;
+#endif
+
+/*
+ * Methods to override.
+ *
+ * Log files are named `"<bundle identifier> <date> <time>.log"`
+ * Example: `com.organization.myapp 2013-12-03 17-14.log`
+ *
+ * If you wish to change default filename, you can override following two methods.
+ * - `newLogFileName` method would be called on new logfile creation.
+ * - `isLogFile:` method would be called to filter logfiles from all other files in logsDirectory.
+ *   You have to parse given filename and return YES if it is logFile.
+ *
+ * **NOTE**
+ * `newLogFileName` returns filename. If appropriate file already exists, number would be added
+ * to filename before extension. You have to handle this case in isLogFile: method.
+ *
+ * Example:
+ * - newLogFileName returns `"com.organization.myapp 2013-12-03.log"`,
+ *   file `"com.organization.myapp 2013-12-03.log"` would be created.
+ * - after some time `"com.organization.myapp 2013-12-03.log"` is archived
+ * - newLogFileName again returns `"com.organization.myapp 2013-12-03.log"`,
+ *   file `"com.organization.myapp 2013-12-03 2.log"` would be created.
+ * - after some time `"com.organization.myapp 2013-12-03 1.log"` is archived
+ * - newLogFileName again returns `"com.organization.myapp 2013-12-03.log"`,
+ *   file `"com.organization.myapp 2013-12-03 3.log"` would be created.
+ **/
+
+/**
+ * Generates log file name with default format `"<bundle identifier> <date> <time>.log"`
+ * Example: `MobileSafari 2013-12-03 17-14.log`
+ *
+ * You can change it by overriding `newLogFileName` and `isLogFile:` methods.
+ **/
+@property (readonly, copy) NSString *newLogFileName;
+
+/**
+ * Default log file name is `"<bundle identifier> <date> <time>.log"`.
+ * Example: `MobileSafari 2013-12-03 17-14.log`
+ *
+ * You can change it by overriding `newLogFileName` and `isLogFile:` methods.
+ **/
+- (BOOL)isLogFile:(NSString *)fileName;
+
+/* Inherited from DDLogFileManager protocol:
+
+   @property (readwrite, assign, atomic) NSUInteger maximumNumberOfLogFiles;
+   @property (readwrite, assign, atomic) NSUInteger logFilesDiskQuota;
+
+   - (NSString *)logsDirectory;
+
+   - (NSArray *)unsortedLogFilePaths;
+   - (NSArray *)unsortedLogFileNames;
+   - (NSArray *)unsortedLogFileInfos;
+
+   - (NSArray *)sortedLogFilePaths;
+   - (NSArray *)sortedLogFileNames;
+   - (NSArray *)sortedLogFileInfos;
+
+ */
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Most users will want file log messages to be prepended with the date and time.
+ * Rather than forcing the majority of users to write their own formatter,
+ * we will supply a logical default formatter.
+ * Users can easily replace this formatter with their own by invoking the `setLogFormatter:` method.
+ * It can also be removed by calling `setLogFormatter:`, and passing a nil parameter.
+ *
+ * In addition to the convenience of having a logical default formatter,
+ * it will also provide a template that makes it easy for developers to copy and change.
+ **/
+@interface DDLogFileFormatterDefault : NSObject <DDLogFormatter>
+
+/**
+ *  Default initializer
+ */
+- (instancetype)init;
+
+/**
+ *  Designated initializer, requires a date formatter
+ */
+- (instancetype)initWithDateFormatter:(NSDateFormatter *)dateFormatter NS_DESIGNATED_INITIALIZER;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ *  The standard implementation for a file logger
+ */
+@interface DDFileLogger : DDAbstractLogger <DDLogger>
+
+/**
+ *  Default initializer
+ */
+- (instancetype)init;
+
+/**
+ *  Designated initializer, requires a `DDLogFileManager` instance
+ */
+- (instancetype)initWithLogFileManager:(id <DDLogFileManager>)logFileManager NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Log File Rolling:
+ *
+ * `maximumFileSize`:
+ *   The approximate maximum size to allow log files to grow.
+ *   If a log file is larger than this value after a log statement is appended,
+ *   then the log file is rolled.
+ *
+ * `rollingFrequency`
+ *   How often to roll the log file.
+ *   The frequency is given as an `NSTimeInterval`, which is a double that specifies the interval in seconds.
+ *   Once the log file gets to be this old, it is rolled.
+ *
+ * Both the `maximumFileSize` and the `rollingFrequency` are used to manage rolling.
+ * Whichever occurs first will cause the log file to be rolled.
+ *
+ * For example:
+ * The `rollingFrequency` is 24 hours,
+ * but the log file surpasses the `maximumFileSize` after only 20 hours.
+ * The log file will be rolled at that 20 hour mark.
+ * A new log file will be created, and the 24 hour timer will be restarted.
+ *
+ * You may optionally disable rolling due to filesize by setting `maximumFileSize` to zero.
+ * If you do so, rolling is based solely on `rollingFrequency`.
+ *
+ * You may optionally disable rolling due to time by setting `rollingFrequency` to zero (or any non-positive number).
+ * If you do so, rolling is based solely on `maximumFileSize`.
+ *
+ * If you disable both `maximumFileSize` and `rollingFrequency`, then the log file won't ever be rolled.
+ * This is strongly discouraged.
+ **/
+@property (readwrite, assign) unsigned long long maximumFileSize;
+
+/**
+ *  See description for `maximumFileSize`
+ */
+@property (readwrite, assign) NSTimeInterval rollingFrequency;
+
+/**
+ *  See description for `maximumFileSize`
+ */
+@property (readwrite, assign, atomic) BOOL doNotReuseLogFiles;
+
+/**
+ * The DDLogFileManager instance can be used to retrieve the list of log files,
+ * and configure the maximum number of archived log files to keep.
+ *
+ * @see DDLogFileManager.maximumNumberOfLogFiles
+ **/
+@property (strong, nonatomic, readonly) id <DDLogFileManager> logFileManager;
+
+/**
+ * When using a custom formatter you can set the `logMessage` method not to append
+ * `\n` character after each output. This allows for some greater flexibility with
+ * custom formatters. Default value is YES.
+ **/
+@property (nonatomic, readwrite, assign) BOOL automaticallyAppendNewlineForCustomFormatters;
+
+/**
+ *  You can optionally force the current log file to be rolled with this method.
+ *  CompletionBlock will be called on main queue.
+ */
+- (void)rollLogFileWithCompletionBlock:(void (^)())completionBlock;
+
+/**
+ *  Method is deprecated.
+ *  @deprecated Use `rollLogFileWithCompletionBlock:` method instead.
+ */
+- (void)rollLogFile __attribute((deprecated));
+
+// Inherited from DDAbstractLogger
+
+// - (id <DDLogFormatter>)logFormatter;
+// - (void)setLogFormatter:(id <DDLogFormatter>)formatter;
+
+/**
+ * Returns the log file that should be used.
+ * If there is an existing log file that is suitable,
+ * within the constraints of `maximumFileSize` and `rollingFrequency`, then it is returned.
+ *
+ * Otherwise a new file is created and returned.
+ **/
+- (DDLogFileInfo *)currentLogFileInfo;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * `DDLogFileInfo` is a simple class that provides access to various file attributes.
+ * It provides good performance as it only fetches the information if requested,
+ * and it caches the information to prevent duplicate fetches.
+ *
+ * It was designed to provide quick snapshots of the current state of log files,
+ * and to help sort log files in an array.
+ *
+ * This class does not monitor the files, or update it's cached attribute values if the file changes on disk.
+ * This is not what the class was designed for.
+ *
+ * If you absolutely must get updated values,
+ * you can invoke the reset method which will clear the cache.
+ **/
+@interface DDLogFileInfo : NSObject
+
+@property (strong, nonatomic, readonly) NSString *filePath;
+@property (strong, nonatomic, readonly) NSString *fileName;
+
+@property (strong, nonatomic, readonly) NSDictionary *fileAttributes;
+
+@property (strong, nonatomic, readonly) NSDate *creationDate;
+@property (strong, nonatomic, readonly) NSDate *modificationDate;
+
+@property (nonatomic, readonly) unsigned long long fileSize;
+
+@property (nonatomic, readonly) NSTimeInterval age;
+
+@property (nonatomic, readwrite) BOOL isArchived;
+
++ (instancetype)logFileWithPath:(NSString *)filePath;
+
+- (instancetype)init NS_UNAVAILABLE;
+- (instancetype)initWithFilePath:(NSString *)filePath NS_DESIGNATED_INITIALIZER;
+
+- (void)reset;
+- (void)renameFile:(NSString *)newFileName;
+
+#if TARGET_IPHONE_SIMULATOR
+
+// So here's the situation.
+// Extended attributes are perfect for what we're trying to do here (marking files as archived).
+// This is exactly what extended attributes were designed for.
+//
+// But Apple screws us over on the simulator.
+// Everytime you build-and-go, they copy the application into a new folder on the hard drive,
+// and as part of the process they strip extended attributes from our log files.
+// Normally, a copy of a file preserves extended attributes.
+// So obviously Apple has gone to great lengths to piss us off.
+//
+// Thus we use a slightly different tactic for marking log files as archived in the simulator.
+// That way it "just works" and there's no confusion when testing.
+//
+// The difference in method names is indicative of the difference in functionality.
+// On the simulator we add an attribute by appending a filename extension.
+//
+// For example:
+// "mylog.txt" -> "mylog.archived.txt"
+// "mylog"     -> "mylog.archived"
+
+- (BOOL)hasExtensionAttributeWithName:(NSString *)attrName;
+
+- (void)addExtensionAttributeWithName:(NSString *)attrName;
+- (void)removeExtensionAttributeWithName:(NSString *)attrName;
+
+#else /* if TARGET_IPHONE_SIMULATOR */
+
+// Normal use of extended attributes used everywhere else,
+// such as on Macs and on iPhone devices.
+
+- (BOOL)hasExtendedAttributeWithName:(NSString *)attrName;
+
+- (void)addExtendedAttributeWithName:(NSString *)attrName;
+- (void)removeExtendedAttributeWithName:(NSString *)attrName;
+
+#endif /* if TARGET_IPHONE_SIMULATOR */
+
+- (NSComparisonResult)reverseCompareByCreationDate:(DDLogFileInfo *)another;
+- (NSComparisonResult)reverseCompareByModificationDate:(DDLogFileInfo *)another;
+
+@end
diff --git a/cocoalumberjack/Classes/DDFileLogger.m b/cocoalumberjack/Classes/DDFileLogger.m
new file mode 100644
index 0000000..1b78578
--- /dev/null
+++ b/cocoalumberjack/Classes/DDFileLogger.m
@@ -0,0 +1,1484 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+#import "DDFileLogger.h"
+
+#import <unistd.h>
+#import <sys/attr.h>
+#import <sys/xattr.h>
+#import <libkern/OSAtomic.h>
+
+#if !__has_feature(objc_arc)
+#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
+#endif
+
+// We probably shouldn't be using DDLog() statements within the DDLog implementation.
+// But we still want to leave our log statements for any future debugging,
+// and to allow other developers to trace the implementation (which is a great learning tool).
+//
+// So we use primitive logging macros around NSLog.
+// We maintain the NS prefix on the macros to be explicit about the fact that we're using NSLog.
+
+#ifndef DD_NSLOG_LEVEL
+    #define DD_NSLOG_LEVEL 2
+#endif
+
+#define NSLogError(frmt, ...)    do{ if(DD_NSLOG_LEVEL >= 1) NSLog((frmt), ##__VA_ARGS__); } while(0)
+#define NSLogWarn(frmt, ...)     do{ if(DD_NSLOG_LEVEL >= 2) NSLog((frmt), ##__VA_ARGS__); } while(0)
+#define NSLogInfo(frmt, ...)     do{ if(DD_NSLOG_LEVEL >= 3) NSLog((frmt), ##__VA_ARGS__); } while(0)
+#define NSLogDebug(frmt, ...)    do{ if(DD_NSLOG_LEVEL >= 4) NSLog((frmt), ##__VA_ARGS__); } while(0)
+#define NSLogVerbose(frmt, ...)  do{ if(DD_NSLOG_LEVEL >= 5) NSLog((frmt), ##__VA_ARGS__); } while(0)
+
+
+#if TARGET_OS_IPHONE
+BOOL doesAppRunInBackground(void);
+#endif
+
+unsigned long long const kDDDefaultLogMaxFileSize      = 1024 * 1024;      // 1 MB
+NSTimeInterval     const kDDDefaultLogRollingFrequency = 60 * 60 * 24;     // 24 Hours
+NSUInteger         const kDDDefaultLogMaxNumLogFiles   = 5;                // 5 Files
+unsigned long long const kDDDefaultLogFilesDiskQuota   = 20 * 1024 * 1024; // 20 MB
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface DDLogFileManagerDefault () {
+    NSUInteger _maximumNumberOfLogFiles;
+    unsigned long long _logFilesDiskQuota;
+    NSString *_logsDirectory;
+#if TARGET_OS_IPHONE
+    NSString *_defaultFileProtectionLevel;
+#endif
+}
+
+- (void)deleteOldLogFiles;
+- (NSString *)defaultLogsDirectory;
+
+@end
+
+@implementation DDLogFileManagerDefault
+
+@synthesize maximumNumberOfLogFiles = _maximumNumberOfLogFiles;
+@synthesize logFilesDiskQuota = _logFilesDiskQuota;
+
+
+- (instancetype)init {
+    return [self initWithLogsDirectory:nil];
+}
+
+- (instancetype)initWithLogsDirectory:(NSString *)aLogsDirectory {
+    if ((self = [super init])) {
+        _maximumNumberOfLogFiles = kDDDefaultLogMaxNumLogFiles;
+        _logFilesDiskQuota = kDDDefaultLogFilesDiskQuota;
+
+        if (aLogsDirectory) {
+            _logsDirectory = [aLogsDirectory copy];
+        } else {
+            _logsDirectory = [[self defaultLogsDirectory] copy];
+        }
+
+        NSKeyValueObservingOptions kvoOptions = NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew;
+
+        [self addObserver:self forKeyPath:NSStringFromSelector(@selector(maximumNumberOfLogFiles)) options:kvoOptions context:nil];
+        [self addObserver:self forKeyPath:NSStringFromSelector(@selector(logFilesDiskQuota)) options:kvoOptions context:nil];
+
+        NSLogVerbose(@"DDFileLogManagerDefault: logsDirectory:\n%@", [self logsDirectory]);
+        NSLogVerbose(@"DDFileLogManagerDefault: sortedLogFileNames:\n%@", [self sortedLogFileNames]);
+    }
+
+    return self;
+}
+
++ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey
+{
+    BOOL automatic = NO;
+    if ([theKey isEqualToString:@"maximumNumberOfLogFiles"] || [theKey isEqualToString:@"logFilesDiskQuota"]) {
+        automatic = NO;
+    } else {
+        automatic = [super automaticallyNotifiesObserversForKey:theKey];
+    }
+    
+    return automatic;
+}
+
+#if TARGET_OS_IPHONE
+- (instancetype)initWithLogsDirectory:(NSString *)logsDirectory defaultFileProtectionLevel:(NSString *)fileProtectionLevel {
+    if ((self = [self initWithLogsDirectory:logsDirectory])) {
+        if ([fileProtectionLevel isEqualToString:NSFileProtectionNone] ||
+            [fileProtectionLevel isEqualToString:NSFileProtectionComplete] ||
+            [fileProtectionLevel isEqualToString:NSFileProtectionCompleteUnlessOpen] ||
+            [fileProtectionLevel isEqualToString:NSFileProtectionCompleteUntilFirstUserAuthentication]) {
+            _defaultFileProtectionLevel = fileProtectionLevel;
+        }
+    }
+
+    return self;
+}
+
+#endif
+
+- (void)dealloc {
+    // try-catch because the observer might be removed or never added. In this case, removeObserver throws and exception
+    @try {
+        [self removeObserver:self forKeyPath:NSStringFromSelector(@selector(maximumNumberOfLogFiles))];
+        [self removeObserver:self forKeyPath:NSStringFromSelector(@selector(logFilesDiskQuota))];
+    } @catch (NSException *exception) {
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Configuration
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+- (void)observeValueForKeyPath:(NSString *)keyPath
+                      ofObject:(id)object
+                        change:(NSDictionary *)change
+                       context:(void *)context {
+    NSNumber *old = change[NSKeyValueChangeOldKey];
+    NSNumber *new = change[NSKeyValueChangeNewKey];
+
+    if ([old isEqual:new]) {
+        // No change in value - don't bother with any processing.
+        return;
+    }
+
+    if ([keyPath isEqualToString:NSStringFromSelector(@selector(maximumNumberOfLogFiles))] ||
+        [keyPath isEqualToString:NSStringFromSelector(@selector(logFilesDiskQuota))]) {
+        NSLogInfo(@"DDFileLogManagerDefault: Responding to configuration change: %@", keyPath);
+
+        dispatch_async([DDLog loggingQueue], ^{ @autoreleasepool {
+                                                    [self deleteOldLogFiles];
+                                                } });
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark File Deleting
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Deletes archived log files that exceed the maximumNumberOfLogFiles or logFilesDiskQuota configuration values.
+ **/
+- (void)deleteOldLogFiles {
+    NSLogVerbose(@"DDLogFileManagerDefault: deleteOldLogFiles");
+
+    NSArray *sortedLogFileInfos = [self sortedLogFileInfos];
+
+    NSUInteger firstIndexToDelete = NSNotFound;
+
+    const unsigned long long diskQuota = self.logFilesDiskQuota;
+    const NSUInteger maxNumLogFiles = self.maximumNumberOfLogFiles;
+
+    if (diskQuota) {
+        unsigned long long used = 0;
+
+        for (NSUInteger i = 0; i < sortedLogFileInfos.count; i++) {
+            DDLogFileInfo *info = sortedLogFileInfos[i];
+            used += info.fileSize;
+
+            if (used > diskQuota) {
+                firstIndexToDelete = i;
+                break;
+            }
+        }
+    }
+
+    if (maxNumLogFiles) {
+        if (firstIndexToDelete == NSNotFound) {
+            firstIndexToDelete = maxNumLogFiles;
+        } else {
+            firstIndexToDelete = MIN(firstIndexToDelete, maxNumLogFiles);
+        }
+    }
+
+    if (firstIndexToDelete == 0) {
+        // Do we consider the first file?
+        // We are only supposed to be deleting archived files.
+        // In most cases, the first file is likely the log file that is currently being written to.
+        // So in most cases, we do not want to consider this file for deletion.
+
+        if (sortedLogFileInfos.count > 0) {
+            DDLogFileInfo *logFileInfo = sortedLogFileInfos[0];
+
+            if (!logFileInfo.isArchived) {
+                // Don't delete active file.
+                ++firstIndexToDelete;
+            }
+        }
+    }
+
+    if (firstIndexToDelete != NSNotFound) {
+        // removing all logfiles starting with firstIndexToDelete
+
+        for (NSUInteger i = firstIndexToDelete; i < sortedLogFileInfos.count; i++) {
+            DDLogFileInfo *logFileInfo = sortedLogFileInfos[i];
+
+            NSLogInfo(@"DDLogFileManagerDefault: Deleting file: %@", logFileInfo.fileName);
+
+            [[NSFileManager defaultManager] removeItemAtPath:logFileInfo.filePath error:nil];
+        }
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Log Files
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Returns the path to the default logs directory.
+ * If the logs directory doesn't exist, this method automatically creates it.
+ **/
+- (NSString *)defaultLogsDirectory {
+#if TARGET_OS_IPHONE
+    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
+    NSString *baseDir = paths.firstObject;
+    NSString *logsDirectory = [baseDir stringByAppendingPathComponent:@"Logs"];
+
+#else
+    NSString *appName = [[NSProcessInfo processInfo] processName];
+    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
+    NSString *basePath = ([paths count] > 0) ? paths[0] : NSTemporaryDirectory();
+    NSString *logsDirectory = [[basePath stringByAppendingPathComponent:@"Logs"] stringByAppendingPathComponent:appName];
+
+#endif
+
+    return logsDirectory;
+}
+
+- (NSString *)logsDirectory {
+    // We could do this check once, during initalization, and not bother again.
+    // But this way the code continues to work if the directory gets deleted while the code is running.
+
+    if (![[NSFileManager defaultManager] fileExistsAtPath:_logsDirectory]) {
+        NSError *err = nil;
+
+        if (![[NSFileManager defaultManager] createDirectoryAtPath:_logsDirectory
+                                       withIntermediateDirectories:YES
+                                                        attributes:nil
+                                                             error:&err]) {
+            NSLogError(@"DDFileLogManagerDefault: Error creating logsDirectory: %@", err);
+        }
+    }
+
+    return _logsDirectory;
+}
+
+- (BOOL)isLogFile:(NSString *)fileName {
+    NSString *appName = [self applicationName];
+
+    BOOL hasProperPrefix = [fileName hasPrefix:appName];
+    BOOL hasProperSuffix = [fileName hasSuffix:@".log"];
+    BOOL hasProperDate = NO;
+
+    if (hasProperPrefix && hasProperSuffix) {
+        NSUInteger lengthOfMiddle = fileName.length - appName.length - @".log".length;
+
+        // Date string should have at least 16 characters - " 2013-12-03 17-14"
+        if (lengthOfMiddle >= 17) {
+            NSRange range = NSMakeRange(appName.length, lengthOfMiddle);
+
+            NSString *middle = [fileName substringWithRange:range];
+            NSArray *components = [middle componentsSeparatedByString:@" "];
+
+            // When creating logfile if there is existing file with the same name, we append attemp number at the end.
+            // Thats why here we can have three or four components. For details see createNewLogFile method.
+            //
+            // Components:
+            //     "", "2013-12-03", "17-14"
+            // or
+            //     "", "2013-12-03", "17-14", "1"
+            if (components.count == 3 || components.count == 4) {
+                NSString *dateString = [NSString stringWithFormat:@"%@ %@", components[1], components[2]];
+                NSDateFormatter *dateFormatter = [self logFileDateFormatter];
+
+                NSDate *date = [dateFormatter dateFromString:dateString];
+
+                if (date) {
+                    hasProperDate = YES;
+                }
+            }
+        }
+    }
+
+    return (hasProperPrefix && hasProperDate && hasProperSuffix);
+}
+
+- (NSDateFormatter *)logFileDateFormatter {
+    NSMutableDictionary *dictionary = [[NSThread currentThread]
+                                       threadDictionary];
+    NSString *dateFormat = @"yyyy'-'MM'-'dd' 'HH'-'mm'";
+    NSString *key = [NSString stringWithFormat:@"logFileDateFormatter.%@", dateFormat];
+    NSDateFormatter *dateFormatter = dictionary[key];
+
+    if (dateFormatter == nil) {
+        dateFormatter = [[NSDateFormatter alloc] init];
+        [dateFormatter setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]];
+        [dateFormatter setDateFormat:dateFormat];
+        [dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
+        dictionary[key] = dateFormatter;
+    }
+
+    return dateFormatter;
+}
+
+- (NSArray *)unsortedLogFilePaths {
+    NSString *logsDirectory = [self logsDirectory];
+    NSArray *fileNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:logsDirectory error:nil];
+
+    NSMutableArray *unsortedLogFilePaths = [NSMutableArray arrayWithCapacity:[fileNames count]];
+
+    for (NSString *fileName in fileNames) {
+        // Filter out any files that aren't log files. (Just for extra safety)
+
+    #if TARGET_IPHONE_SIMULATOR
+        // In case of iPhone simulator there can be 'archived' extension. isLogFile:
+        // method knows nothing about it. Thus removing it for this method.
+        //
+        // See full explanation in the header file.
+        NSString *theFileName = [fileName stringByReplacingOccurrencesOfString:@".archived"
+                                                                    withString:@""];
+
+        if ([self isLogFile:theFileName])
+    #else
+
+        if ([self isLogFile:fileName])
+    #endif
+        {
+            NSString *filePath = [logsDirectory stringByAppendingPathComponent:fileName];
+
+            [unsortedLogFilePaths addObject:filePath];
+        }
+    }
+
+    return unsortedLogFilePaths;
+}
+
+- (NSArray *)unsortedLogFileNames {
+    NSArray *unsortedLogFilePaths = [self unsortedLogFilePaths];
+
+    NSMutableArray *unsortedLogFileNames = [NSMutableArray arrayWithCapacity:[unsortedLogFilePaths count]];
+
+    for (NSString *filePath in unsortedLogFilePaths) {
+        [unsortedLogFileNames addObject:[filePath lastPathComponent]];
+    }
+
+    return unsortedLogFileNames;
+}
+
+- (NSArray *)unsortedLogFileInfos {
+    NSArray *unsortedLogFilePaths = [self unsortedLogFilePaths];
+
+    NSMutableArray *unsortedLogFileInfos = [NSMutableArray arrayWithCapacity:[unsortedLogFilePaths count]];
+
+    for (NSString *filePath in unsortedLogFilePaths) {
+        DDLogFileInfo *logFileInfo = [[DDLogFileInfo alloc] initWithFilePath:filePath];
+
+        [unsortedLogFileInfos addObject:logFileInfo];
+    }
+
+    return unsortedLogFileInfos;
+}
+
+- (NSArray *)sortedLogFilePaths {
+    NSArray *sortedLogFileInfos = [self sortedLogFileInfos];
+
+    NSMutableArray *sortedLogFilePaths = [NSMutableArray arrayWithCapacity:[sortedLogFileInfos count]];
+
+    for (DDLogFileInfo *logFileInfo in sortedLogFileInfos) {
+        [sortedLogFilePaths addObject:[logFileInfo filePath]];
+    }
+
+    return sortedLogFilePaths;
+}
+
+- (NSArray *)sortedLogFileNames {
+    NSArray *sortedLogFileInfos = [self sortedLogFileInfos];
+
+    NSMutableArray *sortedLogFileNames = [NSMutableArray arrayWithCapacity:[sortedLogFileInfos count]];
+
+    for (DDLogFileInfo *logFileInfo in sortedLogFileInfos) {
+        [sortedLogFileNames addObject:[logFileInfo fileName]];
+    }
+
+    return sortedLogFileNames;
+}
+
+- (NSArray *)sortedLogFileInfos {
+    return [[self unsortedLogFileInfos] sortedArrayUsingSelector:@selector(reverseCompareByCreationDate:)];
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Creation
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+- (NSString *)newLogFileName {
+    NSString *appName = [self applicationName];
+
+    NSDateFormatter *dateFormatter = [self logFileDateFormatter];
+    NSString *formattedDate = [dateFormatter stringFromDate:[NSDate date]];
+
+    return [NSString stringWithFormat:@"%@ %@.log", appName, formattedDate];
+}
+
+- (NSString *)createNewLogFile {
+    NSString *fileName = [self newLogFileName];
+    NSString *logsDirectory = [self logsDirectory];
+
+    NSUInteger attempt = 1;
+
+    do {
+        NSString *actualFileName = fileName;
+
+        if (attempt > 1) {
+            NSString *extension = [actualFileName pathExtension];
+
+            actualFileName = [actualFileName stringByDeletingPathExtension];
+            actualFileName = [actualFileName stringByAppendingFormat:@" %lu", (unsigned long)attempt];
+
+            if (extension.length) {
+                actualFileName = [actualFileName stringByAppendingPathExtension:extension];
+            }
+        }
+
+        NSString *filePath = [logsDirectory stringByAppendingPathComponent:actualFileName];
+
+        if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
+            NSLogVerbose(@"DDLogFileManagerDefault: Creating new log file: %@", actualFileName);
+
+            NSDictionary *attributes = nil;
+
+        #if TARGET_OS_IPHONE
+            // When creating log file on iOS we're setting NSFileProtectionKey attribute to NSFileProtectionCompleteUnlessOpen.
+            //
+            // But in case if app is able to launch from background we need to have an ability to open log file any time we
+            // want (even if device is locked). Thats why that attribute have to be changed to
+            // NSFileProtectionCompleteUntilFirstUserAuthentication.
+
+            NSString *key = _defaultFileProtectionLevel ? :
+                (doesAppRunInBackground() ? NSFileProtectionCompleteUntilFirstUserAuthentication : NSFileProtectionCompleteUnlessOpen);
+
+            attributes = @{
+                NSFileProtectionKey: key
+            };
+        #endif
+
+            [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:attributes];
+
+            // Since we just created a new log file, we may need to delete some old log files
+            [self deleteOldLogFiles];
+
+            return filePath;
+        } else {
+            attempt++;
+        }
+    } while (YES);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Utility
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+- (NSString *)applicationName {
+    static NSString *_appName;
+    static dispatch_once_t onceToken;
+
+    dispatch_once(&onceToken, ^{
+        _appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"];
+
+        if (!_appName) {
+            _appName = [[NSProcessInfo processInfo] processName];
+        }
+
+        if (!_appName) {
+            _appName = @"";
+        }
+    });
+
+    return _appName;
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface DDLogFileFormatterDefault () {
+    NSDateFormatter *_dateFormatter;
+}
+
+@end
+
+@implementation DDLogFileFormatterDefault
+
+- (instancetype)init {
+    return [self initWithDateFormatter:nil];
+}
+
+- (instancetype)initWithDateFormatter:(NSDateFormatter *)aDateFormatter {
+    if ((self = [super init])) {
+        if (aDateFormatter) {
+            _dateFormatter = aDateFormatter;
+        } else {
+            _dateFormatter = [[NSDateFormatter alloc] init];
+            [_dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; // 10.4+ style
+            [_dateFormatter setDateFormat:@"yyyy/MM/dd HH:mm:ss:SSS"];
+        }
+    }
+
+    return self;
+}
+
+- (NSString *)formatLogMessage:(DDLogMessage *)logMessage {
+    NSString *dateAndTime = [_dateFormatter stringFromDate:(logMessage->_timestamp)];
+
+    return [NSString stringWithFormat:@"%@  %@", dateAndTime, logMessage->_message];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface DDFileLogger () {
+    __strong id <DDLogFileManager> _logFileManager;
+    
+    DDLogFileInfo *_currentLogFileInfo;
+    NSFileHandle *_currentLogFileHandle;
+    
+    dispatch_source_t _currentLogFileVnode;
+    dispatch_source_t _rollingTimer;
+    
+    unsigned long long _maximumFileSize;
+    NSTimeInterval _rollingFrequency;
+}
+
+- (void)rollLogFileNow;
+- (void)maybeRollLogFileDueToAge;
+- (void)maybeRollLogFileDueToSize;
+
+@end
+
+@implementation DDFileLogger
+
+- (instancetype)init {
+    DDLogFileManagerDefault *defaultLogFileManager = [[DDLogFileManagerDefault alloc] init];
+
+    return [self initWithLogFileManager:defaultLogFileManager];
+}
+
+- (instancetype)initWithLogFileManager:(id <DDLogFileManager>)aLogFileManager {
+    if ((self = [super init])) {
+        _maximumFileSize = kDDDefaultLogMaxFileSize;
+        _rollingFrequency = kDDDefaultLogRollingFrequency;
+        _automaticallyAppendNewlineForCustomFormatters = YES;
+
+        logFileManager = aLogFileManager;
+
+        self.logFormatter = [DDLogFileFormatterDefault new];
+    }
+
+    return self;
+}
+
+- (void)dealloc {
+    [_currentLogFileHandle synchronizeFile];
+    [_currentLogFileHandle closeFile];
+
+    if (_currentLogFileVnode) {
+        dispatch_source_cancel(_currentLogFileVnode);
+        _currentLogFileVnode = NULL;
+    }
+
+    if (_rollingTimer) {
+        dispatch_source_cancel(_rollingTimer);
+        _rollingTimer = NULL;
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Properties
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@synthesize logFileManager;
+
+- (unsigned long long)maximumFileSize {
+    __block unsigned long long result;
+
+    dispatch_block_t block = ^{
+        result = _maximumFileSize;
+    };
+
+    // The design of this method is taken from the DDAbstractLogger implementation.
+    // For extensive documentation please refer to the DDAbstractLogger implementation.
+
+    // Note: The internal implementation MUST access the maximumFileSize variable directly,
+    // This method is designed explicitly for external access.
+    //
+    // Using "self." syntax to go through this method will cause immediate deadlock.
+    // This is the intended result. Fix it by accessing the ivar directly.
+    // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
+
+    NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+    NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
+
+    dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+
+    dispatch_sync(globalLoggingQueue, ^{
+        dispatch_sync(self.loggerQueue, block);
+    });
+
+    return result;
+}
+
+- (void)setMaximumFileSize:(unsigned long long)newMaximumFileSize {
+    dispatch_block_t block = ^{
+        @autoreleasepool {
+            _maximumFileSize = newMaximumFileSize;
+            [self maybeRollLogFileDueToSize];
+        }
+    };
+
+    // The design of this method is taken from the DDAbstractLogger implementation.
+    // For extensive documentation please refer to the DDAbstractLogger implementation.
+
+    // Note: The internal implementation MUST access the maximumFileSize variable directly,
+    // This method is designed explicitly for external access.
+    //
+    // Using "self." syntax to go through this method will cause immediate deadlock.
+    // This is the intended result. Fix it by accessing the ivar directly.
+    // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
+
+    NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+    NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
+
+    dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+
+    dispatch_async(globalLoggingQueue, ^{
+        dispatch_async(self.loggerQueue, block);
+    });
+}
+
+- (NSTimeInterval)rollingFrequency {
+    __block NSTimeInterval result;
+
+    dispatch_block_t block = ^{
+        result = _rollingFrequency;
+    };
+
+    // The design of this method is taken from the DDAbstractLogger implementation.
+    // For extensive documentation please refer to the DDAbstractLogger implementation.
+
+    // Note: The internal implementation should access the rollingFrequency variable directly,
+    // This method is designed explicitly for external access.
+    //
+    // Using "self." syntax to go through this method will cause immediate deadlock.
+    // This is the intended result. Fix it by accessing the ivar directly.
+    // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
+
+    NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+    NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
+
+    dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+
+    dispatch_sync(globalLoggingQueue, ^{
+        dispatch_sync(self.loggerQueue, block);
+    });
+
+    return result;
+}
+
+- (void)setRollingFrequency:(NSTimeInterval)newRollingFrequency {
+    dispatch_block_t block = ^{
+        @autoreleasepool {
+            _rollingFrequency = newRollingFrequency;
+            [self maybeRollLogFileDueToAge];
+        }
+    };
+
+    // The design of this method is taken from the DDAbstractLogger implementation.
+    // For extensive documentation please refer to the DDAbstractLogger implementation.
+
+    // Note: The internal implementation should access the rollingFrequency variable directly,
+    // This method is designed explicitly for external access.
+    //
+    // Using "self." syntax to go through this method will cause immediate deadlock.
+    // This is the intended result. Fix it by accessing the ivar directly.
+    // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
+
+    NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+    NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
+
+    dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+
+    dispatch_async(globalLoggingQueue, ^{
+        dispatch_async(self.loggerQueue, block);
+    });
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark File Rolling
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+- (void)scheduleTimerToRollLogFileDueToAge {
+    if (_rollingTimer) {
+        dispatch_source_cancel(_rollingTimer);
+        _rollingTimer = NULL;
+    }
+
+    if (_currentLogFileInfo == nil || _rollingFrequency <= 0.0) {
+        return;
+    }
+
+    NSDate *logFileCreationDate = [_currentLogFileInfo creationDate];
+
+    NSTimeInterval ti = [logFileCreationDate timeIntervalSinceReferenceDate];
+    ti += _rollingFrequency;
+
+    NSDate *logFileRollingDate = [NSDate dateWithTimeIntervalSinceReferenceDate:ti];
+
+    NSLogVerbose(@"DDFileLogger: scheduleTimerToRollLogFileDueToAge");
+
+    NSLogVerbose(@"DDFileLogger: logFileCreationDate: %@", logFileCreationDate);
+    NSLogVerbose(@"DDFileLogger: logFileRollingDate : %@", logFileRollingDate);
+
+    _rollingTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.loggerQueue);
+
+    dispatch_source_set_event_handler(_rollingTimer, ^{ @autoreleasepool {
+                                                           [self maybeRollLogFileDueToAge];
+                                                       } });
+
+    #if !OS_OBJECT_USE_OBJC
+    dispatch_source_t theRollingTimer = _rollingTimer;
+    dispatch_source_set_cancel_handler(_rollingTimer, ^{
+        dispatch_release(theRollingTimer);
+    });
+    #endif
+
+    uint64_t delay = (uint64_t)([logFileRollingDate timeIntervalSinceNow] * NSEC_PER_SEC);
+    dispatch_time_t fireTime = dispatch_time(DISPATCH_TIME_NOW, delay);
+
+    dispatch_source_set_timer(_rollingTimer, fireTime, DISPATCH_TIME_FOREVER, 1.0);
+    dispatch_resume(_rollingTimer);
+}
+
+- (void)rollLogFile {
+    [self rollLogFileWithCompletionBlock:nil];
+}
+
+- (void)rollLogFileWithCompletionBlock:(void (^)())completionBlock {
+    // This method is public.
+    // We need to execute the rolling on our logging thread/queue.
+
+    dispatch_block_t block = ^{
+        @autoreleasepool {
+            [self rollLogFileNow];
+
+            if (completionBlock) {
+                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+                    completionBlock();
+                });
+            }
+        }
+    };
+
+    // The design of this method is taken from the DDAbstractLogger implementation.
+    // For extensive documentation please refer to the DDAbstractLogger implementation.
+
+    if ([self isOnInternalLoggerQueue]) {
+        block();
+    } else {
+        dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+        NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+
+        dispatch_async(globalLoggingQueue, ^{
+            dispatch_async(self.loggerQueue, block);
+        });
+    }
+}
+
+- (void)rollLogFileNow {
+    NSLogVerbose(@"DDFileLogger: rollLogFileNow");
+
+    if (_currentLogFileHandle == nil) {
+        return;
+    }
+
+    [_currentLogFileHandle synchronizeFile];
+    [_currentLogFileHandle closeFile];
+    _currentLogFileHandle = nil;
+
+    _currentLogFileInfo.isArchived = YES;
+
+    if ([logFileManager respondsToSelector:@selector(didRollAndArchiveLogFile:)]) {
+        [logFileManager didRollAndArchiveLogFile:(_currentLogFileInfo.filePath)];
+    }
+
+    _currentLogFileInfo = nil;
+
+    if (_currentLogFileVnode) {
+        dispatch_source_cancel(_currentLogFileVnode);
+        _currentLogFileVnode = NULL;
+    }
+
+    if (_rollingTimer) {
+        dispatch_source_cancel(_rollingTimer);
+        _rollingTimer = NULL;
+    }
+}
+
+- (void)maybeRollLogFileDueToAge {
+    if (_rollingFrequency > 0.0 && _currentLogFileInfo.age >= _rollingFrequency) {
+        NSLogVerbose(@"DDFileLogger: Rolling log file due to age...");
+
+        [self rollLogFileNow];
+    } else {
+        [self scheduleTimerToRollLogFileDueToAge];
+    }
+}
+
+- (void)maybeRollLogFileDueToSize {
+    // This method is called from logMessage.
+    // Keep it FAST.
+
+    // Note: Use direct access to maximumFileSize variable.
+    // We specifically wrote our own getter/setter method to allow us to do this (for performance reasons).
+
+    if (_maximumFileSize > 0) {
+        unsigned long long fileSize = [_currentLogFileHandle offsetInFile];
+
+        if (fileSize >= _maximumFileSize) {
+            NSLogVerbose(@"DDFileLogger: Rolling log file due to size (%qu)...", fileSize);
+
+            [self rollLogFileNow];
+        }
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark File Logging
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Returns the log file that should be used.
+ * If there is an existing log file that is suitable,
+ * within the constraints of maximumFileSize and rollingFrequency, then it is returned.
+ *
+ * Otherwise a new file is created and returned.
+ **/
+- (DDLogFileInfo *)currentLogFileInfo {
+    if (_currentLogFileInfo == nil) {
+        NSArray *sortedLogFileInfos = [logFileManager sortedLogFileInfos];
+
+        if ([sortedLogFileInfos count] > 0) {
+            DDLogFileInfo *mostRecentLogFileInfo = sortedLogFileInfos[0];
+
+            BOOL shouldArchiveMostRecent = NO;
+
+            if (mostRecentLogFileInfo.isArchived) {
+                shouldArchiveMostRecent = NO;
+            } else if (_maximumFileSize > 0 && mostRecentLogFileInfo.fileSize >= _maximumFileSize) {
+                shouldArchiveMostRecent = YES;
+            } else if (_rollingFrequency > 0.0 && mostRecentLogFileInfo.age >= _rollingFrequency) {
+                shouldArchiveMostRecent = YES;
+            }
+
+        #if TARGET_OS_IPHONE
+            // When creating log file on iOS we're setting NSFileProtectionKey attribute to NSFileProtectionCompleteUnlessOpen.
+            //
+            // But in case if app is able to launch from background we need to have an ability to open log file any time we
+            // want (even if device is locked). Thats why that attribute have to be changed to
+            // NSFileProtectionCompleteUntilFirstUserAuthentication.
+            //
+            // If previous log was created when app wasn't running in background, but now it is - we archive it and create
+            // a new one.
+            //
+            // If user has owerwritten to NSFileProtectionNone there is no neeed to create a new one.
+
+            if (!_doNotReuseLogFiles && doesAppRunInBackground()) {
+                NSString *key = mostRecentLogFileInfo.fileAttributes[NSFileProtectionKey];
+
+                if ([key length] > 0 && !([key isEqualToString:NSFileProtectionCompleteUntilFirstUserAuthentication] || [key isEqualToString:NSFileProtectionNone])) {
+                    shouldArchiveMostRecent = YES;
+                }
+            }
+
+        #endif
+
+            if (!_doNotReuseLogFiles && !mostRecentLogFileInfo.isArchived && !shouldArchiveMostRecent) {
+                NSLogVerbose(@"DDFileLogger: Resuming logging with file %@", mostRecentLogFileInfo.fileName);
+
+                _currentLogFileInfo = mostRecentLogFileInfo;
+            } else {
+                if (shouldArchiveMostRecent) {
+                    mostRecentLogFileInfo.isArchived = YES;
+
+                    if ([logFileManager respondsToSelector:@selector(didArchiveLogFile:)]) {
+                        [logFileManager didArchiveLogFile:(mostRecentLogFileInfo.filePath)];
+                    }
+                }
+            }
+        }
+
+        if (_currentLogFileInfo == nil) {
+            NSString *currentLogFilePath = [logFileManager createNewLogFile];
+
+            _currentLogFileInfo = [[DDLogFileInfo alloc] initWithFilePath:currentLogFilePath];
+        }
+    }
+
+    return _currentLogFileInfo;
+}
+
+- (NSFileHandle *)currentLogFileHandle {
+    if (_currentLogFileHandle == nil) {
+        NSString *logFilePath = [[self currentLogFileInfo] filePath];
+
+        _currentLogFileHandle = [NSFileHandle fileHandleForWritingAtPath:logFilePath];
+        [_currentLogFileHandle seekToEndOfFile];
+
+        if (_currentLogFileHandle) {
+            [self scheduleTimerToRollLogFileDueToAge];
+
+            // Here we are monitoring the log file. In case if it would be deleted ormoved
+            // somewhere we want to roll it and use a new one.
+            _currentLogFileVnode = dispatch_source_create(
+                    DISPATCH_SOURCE_TYPE_VNODE,
+                    [_currentLogFileHandle fileDescriptor],
+                    DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME,
+                    self.loggerQueue
+                    );
+
+            dispatch_source_set_event_handler(_currentLogFileVnode, ^{ @autoreleasepool {
+                                                                          NSLogInfo(@"DDFileLogger: Current logfile was moved. Rolling it and creating a new one");
+                                                                          [self rollLogFileNow];
+                                                                      } });
+
+            #if !OS_OBJECT_USE_OBJC
+            dispatch_source_t vnode = _currentLogFileVnode;
+            dispatch_source_set_cancel_handler(_currentLogFileVnode, ^{
+                dispatch_release(vnode);
+            });
+            #endif
+
+            dispatch_resume(_currentLogFileVnode);
+        }
+    }
+
+    return _currentLogFileHandle;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark DDLogger Protocol
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+static int exception_count = 0;
+- (void)logMessage:(DDLogMessage *)logMessage {
+    NSString *message = logMessage->_message;
+    BOOL isFormatted = NO;
+
+    if (_logFormatter) {
+        message = [_logFormatter formatLogMessage:logMessage];
+        isFormatted = message != logMessage->_message;
+    }
+
+    if (message) {
+        if ((!isFormatted || _automaticallyAppendNewlineForCustomFormatters) &&
+            (![message hasSuffix:@"\n"])) {
+            message = [message stringByAppendingString:@"\n"];
+        }
+
+        NSData *logData = [message dataUsingEncoding:NSUTF8StringEncoding];
+
+        @try {
+            [[self currentLogFileHandle] writeData:logData];
+
+            [self maybeRollLogFileDueToSize];
+        } @catch (NSException *exception) {
+            exception_count++;
+
+            if (exception_count <= 10) {
+                NSLogError(@"DDFileLogger.logMessage: %@", exception);
+
+                if (exception_count == 10) {
+                    NSLogError(@"DDFileLogger.logMessage: Too many exceptions -- will not log any more of them.");
+                }
+            }
+        }
+    }
+}
+
+- (void)willRemoveLogger {
+    // If you override me be sure to invoke [super willRemoveLogger];
+
+    [self rollLogFileNow];
+}
+
+- (NSString *)loggerName {
+    return @"cocoa.lumberjack.fileLogger";
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#if TARGET_IPHONE_SIMULATOR
+    static NSString * const kDDXAttrArchivedName = @"archived";
+#else
+    static NSString * const kDDXAttrArchivedName = @"lumberjack.log.archived";
+#endif
+
+@interface DDLogFileInfo () {
+    __strong NSString *_filePath;
+    __strong NSString *_fileName;
+    
+    __strong NSDictionary *_fileAttributes;
+    
+    __strong NSDate *_creationDate;
+    __strong NSDate *_modificationDate;
+    
+    unsigned long long _fileSize;
+}
+
+@end
+
+
+@implementation DDLogFileInfo
+
+@synthesize filePath;
+
+@dynamic fileName;
+@dynamic fileAttributes;
+@dynamic creationDate;
+@dynamic modificationDate;
+@dynamic fileSize;
+@dynamic age;
+
+@dynamic isArchived;
+
+
+#pragma mark Lifecycle
+
++ (instancetype)logFileWithPath:(NSString *)aFilePath {
+    return [[self alloc] initWithFilePath:aFilePath];
+}
+
+- (instancetype)initWithFilePath:(NSString *)aFilePath {
+    if ((self = [super init])) {
+        filePath = [aFilePath copy];
+    }
+
+    return self;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Standard Info
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+- (NSDictionary *)fileAttributes {
+    if (_fileAttributes == nil) {
+        _fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
+    }
+
+    return _fileAttributes;
+}
+
+- (NSString *)fileName {
+    if (_fileName == nil) {
+        _fileName = [filePath lastPathComponent];
+    }
+
+    return _fileName;
+}
+
+- (NSDate *)modificationDate {
+    if (_modificationDate == nil) {
+        _modificationDate = self.fileAttributes[NSFileModificationDate];
+    }
+
+    return _modificationDate;
+}
+
+- (NSDate *)creationDate {
+    if (_creationDate == nil) {
+        _creationDate = self.fileAttributes[NSFileCreationDate];
+    }
+
+    return _creationDate;
+}
+
+- (unsigned long long)fileSize {
+    if (_fileSize == 0) {
+        _fileSize = [self.fileAttributes[NSFileSize] unsignedLongLongValue];
+    }
+
+    return _fileSize;
+}
+
+- (NSTimeInterval)age {
+    return [[self creationDate] timeIntervalSinceNow] * -1.0;
+}
+
+- (NSString *)description {
+    return [@{ @"filePath": self.filePath ? : @"",
+               @"fileName": self.fileName ? : @"",
+               @"fileAttributes": self.fileAttributes ? : @"",
+               @"creationDate": self.creationDate ? : @"",
+               @"modificationDate": self.modificationDate ? : @"",
+               @"fileSize": @(self.fileSize),
+               @"age": @(self.age),
+               @"isArchived": @(self.isArchived) } description];
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Archiving
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+- (BOOL)isArchived {
+#if TARGET_IPHONE_SIMULATOR
+
+    // Extended attributes don't work properly on the simulator.
+    // So we have to use a less attractive alternative.
+    // See full explanation in the header file.
+
+    return [self hasExtensionAttributeWithName:kDDXAttrArchivedName];
+
+#else
+
+    return [self hasExtendedAttributeWithName:kDDXAttrArchivedName];
+
+#endif
+}
+
+- (void)setIsArchived:(BOOL)flag {
+#if TARGET_IPHONE_SIMULATOR
+
+    // Extended attributes don't work properly on the simulator.
+    // So we have to use a less attractive alternative.
+    // See full explanation in the header file.
+
+    if (flag) {
+        [self addExtensionAttributeWithName:kDDXAttrArchivedName];
+    } else {
+        [self removeExtensionAttributeWithName:kDDXAttrArchivedName];
+    }
+
+#else
+
+    if (flag) {
+        [self addExtendedAttributeWithName:kDDXAttrArchivedName];
+    } else {
+        [self removeExtendedAttributeWithName:kDDXAttrArchivedName];
+    }
+
+#endif
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Changes
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+- (void)reset {
+    _fileName = nil;
+    _fileAttributes = nil;
+    _creationDate = nil;
+    _modificationDate = nil;
+}
+
+- (void)renameFile:(NSString *)newFileName {
+    // This method is only used on the iPhone simulator, where normal extended attributes are broken.
+    // See full explanation in the header file.
+
+    if (![newFileName isEqualToString:[self fileName]]) {
+        NSString *fileDir = [filePath stringByDeletingLastPathComponent];
+
+        NSString *newFilePath = [fileDir stringByAppendingPathComponent:newFileName];
+
+        NSLogVerbose(@"DDLogFileInfo: Renaming file: '%@' -> '%@'", self.fileName, newFileName);
+
+        NSError *error = nil;
+
+        if ([[NSFileManager defaultManager] fileExistsAtPath:newFilePath] &&
+            ![[NSFileManager defaultManager] removeItemAtPath:newFilePath error:&error]) {
+            NSLogError(@"DDLogFileInfo: Error deleting archive (%@): %@", self.fileName, error);
+        }
+
+        if (![[NSFileManager defaultManager] moveItemAtPath:filePath toPath:newFilePath error:&error]) {
+            NSLogError(@"DDLogFileInfo: Error renaming file (%@): %@", self.fileName, error);
+        }
+
+        filePath = newFilePath;
+        [self reset];
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Attribute Management
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#if TARGET_IPHONE_SIMULATOR
+
+// Extended attributes don't work properly on the simulator.
+// So we have to use a less attractive alternative.
+// See full explanation in the header file.
+
+- (BOOL)hasExtensionAttributeWithName:(NSString *)attrName {
+    // This method is only used on the iPhone simulator, where normal extended attributes are broken.
+    // See full explanation in the header file.
+
+    // Split the file name into components. File name may have various format, but generally
+    // structure is same:
+    //
+    // <name part>.<extension part> and <name part>.archived.<extension part>
+    // or
+    // <name part> and <name part>.archived
+    //
+    // So we want to search for the attrName in the components (ignoring the first array index).
+
+    NSArray *components = [[self fileName] componentsSeparatedByString:@"."];
+
+    // Watch out for file names without an extension
+
+    for (NSUInteger i = 1; i < components.count; i++) {
+        NSString *attr = components[i];
+
+        if ([attrName isEqualToString:attr]) {
+            return YES;
+        }
+    }
+
+    return NO;
+}
+
+- (void)addExtensionAttributeWithName:(NSString *)attrName {
+    // This method is only used on the iPhone simulator, where normal extended attributes are broken.
+    // See full explanation in the header file.
+
+    if ([attrName length] == 0) {
+        return;
+    }
+
+    // Example:
+    // attrName = "archived"
+    //
+    // "mylog.txt" -> "mylog.archived.txt"
+    // "mylog"     -> "mylog.archived"
+
+    NSArray *components = [[self fileName] componentsSeparatedByString:@"."];
+
+    NSUInteger count = [components count];
+
+    NSUInteger estimatedNewLength = [[self fileName] length] + [attrName length] + 1;
+    NSMutableString *newFileName = [NSMutableString stringWithCapacity:estimatedNewLength];
+
+    if (count > 0) {
+        [newFileName appendString:components.firstObject];
+    }
+
+    NSString *lastExt = @"";
+
+    NSUInteger i;
+
+    for (i = 1; i < count; i++) {
+        NSString *attr = components[i];
+
+        if ([attr length] == 0) {
+            continue;
+        }
+
+        if ([attrName isEqualToString:attr]) {
+            // Extension attribute already exists in file name
+            return;
+        }
+
+        if ([lastExt length] > 0) {
+            [newFileName appendFormat:@".%@", lastExt];
+        }
+
+        lastExt = attr;
+    }
+
+    [newFileName appendFormat:@".%@", attrName];
+
+    if ([lastExt length] > 0) {
+        [newFileName appendFormat:@".%@", lastExt];
+    }
+
+    [self renameFile:newFileName];
+}
+
+- (void)removeExtensionAttributeWithName:(NSString *)attrName {
+    // This method is only used on the iPhone simulator, where normal extended attributes are broken.
+    // See full explanation in the header file.
+
+    if ([attrName length] == 0) {
+        return;
+    }
+
+    // Example:
+    // attrName = "archived"
+    //
+    // "mylog.archived.txt" -> "mylog.txt"
+    // "mylog.archived"     -> "mylog"
+
+    NSArray *components = [[self fileName] componentsSeparatedByString:@"."];
+
+    NSUInteger count = [components count];
+
+    NSUInteger estimatedNewLength = [[self fileName] length];
+    NSMutableString *newFileName = [NSMutableString stringWithCapacity:estimatedNewLength];
+
+    if (count > 0) {
+        [newFileName appendString:components.firstObject];
+    }
+
+    BOOL found = NO;
+
+    NSUInteger i;
+
+    for (i = 1; i < count; i++) {
+        NSString *attr = components[i];
+
+        if ([attrName isEqualToString:attr]) {
+            found = YES;
+        } else {
+            [newFileName appendFormat:@".%@", attr];
+        }
+    }
+
+    if (found) {
+        [self renameFile:newFileName];
+    }
+}
+
+#else /* if TARGET_IPHONE_SIMULATOR */
+
+- (BOOL)hasExtendedAttributeWithName:(NSString *)attrName {
+    const char *path = [filePath UTF8String];
+    const char *name = [attrName UTF8String];
+
+    ssize_t result = getxattr(path, name, NULL, 0, 0, 0);
+
+    return (result >= 0);
+}
+
+- (void)addExtendedAttributeWithName:(NSString *)attrName {
+    const char *path = [filePath UTF8String];
+    const char *name = [attrName UTF8String];
+
+    int result = setxattr(path, name, NULL, 0, 0, 0);
+
+    if (result < 0) {
+        NSLogError(@"DDLogFileInfo: setxattr(%@, %@): error = %s",
+                   attrName,
+                   filePath,
+                   strerror(errno));
+    }
+}
+
+- (void)removeExtendedAttributeWithName:(NSString *)attrName {
+    const char *path = [filePath UTF8String];
+    const char *name = [attrName UTF8String];
+
+    int result = removexattr(path, name, 0);
+
+    if (result < 0 && errno != ENOATTR) {
+        NSLogError(@"DDLogFileInfo: removexattr(%@, %@): error = %s",
+                   attrName,
+                   self.fileName,
+                   strerror(errno));
+    }
+}
+
+#endif /* if TARGET_IPHONE_SIMULATOR */
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Comparisons
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+- (BOOL)isEqual:(id)object {
+    if ([object isKindOfClass:[self class]]) {
+        DDLogFileInfo *another = (DDLogFileInfo *)object;
+
+        return [filePath isEqualToString:[another filePath]];
+    }
+
+    return NO;
+}
+
+- (NSComparisonResult)reverseCompareByCreationDate:(DDLogFileInfo *)another {
+    NSDate *us = [self creationDate];
+    NSDate *them = [another creationDate];
+
+    NSComparisonResult result = [us compare:them];
+
+    if (result == NSOrderedAscending) {
+        return NSOrderedDescending;
+    }
+
+    if (result == NSOrderedDescending) {
+        return NSOrderedAscending;
+    }
+
+    return NSOrderedSame;
+}
+
+- (NSComparisonResult)reverseCompareByModificationDate:(DDLogFileInfo *)another {
+    NSDate *us = [self modificationDate];
+    NSDate *them = [another modificationDate];
+
+    NSComparisonResult result = [us compare:them];
+
+    if (result == NSOrderedAscending) {
+        return NSOrderedDescending;
+    }
+
+    if (result == NSOrderedDescending) {
+        return NSOrderedAscending;
+    }
+
+    return NSOrderedSame;
+}
+
+@end
+
+#if TARGET_OS_IPHONE
+/**
+ * When creating log file on iOS we're setting NSFileProtectionKey attribute to NSFileProtectionCompleteUnlessOpen.
+ *
+ * But in case if app is able to launch from background we need to have an ability to open log file any time we
+ * want (even if device is locked). Thats why that attribute have to be changed to
+ * NSFileProtectionCompleteUntilFirstUserAuthentication.
+ */
+BOOL doesAppRunInBackground() {
+    BOOL answer = NO;
+
+    NSArray *backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"];
+
+    for (NSString *mode in backgroundModes) {
+        if (mode.length > 0) {
+            answer = YES;
+            break;
+        }
+    }
+
+    return answer;
+}
+
+#endif
diff --git a/cocoalumberjack/Classes/DDLegacyMacros.h b/cocoalumberjack/Classes/DDLegacyMacros.h
new file mode 100644
index 0000000..e0671b9
--- /dev/null
+++ b/cocoalumberjack/Classes/DDLegacyMacros.h
@@ -0,0 +1,75 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+/**
+ * Legacy macros used for 1.9.x backwards compatibility.
+ *
+ * Imported by default when importing a DDLog.h directly and DD_LEGACY_MACROS is not defined and set to 0.
+ **/
+#if DD_LEGACY_MACROS
+
+#warning CocoaLumberjack 1.9.x legacy macros enabled. \
+Disable legacy macros by importing CocoaLumberjack.h or DDLogMacros.h instead of DDLog.h or add `#define DD_LEGACY_MACROS 0` before importing DDLog.h.
+
+#ifndef LOG_LEVEL_DEF
+    #define LOG_LEVEL_DEF ddLogLevel
+#endif
+
+#define LOG_FLAG_ERROR    DDLogFlagError
+#define LOG_FLAG_WARN     DDLogFlagWarning
+#define LOG_FLAG_INFO     DDLogFlagInfo
+#define LOG_FLAG_DEBUG    DDLogFlagDebug
+#define LOG_FLAG_VERBOSE  DDLogFlagVerbose
+
+#define LOG_LEVEL_OFF     DDLogLevelOff
+#define LOG_LEVEL_ERROR   DDLogLevelError
+#define LOG_LEVEL_WARN    DDLogLevelWarning
+#define LOG_LEVEL_INFO    DDLogLevelInfo
+#define LOG_LEVEL_DEBUG   DDLogLevelDebug
+#define LOG_LEVEL_VERBOSE DDLogLevelVerbose
+#define LOG_LEVEL_ALL     DDLogLevelAll
+
+#define LOG_ASYNC_ENABLED YES
+
+#define LOG_ASYNC_ERROR    ( NO && LOG_ASYNC_ENABLED)
+#define LOG_ASYNC_WARN     (YES && LOG_ASYNC_ENABLED)
+#define LOG_ASYNC_INFO     (YES && LOG_ASYNC_ENABLED)
+#define LOG_ASYNC_DEBUG    (YES && LOG_ASYNC_ENABLED)
+#define LOG_ASYNC_VERBOSE  (YES && LOG_ASYNC_ENABLED)
+
+#define LOG_MACRO(isAsynchronous, lvl, flg, ctx, atag, fnct, frmt, ...) \
+        [DDLog log : isAsynchronous                                     \
+             level : lvl                                                \
+              flag : flg                                                \
+           context : ctx                                                \
+              file : __FILE__                                           \
+          function : fnct                                               \
+              line : __LINE__                                           \
+               tag : atag                                               \
+            format : (frmt), ## __VA_ARGS__]
+
+#define LOG_MAYBE(async, lvl, flg, ctx, fnct, frmt, ...)                       \
+        do { if(lvl & flg) LOG_MACRO(async, lvl, flg, ctx, nil, fnct, frmt, ##__VA_ARGS__); } while(0)
+
+#define LOG_OBJC_MAYBE(async, lvl, flg, ctx, frmt, ...) \
+        LOG_MAYBE(async, lvl, flg, ctx, __PRETTY_FUNCTION__, frmt, ## __VA_ARGS__)
+
+#define DDLogError(frmt, ...)   LOG_OBJC_MAYBE(LOG_ASYNC_ERROR,   LOG_LEVEL_DEF, LOG_FLAG_ERROR,   0, frmt, ##__VA_ARGS__)
+#define DDLogWarn(frmt, ...)    LOG_OBJC_MAYBE(LOG_ASYNC_WARN,    LOG_LEVEL_DEF, LOG_FLAG_WARN,    0, frmt, ##__VA_ARGS__)
+#define DDLogInfo(frmt, ...)    LOG_OBJC_MAYBE(LOG_ASYNC_INFO,    LOG_LEVEL_DEF, LOG_FLAG_INFO,    0, frmt, ##__VA_ARGS__)
+#define DDLogDebug(frmt, ...)   LOG_OBJC_MAYBE(LOG_ASYNC_DEBUG,   LOG_LEVEL_DEF, LOG_FLAG_DEBUG,   0, frmt, ##__VA_ARGS__)
+#define DDLogVerbose(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_VERBOSE, LOG_LEVEL_DEF, LOG_FLAG_VERBOSE, 0, frmt, ##__VA_ARGS__)
+
+#endif
diff --git a/cocoalumberjack/Classes/DDLog+LOGV.h b/cocoalumberjack/Classes/DDLog+LOGV.h
new file mode 100644
index 0000000..cf4bfc3
--- /dev/null
+++ b/cocoalumberjack/Classes/DDLog+LOGV.h
@@ -0,0 +1,83 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+// Disable legacy macros
+#ifndef DD_LEGACY_MACROS
+    #define DD_LEGACY_MACROS 0
+#endif
+
+#import "DDLog.h"
+
+/**
+ * The constant/variable/method responsible for controlling the current log level.
+ **/
+#ifndef LOG_LEVEL_DEF
+    #define LOG_LEVEL_DEF ddLogLevel
+#endif
+
+/**
+ * Whether async should be used by log messages, excluding error messages that are always sent sync.
+ **/
+#ifndef LOG_ASYNC_ENABLED
+    #define LOG_ASYNC_ENABLED YES
+#endif
+
+/**
+ * This is the single macro that all other macros below compile into.
+ * This big multiline macro makes all the other macros easier to read.
+ **/
+#define LOGV_MACRO(isAsynchronous, lvl, flg, ctx, atag, fnct, frmt, avalist) \
+        [DDLog log : isAsynchronous                                     \
+             level : lvl                                                \
+              flag : flg                                                \
+           context : ctx                                                \
+              file : __FILE__                                           \
+          function : fnct                                               \
+              line : __LINE__                                           \
+               tag : atag                                               \
+            format : frmt                                               \
+              args : avalist]
+
+/**
+ * Define version of the macro that only execute if the log level is above the threshold.
+ * The compiled versions essentially look like this:
+ *
+ * if (logFlagForThisLogMsg & ddLogLevel) { execute log message }
+ *
+ * When LOG_LEVEL_DEF is defined as ddLogLevel.
+ *
+ * As shown further below, Lumberjack actually uses a bitmask as opposed to primitive log levels.
+ * This allows for a great amount of flexibility and some pretty advanced fine grained logging techniques.
+ *
+ * Note that when compiler optimizations are enabled (as they are for your release builds),
+ * the log messages above your logging threshold will automatically be compiled out.
+ *
+ * (If the compiler sees LOG_LEVEL_DEF/ddLogLevel declared as a constant, the compiler simply checks to see
+ *  if the 'if' statement would execute, and if not it strips it from the binary.)
+ *
+ * We also define shorthand versions for asynchronous and synchronous logging.
+ **/
+#define LOGV_MAYBE(async, lvl, flg, ctx, tag, fnct, frmt, avalist) \
+        do { if(lvl & flg) LOGV_MACRO(async, lvl, flg, ctx, tag, fnct, frmt, avalist); } while(0)
+
+/**
+ * Ready to use log macros with no context or tag.
+ **/
+#define DDLogVError(frmt, avalist)   LOGV_MAYBE(NO,                LOG_LEVEL_DEF, DDLogFlagError,   0, nil, __PRETTY_FUNCTION__, frmt, avalist)
+#define DDLogVWarn(frmt, avalist)    LOGV_MAYBE(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, DDLogFlagWarning, 0, nil, __PRETTY_FUNCTION__, frmt, avalist)
+#define DDLogVInfo(frmt, avalist)    LOGV_MAYBE(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, DDLogFlagInfo,    0, nil, __PRETTY_FUNCTION__, frmt, avalist)
+#define DDLogVDebug(frmt, avalist)   LOGV_MAYBE(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, DDLogFlagDebug,   0, nil, __PRETTY_FUNCTION__, frmt, avalist)
+#define DDLogVVerbose(frmt, avalist) LOGV_MAYBE(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, DDLogFlagVerbose, 0, nil, __PRETTY_FUNCTION__, frmt, avalist)
+
diff --git a/cocoalumberjack/Classes/DDLog.h b/cocoalumberjack/Classes/DDLog.h
new file mode 100644
index 0000000..b7a817e
--- /dev/null
+++ b/cocoalumberjack/Classes/DDLog.h
@@ -0,0 +1,743 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+#import <Foundation/Foundation.h>
+
+// Enable 1.9.x legacy macros if imported directly
+#ifndef DD_LEGACY_MACROS
+    #define DD_LEGACY_MACROS 1
+#endif
+// DD_LEGACY_MACROS is checked in the file itself
+#import "DDLegacyMacros.h"
+
+#if OS_OBJECT_USE_OBJC
+    #define DISPATCH_QUEUE_REFERENCE_TYPE strong
+#else
+    #define DISPATCH_QUEUE_REFERENCE_TYPE assign
+#endif
+
+@class DDLogMessage;
+@protocol DDLogger;
+@protocol DDLogFormatter;
+
+/**
+ * Define the standard options.
+ *
+ * We default to only 4 levels because it makes it easier for beginners
+ * to make the transition to a logging framework.
+ *
+ * More advanced users may choose to completely customize the levels (and level names) to suite their needs.
+ * For more information on this see the "Custom Log Levels" page:
+ * Documentation/CustomLogLevels.md
+ *
+ * Advanced users may also notice that we're using a bitmask.
+ * This is to allow for custom fine grained logging:
+ * Documentation/FineGrainedLogging.md
+ *
+ * -- Flags --
+ *
+ * Typically you will use the LOG_LEVELS (see below), but the flags may be used directly in certain situations.
+ * For example, say you have a lot of warning log messages, and you wanted to disable them.
+ * However, you still needed to see your error and info log messages.
+ * You could accomplish that with the following:
+ *
+ * static const DDLogLevel ddLogLevel = DDLogFlagError | DDLogFlagInfo;
+ *
+ * When LOG_LEVEL_DEF is defined as ddLogLevel.
+ *
+ * Flags may also be consulted when writing custom log formatters,
+ * as the DDLogMessage class captures the individual flag that caused the log message to fire.
+ *
+ * -- Levels --
+ *
+ * Log levels are simply the proper bitmask of the flags.
+ *
+ * -- Booleans --
+ *
+ * The booleans may be used when your logging code involves more than one line.
+ * For example:
+ *
+ * if (LOG_VERBOSE) {
+ *     for (id sprocket in sprockets)
+ *         DDLogVerbose(@"sprocket: %@", [sprocket description])
+ * }
+ *
+ * -- Async --
+ *
+ * Defines the default asynchronous options.
+ * The default philosophy for asynchronous logging is very simple:
+ *
+ * Log messages with errors should be executed synchronously.
+ *     After all, an error just occurred. The application could be unstable.
+ *
+ * All other log messages, such as debug output, are executed asynchronously.
+ *     After all, if it wasn't an error, then it was just informational output,
+ *     or something the application was easily able to recover from.
+ *
+ * -- Changes --
+ *
+ * You are strongly discouraged from modifying this file.
+ * If you do, you make it more difficult on yourself to merge future bug fixes and improvements from the project.
+ * Instead, create your own MyLogging.h or ApplicationNameLogging.h or CompanyLogging.h
+ *
+ * For an example of customizing your logging experience, see the "Custom Log Levels" page:
+ * Documentation/CustomLogLevels.md
+ **/
+
+/**
+ *  Flags accompany each log. They are used together with levels to filter out logs.
+ */
+typedef NS_OPTIONS(NSUInteger, DDLogFlag){
+    /**
+     *  0...00001 DDLogFlagError
+     */
+    DDLogFlagError      = (1 << 0),
+    
+    /**
+     *  0...00010 DDLogFlagWarning
+     */
+    DDLogFlagWarning    = (1 << 1),
+    
+    /**
+     *  0...00100 DDLogFlagInfo
+     */
+    DDLogFlagInfo       = (1 << 2),
+    
+    /**
+     *  0...01000 DDLogFlagDebug
+     */
+    DDLogFlagDebug      = (1 << 3),
+    
+    /**
+     *  0...10000 DDLogFlagVerbose
+     */
+    DDLogFlagVerbose    = (1 << 4)
+};
+
+/**
+ *  Log levels are used to filter out logs. Used together with flags.
+ */
+typedef NS_ENUM(NSUInteger, DDLogLevel){
+    /**
+     *  No logs
+     */
+    DDLogLevelOff       = 0,
+    
+    /**
+     *  Error logs only
+     */
+    DDLogLevelError     = (DDLogFlagError),
+    
+    /**
+     *  Error and warning logs
+     */
+    DDLogLevelWarning   = (DDLogLevelError   | DDLogFlagWarning),
+    
+    /**
+     *  Error, warning and info logs
+     */
+    DDLogLevelInfo      = (DDLogLevelWarning | DDLogFlagInfo),
+    
+    /**
+     *  Error, warning, info and debug logs
+     */
+    DDLogLevelDebug     = (DDLogLevelInfo    | DDLogFlagDebug),
+    
+    /**
+     *  Error, warning, info, debug and verbose logs
+     */
+    DDLogLevelVerbose   = (DDLogLevelDebug   | DDLogFlagVerbose),
+    
+    /**
+     *  All logs (1...11111)
+     */
+    DDLogLevelAll       = NSUIntegerMax
+};
+
+/**
+ *  Extracts just the file name, no path or extension
+ *
+ *  @param filePath input file path
+ *  @param copy     YES if we want the result to be copied
+ *
+ *  @return the file name
+ */
+NSString * DDExtractFileNameWithoutExtension(const char *filePath, BOOL copy);
+
+/**
+ * The THIS_FILE macro gives you an NSString of the file name.
+ * For simplicity and clarity, the file name does not include the full path or file extension.
+ *
+ * For example: DDLogWarn(@"%@: Unable to find thingy", THIS_FILE) -> @"MyViewController: Unable to find thingy"
+ **/
+#define THIS_FILE         (DDExtractFileNameWithoutExtension(__FILE__, NO))
+
+/**
+ * The THIS_METHOD macro gives you the name of the current objective-c method.
+ *
+ * For example: DDLogWarn(@"%@ - Requires non-nil strings", THIS_METHOD) -> @"setMake:model: requires non-nil strings"
+ *
+ * Note: This does NOT work in straight C functions (non objective-c).
+ * Instead you should use the predefined __FUNCTION__ macro.
+ **/
+#define THIS_METHOD       NSStringFromSelector(_cmd)
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ *  The main class, exposes all logging mechanisms, loggers, ...
+ *  For most of the users, this class is hidden behind the logging functions like `DDLogInfo`
+ */
+@interface DDLog : NSObject
+
+/**
+ * Provides access to the underlying logging queue.
+ * This may be helpful to Logger classes for things like thread synchronization.
+ **/
++ (dispatch_queue_t)loggingQueue;
+
+/**
+ * Logging Primitive.
+ *
+ * This method is used by the macros or logging functions.
+ * It is suggested you stick with the macros as they're easier to use.
+ *
+ *  @param asynchronous YES if the logging is done async, NO if you want to force sync
+ *  @param level        the log level
+ *  @param flag         the log flag
+ *  @param context      the context (if any is defined)
+ *  @param file         the current file
+ *  @param function     the current function
+ *  @param line         the current code line
+ *  @param tag          potential tag
+ *  @param format       the log format
+ */
++ (void)log:(BOOL)asynchronous
+      level:(DDLogLevel)level
+       flag:(DDLogFlag)flag
+    context:(NSInteger)context
+       file:(const char *)file
+   function:(const char *)function
+       line:(NSUInteger)line
+        tag:(id)tag
+     format:(NSString *)format, ... NS_FORMAT_FUNCTION(9,10);
+
+/**
+ * Logging Primitive.
+ *
+ * This method can be used if you have a prepared va_list.
+ * Similar to `log:level:flag:context:file:function:line:tag:format:...`
+ *
+ *  @param asynchronous YES if the logging is done async, NO if you want to force sync
+ *  @param level        the log level
+ *  @param flag         the log flag
+ *  @param context      the context (if any is defined)
+ *  @param file         the current file
+ *  @param function     the current function
+ *  @param line         the current code line
+ *  @param tag          potential tag
+ *  @param format       the log format
+ *  @param argList      the arguments list as a va_list
+ */
++ (void)log:(BOOL)asynchronous
+      level:(DDLogLevel)level
+       flag:(DDLogFlag)flag
+    context:(NSInteger)context
+       file:(const char *)file
+   function:(const char *)function
+       line:(NSUInteger)line
+        tag:(id)tag
+     format:(NSString *)format
+       args:(va_list)argList;
+
+/**
+ *  Logging Primitive.
+ *
+ *  @param asynchronous YES if the logging is done async, NO if you want to force sync
+ *  @param message      the message
+ *  @param level        the log level
+ *  @param flag         the log flag
+ *  @param context      the context (if any is defined)
+ *  @param file         the current file
+ *  @param function     the current function
+ *  @param line         the current code line
+ *  @param tag          potential tag
+ */
++ (void)log:(BOOL)asynchronous
+    message:(NSString *)message
+      level:(DDLogLevel)level
+       flag:(DDLogFlag)flag
+    context:(NSInteger)context
+       file:(const char *)file
+   function:(const char *)function
+       line:(NSUInteger)line
+        tag:(id)tag;
+
+/**
+ * Logging Primitive.
+ *
+ * This method can be used if you manualy prepared DDLogMessage.
+ *
+ *  @param asynchronous YES if the logging is done async, NO if you want to force sync
+ *  @param logMessage   the log message stored in a `DDLogMessage` model object
+ */
++ (void)log:(BOOL)asynchronous
+    message:(DDLogMessage *)logMessage;
+
+/**
+ * Since logging can be asynchronous, there may be times when you want to flush the logs.
+ * The framework invokes this automatically when the application quits.
+ **/
++ (void)flushLog;
+
+/**
+ * Loggers
+ *
+ * In order for your log statements to go somewhere, you should create and add a logger.
+ *
+ * You can add multiple loggers in order to direct your log statements to multiple places.
+ * And each logger can be configured separately.
+ * So you could have, for example, verbose logging to the console, but a concise log file with only warnings & errors.
+ **/
+
+/**
+ * Adds the logger to the system.
+ *
+ * This is equivalent to invoking `[DDLog addLogger:logger withLogLevel:DDLogLevelAll]`.
+ **/
++ (void)addLogger:(id <DDLogger>)logger;
+
+/**
+ * Adds the logger to the system.
+ *
+ * The level that you provide here is a preemptive filter (for performance).
+ * That is, the level specified here will be used to filter out logMessages so that
+ * the logger is never even invoked for the messages.
+ *
+ * More information:
+ * When you issue a log statement, the logging framework iterates over each logger,
+ * and checks to see if it should forward the logMessage to the logger.
+ * This check is done using the level parameter passed to this method.
+ *
+ * For example:
+ *
+ * `[DDLog addLogger:consoleLogger withLogLevel:DDLogLevelVerbose];`
+ * `[DDLog addLogger:fileLogger    withLogLevel:DDLogLevelWarning];`
+ *
+ * `DDLogError(@"oh no");` => gets forwarded to consoleLogger & fileLogger
+ * `DDLogInfo(@"hi");`     => gets forwarded to consoleLogger only
+ *
+ * It is important to remember that Lumberjack uses a BITMASK.
+ * Many developers & third party frameworks may define extra log levels & flags.
+ * For example:
+ *
+ * `#define SOME_FRAMEWORK_LOG_FLAG_TRACE (1 << 6) // 0...1000000`
+ *
+ * So if you specify `DDLogLevelVerbose` to this method, you won't see the framework's trace messages.
+ *
+ * `(SOME_FRAMEWORK_LOG_FLAG_TRACE & DDLogLevelVerbose) => (01000000 & 00011111) => NO`
+ *
+ * Consider passing `DDLogLevelAll` to this method, which has all bits set.
+ * You can also use the exclusive-or bitwise operator to get a bitmask that has all flags set,
+ * except the ones you explicitly don't want. For example, if you wanted everything except verbose & debug:
+ *
+ * `((DDLogLevelAll ^ DDLogLevelVerbose) | DDLogLevelInfo)`
+ **/
++ (void)addLogger:(id <DDLogger>)logger withLevel:(DDLogLevel)level;
+
+/**
+ *  Remove the logger from the system
+ */
++ (void)removeLogger:(id <DDLogger>)logger;
+
+/**
+ *  Remove all the current loggers
+ */
++ (void)removeAllLoggers;
+
+/**
+ *  Return all the current loggers
+ */
++ (NSArray *)allLoggers;
+
+/**
+ * Registered Dynamic Logging
+ *
+ * These methods allow you to obtain a list of classes that are using registered dynamic logging,
+ * and also provides methods to get and set their log level during run time.
+ **/
+
+/**
+ *  Returns an array with the classes that are using registered dynamic logging
+ */
++ (NSArray *)registeredClasses;
+
+/**
+ *  Returns an array with the classes names that are using registered dynamic logging
+ */
++ (NSArray *)registeredClassNames;
+
+/**
+ *  Returns the current log level for a certain class
+ *
+ *  @param aClass `Class` param
+ */
++ (DDLogLevel)levelForClass:(Class)aClass;
+
+/**
+ *  Returns the current log level for a certain class
+ *
+ *  @param aClassName string param
+ */
++ (DDLogLevel)levelForClassWithName:(NSString *)aClassName;
+
+/**
+ *  Set the log level for a certain class
+ *
+ *  @param level  the new level
+ *  @param aClass `Class` param
+ */
++ (void)setLevel:(DDLogLevel)level forClass:(Class)aClass;
+
+/**
+ *  Set the log level for a certain class
+ *
+ *  @param level      the new level
+ *  @param aClassName string param
+ */
++ (void)setLevel:(DDLogLevel)level forClassWithName:(NSString *)aClassName;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ *  This protocol describes a basic logger behavior. 
+ *  Basically, it can log messages, store a logFormatter plus a bunch of optional behaviors.
+ *  (i.e. flush, get its loggerQueue, get its name, ...
+ */
+@protocol DDLogger <NSObject>
+
+/**
+ *  The log message method
+ *
+ *  @param logMessage the message (model)
+ */
+- (void)logMessage:(DDLogMessage *)logMessage;
+
+/**
+ * Formatters may optionally be added to any logger.
+ *
+ * If no formatter is set, the logger simply logs the message as it is given in logMessage,
+ * or it may use its own built in formatting style.
+ **/
+@property (nonatomic, strong) id <DDLogFormatter> logFormatter;
+
+@optional
+
+/**
+ * Since logging is asynchronous, adding and removing loggers is also asynchronous.
+ * In other words, the loggers are added and removed at appropriate times with regards to log messages.
+ *
+ * - Loggers will not receive log messages that were executed prior to when they were added.
+ * - Loggers will not receive log messages that were executed after they were removed.
+ *
+ * These methods are executed in the logging thread/queue.
+ * This is the same thread/queue that will execute every logMessage: invocation.
+ * Loggers may use these methods for thread synchronization or other setup/teardown tasks.
+ **/
+- (void)didAddLogger;
+
+/**
+ *  See the above description for `didAddLoger`
+ */
+- (void)willRemoveLogger;
+
+/**
+ * Some loggers may buffer IO for optimization purposes.
+ * For example, a database logger may only save occasionaly as the disk IO is slow.
+ * In such loggers, this method should be implemented to flush any pending IO.
+ *
+ * This allows invocations of DDLog's flushLog method to be propogated to loggers that need it.
+ *
+ * Note that DDLog's flushLog method is invoked automatically when the application quits,
+ * and it may be also invoked manually by the developer prior to application crashes, or other such reasons.
+ **/
+- (void)flush;
+
+/**
+ * Each logger is executed concurrently with respect to the other loggers.
+ * Thus, a dedicated dispatch queue is used for each logger.
+ * Logger implementations may optionally choose to provide their own dispatch queue.
+ **/
+@property (nonatomic, DISPATCH_QUEUE_REFERENCE_TYPE, readonly) dispatch_queue_t loggerQueue;
+
+/**
+ * If the logger implementation does not choose to provide its own queue,
+ * one will automatically be created for it.
+ * The created queue will receive its name from this method.
+ * This may be helpful for debugging or profiling reasons.
+ **/
+@property (nonatomic, readonly) NSString *loggerName;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ *  This protocol describes the behavior of a log formatter
+ */
+@protocol DDLogFormatter <NSObject>
+@required
+
+/**
+ * Formatters may optionally be added to any logger.
+ * This allows for increased flexibility in the logging environment.
+ * For example, log messages for log files may be formatted differently than log messages for the console.
+ *
+ * For more information about formatters, see the "Custom Formatters" page:
+ * Documentation/CustomFormatters.md
+ *
+ * The formatter may also optionally filter the log message by returning nil,
+ * in which case the logger will not log the message.
+ **/
+- (NSString *)formatLogMessage:(DDLogMessage *)logMessage;
+
+@optional
+
+/**
+ * A single formatter instance can be added to multiple loggers.
+ * These methods provides hooks to notify the formatter of when it's added/removed.
+ *
+ * This is primarily for thread-safety.
+ * If a formatter is explicitly not thread-safe, it may wish to throw an exception if added to multiple loggers.
+ * Or if a formatter has potentially thread-unsafe code (e.g. NSDateFormatter),
+ * it could possibly use these hooks to switch to thread-safe versions of the code.
+ **/
+- (void)didAddToLogger:(id <DDLogger>)logger;
+
+/**
+ *  See the above description for `didAddToLogger:`
+ */
+- (void)willRemoveFromLogger:(id <DDLogger>)logger;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ *  This protocol describes a dynamic logging component
+ */
+@protocol DDRegisteredDynamicLogging
+
+/**
+ * Implement these methods to allow a file's log level to be managed from a central location.
+ *
+ * This is useful if you'd like to be able to change log levels for various parts
+ * of your code from within the running application.
+ *
+ * Imagine pulling up the settings for your application,
+ * and being able to configure the logging level on a per file basis.
+ *
+ * The implementation can be very straight-forward:
+ *
+ * ```
+ * + (int)ddLogLevel
+ * {
+ *     return ddLogLevel;
+ * }
+ *
+ * + (void)ddSetLogLevel:(DDLogLevel)level
+ * {
+ *     ddLogLevel = level;
+ * }
+ * ```
+ **/
++ (DDLogLevel)ddLogLevel;
+
+/**
+ *  See the above description for `ddLogLevel`
+ */
++ (void)ddSetLogLevel:(DDLogLevel)level;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#ifndef NS_DESIGNATED_INITIALIZER
+    #define NS_DESIGNATED_INITIALIZER
+#endif
+
+/**
+ *  Log message options, allow copying certain log elements
+ */
+typedef NS_OPTIONS(NSInteger, DDLogMessageOptions){
+    /**
+     *  Use this to use a copy of the file path
+     */
+    DDLogMessageCopyFile     = 1 << 0,
+    /**
+     *  Use this to use a copy of the function name
+     */
+    DDLogMessageCopyFunction = 1 << 1
+};
+
+/**
+ * The `DDLogMessage` class encapsulates information about the log message.
+ * If you write custom loggers or formatters, you will be dealing with objects of this class.
+ **/
+@interface DDLogMessage : NSObject <NSCopying>
+{
+    // Direct accessors to be used only for performance
+    @public
+    NSString *_message;
+    DDLogLevel _level;
+    DDLogFlag _flag;
+    NSInteger _context;
+    NSString *_file;
+    NSString *_fileName;
+    NSString *_function;
+    NSUInteger _line;
+    id _tag;
+    DDLogMessageOptions _options;
+    NSDate *_timestamp;
+    NSString *_threadID;
+    NSString *_threadName;
+    NSString *_queueLabel;
+}
+
+/**
+ *  Default `init` is not available
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+/**
+ * Standard init method for a log message object.
+ * Used by the logging primitives. (And the macros use the logging primitives.)
+ *
+ * If you find need to manually create logMessage objects, there is one thing you should be aware of:
+ *
+ * If no flags are passed, the method expects the file and function parameters to be string literals.
+ * That is, it expects the given strings to exist for the duration of the object's lifetime,
+ * and it expects the given strings to be immutable.
+ * In other words, it does not copy these strings, it simply points to them.
+ * This is due to the fact that __FILE__ and __FUNCTION__ are usually used to specify these parameters,
+ * so it makes sense to optimize and skip the unnecessary allocations.
+ * However, if you need them to be copied you may use the options parameter to specify this.
+ *
+ *  @param message   the message
+ *  @param level     the log level
+ *  @param flag      the log flag
+ *  @param context   the context (if any is defined)
+ *  @param file      the current file
+ *  @param function  the current function
+ *  @param line      the current code line
+ *  @param tag       potential tag
+ *  @param options   a bitmask which supports DDLogMessageCopyFile and DDLogMessageCopyFunction.
+ *  @param timestamp the log timestamp
+ *
+ *  @return a new instance of a log message model object
+ */
+- (instancetype)initWithMessage:(NSString *)message
+                          level:(DDLogLevel)level
+                           flag:(DDLogFlag)flag
+                        context:(NSInteger)context
+                           file:(NSString *)file
+                       function:(NSString *)function
+                           line:(NSUInteger)line
+                            tag:(id)tag
+                        options:(DDLogMessageOptions)options
+                      timestamp:(NSDate *)timestamp NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Read-only properties
+ **/
+
+/**
+ *  The log message
+ */
+@property (readonly, nonatomic) NSString *message;
+@property (readonly, nonatomic) DDLogLevel level;
+@property (readonly, nonatomic) DDLogFlag flag;
+@property (readonly, nonatomic) NSInteger context;
+@property (readonly, nonatomic) NSString *file;
+@property (readonly, nonatomic) NSString *fileName;
+@property (readonly, nonatomic) NSString *function;
+@property (readonly, nonatomic) NSUInteger line;
+@property (readonly, nonatomic) id tag;
+@property (readonly, nonatomic) DDLogMessageOptions options;
+@property (readonly, nonatomic) NSDate *timestamp;
+@property (readonly, nonatomic) NSString *threadID; // ID as it appears in NSLog calculated from the machThreadID
+@property (readonly, nonatomic) NSString *threadName;
+@property (readonly, nonatomic) NSString *queueLabel;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * The `DDLogger` protocol specifies that an optional formatter can be added to a logger.
+ * Most (but not all) loggers will want to support formatters.
+ *
+ * However, writting getters and setters in a thread safe manner,
+ * while still maintaining maximum speed for the logging process, is a difficult task.
+ *
+ * To do it right, the implementation of the getter/setter has strict requiremenets:
+ * - Must NOT require the `logMessage:` method to acquire a lock.
+ * - Must NOT require the `logMessage:` method to access an atomic property (also a lock of sorts).
+ *
+ * To simplify things, an abstract logger is provided that implements the getter and setter.
+ *
+ * Logger implementations may simply extend this class,
+ * and they can ACCESS THE FORMATTER VARIABLE DIRECTLY from within their `logMessage:` method!
+ **/
+@interface DDAbstractLogger : NSObject <DDLogger>
+{
+    // Direct accessors to be used only for performance
+    @public
+    id <DDLogFormatter> _logFormatter;
+    dispatch_queue_t _loggerQueue;
+}
+
+@property (nonatomic, strong) id <DDLogFormatter> logFormatter;
+@property (nonatomic, DISPATCH_QUEUE_REFERENCE_TYPE) dispatch_queue_t loggerQueue;
+
+// For thread-safety assertions
+
+/**
+ *  Return YES if the current logger uses a global queue for logging
+ */
+@property (nonatomic, readonly, getter=isOnGlobalLoggingQueue)  BOOL onGlobalLoggingQueue;
+
+/**
+ *  Return YES if the current logger uses the internal designated queue for logging
+ */
+@property (nonatomic, readonly, getter=isOnInternalLoggerQueue) BOOL onInternalLoggerQueue;
+
+@end
+
diff --git a/cocoalumberjack/Classes/DDLog.m b/cocoalumberjack/Classes/DDLog.m
new file mode 100644
index 0000000..03c6e7c
--- /dev/null
+++ b/cocoalumberjack/Classes/DDLog.m
@@ -0,0 +1,1167 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+// Disable legacy macros
+#ifndef DD_LEGACY_MACROS
+    #define DD_LEGACY_MACROS 0
+#endif
+
+#import "DDLog.h"
+
+#import <pthread.h>
+#import <objc/runtime.h>
+#import <mach/mach_host.h>
+#import <mach/host_info.h>
+#import <libkern/OSAtomic.h>
+#import <Availability.h>
+#if TARGET_OS_IOS
+    #import <UIKit/UIDevice.h>
+#endif
+
+
+#if !__has_feature(objc_arc)
+#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
+#endif
+
+// We probably shouldn't be using DDLog() statements within the DDLog implementation.
+// But we still want to leave our log statements for any future debugging,
+// and to allow other developers to trace the implementation (which is a great learning tool).
+//
+// So we use a primitive logging macro around NSLog.
+// We maintain the NS prefix on the macros to be explicit about the fact that we're using NSLog.
+
+#ifndef DD_DEBUG
+    #define DD_DEBUG NO
+#endif
+
+#define NSLogDebug(frmt, ...) do{ if(DD_DEBUG) NSLog((frmt), ##__VA_ARGS__); } while(0)
+
+// Specifies the maximum queue size of the logging thread.
+//
+// Since most logging is asynchronous, its possible for rogue threads to flood the logging queue.
+// That is, to issue an abundance of log statements faster than the logging thread can keepup.
+// Typically such a scenario occurs when log statements are added haphazardly within large loops,
+// but may also be possible if relatively slow loggers are being used.
+//
+// This property caps the queue size at a given number of outstanding log statements.
+// If a thread attempts to issue a log statement when the queue is already maxed out,
+// the issuing thread will block until the queue size drops below the max again.
+
+#define LOG_MAX_QUEUE_SIZE 1000 // Should not exceed INT32_MAX
+
+// The "global logging queue" refers to [DDLog loggingQueue].
+// It is the queue that all log statements go through.
+//
+// The logging queue sets a flag via dispatch_queue_set_specific using this key.
+// We can check for this key via dispatch_get_specific() to see if we're on the "global logging queue".
+
+static void *const GlobalLoggingQueueIdentityKey = (void *)&GlobalLoggingQueueIdentityKey;
+
+@interface DDLoggerNode : NSObject
+{
+    // Direct accessors to be used only for performance
+    @public
+    id <DDLogger> _logger;
+    DDLogLevel _level;
+    dispatch_queue_t _loggerQueue;
+}
+
+@property (nonatomic, readonly) id <DDLogger> logger;
+@property (nonatomic, readonly) DDLogLevel level;
+@property (nonatomic, readonly) dispatch_queue_t loggerQueue;
+
++ (DDLoggerNode *)nodeWithLogger:(id <DDLogger>)logger
+                     loggerQueue:(dispatch_queue_t)loggerQueue
+                           level:(DDLogLevel)level;
+
+@end
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation DDLog
+
+// An array used to manage all the individual loggers.
+// The array is only modified on the loggingQueue/loggingThread.
+static NSMutableArray *_loggers;
+
+// All logging statements are added to the same queue to ensure FIFO operation.
+static dispatch_queue_t _loggingQueue;
+
+// Individual loggers are executed concurrently per log statement.
+// Each logger has it's own associated queue, and a dispatch group is used for synchrnoization.
+static dispatch_group_t _loggingGroup;
+
+// In order to prevent to queue from growing infinitely large,
+// a maximum size is enforced (LOG_MAX_QUEUE_SIZE).
+static dispatch_semaphore_t _queueSemaphore;
+
+// Minor optimization for uniprocessor machines
+static NSUInteger _numProcessors;
+
+/**
+ * The runtime sends initialize to each class in a program exactly one time just before the class,
+ * or any class that inherits from it, is sent its first message from within the program. (Thus the
+ * method may never be invoked if the class is not used.) The runtime sends the initialize message to
+ * classes in a thread-safe manner. Superclasses receive this message before their subclasses.
+ *
+ * This method may also be called directly (assumably by accident), hence the safety mechanism.
+ **/
++ (void)initialize {
+    static dispatch_once_t DDLogOnceToken;
+
+    dispatch_once(&DDLogOnceToken, ^{
+        _loggers = [[NSMutableArray alloc] initWithCapacity:4];
+
+        NSLogDebug(@"DDLog: Using grand central dispatch");
+
+        _loggingQueue = dispatch_queue_create("cocoa.lumberjack", NULL);
+        _loggingGroup = dispatch_group_create();
+
+        void *nonNullValue = GlobalLoggingQueueIdentityKey; // Whatever, just not null
+        dispatch_queue_set_specific(_loggingQueue, GlobalLoggingQueueIdentityKey, nonNullValue, NULL);
+
+        _queueSemaphore = dispatch_semaphore_create(LOG_MAX_QUEUE_SIZE);
+
+        // Figure out how many processors are available.
+        // This may be used later for an optimization on uniprocessor machines.
+        
+        _numProcessors = MAX([NSProcessInfo processInfo].processorCount, 1);
+
+        NSLogDebug(@"DDLog: numProcessors = %@", @(_numProcessors));
+
+
+#if TARGET_OS_IOS
+        NSString *notificationName = @"UIApplicationWillTerminateNotification";
+#else
+        NSString *notificationName = nil;
+
+        // On Command Line Tool apps AppKit may not be avaliable
+#ifdef NSAppKitVersionNumber10_0
+
+        if (NSApp) {
+            notificationName = @"NSApplicationWillTerminateNotification";
+        }
+
+#endif
+
+        if (!notificationName) {
+            // If there is no NSApp -> we are running Command Line Tool app.
+            // In this case terminate notification wouldn't be fired, so we use workaround.
+            atexit_b (^{
+                [self applicationWillTerminate:nil];
+            });
+        }
+
+#endif /* if TARGET_OS_IOS */
+
+        if (notificationName) {
+            [[NSNotificationCenter defaultCenter] addObserver:self
+                                                     selector:@selector(applicationWillTerminate:)
+                                                         name:notificationName
+                                                       object:nil];
+        }
+    });
+}
+
+/**
+ * Provides access to the logging queue.
+ **/
++ (dispatch_queue_t)loggingQueue {
+    return _loggingQueue;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Notifications
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
++ (void)applicationWillTerminate:(NSNotification * __attribute__((unused)))notification {
+    [self flushLog];
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Logger Management
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
++ (void)addLogger:(id <DDLogger>)logger {
+    [self addLogger:logger withLevel:DDLogLevelAll]; // DDLogLevelAll has all bits set
+}
+
++ (void)addLogger:(id <DDLogger>)logger withLevel:(DDLogLevel)level {
+    if (!logger) {
+        return;
+    }
+
+    dispatch_async(_loggingQueue, ^{ @autoreleasepool {
+                                        [self lt_addLogger:logger level:level];
+                                    } });
+}
+
++ (void)removeLogger:(id <DDLogger>)logger {
+    if (!logger) {
+        return;
+    }
+
+    dispatch_async(_loggingQueue, ^{ @autoreleasepool {
+                                        [self lt_removeLogger:logger];
+                                    } });
+}
+
++ (void)removeAllLoggers {
+    dispatch_async(_loggingQueue, ^{ @autoreleasepool {
+                                        [self lt_removeAllLoggers];
+                                    } });
+}
+
++ (NSArray *)allLoggers {
+    __block NSArray *theLoggers;
+
+    dispatch_sync(_loggingQueue, ^{ @autoreleasepool {
+                                       theLoggers = [self lt_allLoggers];
+                                   } });
+
+    return theLoggers;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark - Master Logging
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
++ (void)queueLogMessage:(DDLogMessage *)logMessage asynchronously:(BOOL)asyncFlag {
+    // We have a tricky situation here...
+    //
+    // In the common case, when the queueSize is below the maximumQueueSize,
+    // we want to simply enqueue the logMessage. And we want to do this as fast as possible,
+    // which means we don't want to block and we don't want to use any locks.
+    //
+    // However, if the queueSize gets too big, we want to block.
+    // But we have very strict requirements as to when we block, and how long we block.
+    //
+    // The following example should help illustrate our requirements:
+    //
+    // Imagine that the maximum queue size is configured to be 5,
+    // and that there are already 5 log messages queued.
+    // Let us call these 5 queued log messages A, B, C, D, and E. (A is next to be executed)
+    //
+    // Now if our thread issues a log statement (let us call the log message F),
+    // it should block before the message is added to the queue.
+    // Furthermore, it should be unblocked immediately after A has been unqueued.
+    //
+    // The requirements are strict in this manner so that we block only as long as necessary,
+    // and so that blocked threads are unblocked in the order in which they were blocked.
+    //
+    // Returning to our previous example, let us assume that log messages A through E are still queued.
+    // Our aforementioned thread is blocked attempting to queue log message F.
+    // Now assume we have another separate thread that attempts to issue log message G.
+    // It should block until log messages A and B have been unqueued.
+
+
+    // We are using a counting semaphore provided by GCD.
+    // The semaphore is initialized with our LOG_MAX_QUEUE_SIZE value.
+    // Everytime we want to queue a log message we decrement this value.
+    // If the resulting value is less than zero,
+    // the semaphore function waits in FIFO order for a signal to occur before returning.
+    //
+    // A dispatch semaphore is an efficient implementation of a traditional counting semaphore.
+    // Dispatch semaphores call down to the kernel only when the calling thread needs to be blocked.
+    // If the calling semaphore does not need to block, no kernel call is made.
+
+    dispatch_semaphore_wait(_queueSemaphore, DISPATCH_TIME_FOREVER);
+
+    // We've now sure we won't overflow the queue.
+    // It is time to queue our log message.
+
+    dispatch_block_t logBlock = ^{
+        @autoreleasepool {
+            [self lt_log:logMessage];
+        }
+    };
+
+    if (asyncFlag) {
+        dispatch_async(_loggingQueue, logBlock);
+    } else {
+        dispatch_sync(_loggingQueue, logBlock);
+    }
+}
+
++ (void)log:(BOOL)asynchronous
+      level:(DDLogLevel)level
+       flag:(DDLogFlag)flag
+    context:(NSInteger)context
+       file:(const char *)file
+   function:(const char *)function
+       line:(NSUInteger)line
+        tag:(id)tag
+     format:(NSString *)format, ... {
+    va_list args;
+    
+    if (format) {
+        va_start(args, format);
+        
+        NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
+        [self log:asynchronous
+          message:message
+            level:level
+             flag:flag
+          context:context
+             file:file
+         function:function
+             line:line
+              tag:tag];
+
+        va_end(args);
+    }
+}
+
++ (void)log:(BOOL)asynchronous
+      level:(DDLogLevel)level
+       flag:(DDLogFlag)flag
+    context:(NSInteger)context
+       file:(const char *)file
+   function:(const char *)function
+       line:(NSUInteger)line
+        tag:(id)tag
+     format:(NSString *)format
+       args:(va_list)args {
+    
+    if (format) {
+        NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
+        [self log:asynchronous
+          message:message
+            level:level
+             flag:flag
+          context:context
+             file:file
+         function:function
+             line:line
+              tag:tag];
+    }
+}
+
++ (void)log:(BOOL)asynchronous
+    message:(NSString *)message
+      level:(DDLogLevel)level
+       flag:(DDLogFlag)flag
+    context:(NSInteger)context
+       file:(const char *)file
+   function:(const char *)function
+       line:(NSUInteger)line
+        tag:(id)tag {
+    
+    DDLogMessage *logMessage = [[DDLogMessage alloc] initWithMessage:message
+                                                               level:level
+                                                                flag:flag
+                                                             context:context
+                                                                file:[NSString stringWithFormat:@"%s", file]
+                                                            function:[NSString stringWithFormat:@"%s", function]
+                                                                line:line
+                                                                 tag:tag
+                                                             options:(DDLogMessageOptions)0
+                                                           timestamp:nil];
+    
+    [self queueLogMessage:logMessage asynchronously:asynchronous];
+}
+
++ (void)log:(BOOL)asynchronous
+    message:(DDLogMessage *)logMessage {
+    [self queueLogMessage:logMessage asynchronously:asynchronous];
+}
+
++ (void)flushLog {
+    dispatch_sync(_loggingQueue, ^{ @autoreleasepool {
+                                       [self lt_flush];
+                                   } });
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Registered Dynamic Logging
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
++ (BOOL)isRegisteredClass:(Class)class {
+    SEL getterSel = @selector(ddLogLevel);
+    SEL setterSel = @selector(ddSetLogLevel:);
+
+#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+
+    // Issue #6 (GoogleCode) - Crashes on iOS 4.2.1 and iPhone 4
+    //
+    // Crash caused by class_getClassMethod(2).
+    //
+    //     "It's a bug with UIAccessibilitySafeCategory__NSObject so it didn't pop up until
+    //      users had VoiceOver enabled [...]. I was able to work around it by searching the
+    //      result of class_copyMethodList() instead of calling class_getClassMethod()"
+
+    BOOL result = NO;
+
+    unsigned int methodCount, i;
+    Method *methodList = class_copyMethodList(object_getClass(class), &methodCount);
+
+    if (methodList != NULL) {
+        BOOL getterFound = NO;
+        BOOL setterFound = NO;
+
+        for (i = 0; i < methodCount; ++i) {
+            SEL currentSel = method_getName(methodList[i]);
+
+            if (currentSel == getterSel) {
+                getterFound = YES;
+            } else if (currentSel == setterSel) {
+                setterFound = YES;
+            }
+
+            if (getterFound && setterFound) {
+                result = YES;
+                break;
+            }
+        }
+
+        free(methodList);
+    }
+
+    return result;
+
+#else /* if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR */
+
+    // Issue #24 (GitHub) - Crashing in in ARC+Simulator
+    //
+    // The method +[DDLog isRegisteredClass] will crash a project when using it with ARC + Simulator.
+    // For running in the Simulator, it needs to execute the non-iOS code.
+
+    Method getter = class_getClassMethod(class, getterSel);
+    Method setter = class_getClassMethod(class, setterSel);
+
+    if ((getter != NULL) && (setter != NULL)) {
+        return YES;
+    }
+
+    return NO;
+
+#endif /* if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR */
+}
+
++ (NSArray *)registeredClasses {
+
+    // We're going to get the list of all registered classes.
+    // The Objective-C runtime library automatically registers all the classes defined in your source code.
+    //
+    // To do this we use the following method (documented in the Objective-C Runtime Reference):
+    //
+    // int objc_getClassList(Class *buffer, int bufferLen)
+    //
+    // We can pass (NULL, 0) to obtain the total number of
+    // registered class definitions without actually retrieving any class definitions.
+    // This allows us to allocate the minimum amount of memory needed for the application.
+
+    NSUInteger numClasses = 0;
+    Class *classes = NULL;
+
+    while (numClasses == 0) {
+
+        numClasses = (NSUInteger)MAX(objc_getClassList(NULL, 0), 0);
+
+        // numClasses now tells us how many classes we have (but it might change)
+        // So we can allocate our buffer, and get pointers to all the class definitions.
+
+        NSUInteger bufferSize = numClasses;
+
+        classes = numClasses ? (Class *)malloc(sizeof(Class) * bufferSize) : NULL;
+        if (classes == NULL) {
+            return nil; //no memory or classes?
+        }
+
+        numClasses = (NSUInteger)MAX(objc_getClassList(classes, (int)bufferSize),0);
+
+        if (numClasses > bufferSize || numClasses == 0) {
+            //apparently more classes added between calls (or a problem); try again
+            free(classes);
+            numClasses = 0;
+        }
+    }
+
+    // We can now loop through the classes, and test each one to see if it is a DDLogging class.
+
+    NSMutableArray *result = [NSMutableArray arrayWithCapacity:numClasses];
+
+    for (NSUInteger i = 0; i < numClasses; i++) {
+        Class class = classes[i];
+
+        if ([self isRegisteredClass:class]) {
+            [result addObject:class];
+        }
+    }
+
+    free(classes);
+
+    return result;
+}
+
++ (NSArray *)registeredClassNames {
+    NSArray *registeredClasses = [self registeredClasses];
+    NSMutableArray *result = [NSMutableArray arrayWithCapacity:[registeredClasses count]];
+
+    for (Class class in registeredClasses) {
+        [result addObject:NSStringFromClass(class)];
+    }
+    return result;
+}
+
++ (DDLogLevel)levelForClass:(Class)aClass {
+    if ([self isRegisteredClass:aClass]) {
+        return [aClass ddLogLevel];
+    }
+    return (DDLogLevel)-1;
+}
+
++ (DDLogLevel)levelForClassWithName:(NSString *)aClassName {
+    Class aClass = NSClassFromString(aClassName);
+
+    return [self levelForClass:aClass];
+}
+
++ (void)setLevel:(DDLogLevel)level forClass:(Class)aClass {
+    if ([self isRegisteredClass:aClass]) {
+        [aClass ddSetLogLevel:level];
+    }
+}
+
++ (void)setLevel:(DDLogLevel)level forClassWithName:(NSString *)aClassName {
+    Class aClass = NSClassFromString(aClassName);
+    [self setLevel:level forClass:aClass];
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Logging Thread
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
++ (void)lt_addLogger:(id <DDLogger>)logger level:(DDLogLevel)level {
+    // Add to loggers array.
+    // Need to create loggerQueue if loggerNode doesn't provide one.
+
+    NSAssert(dispatch_get_specific(GlobalLoggingQueueIdentityKey),
+             @"This method should only be run on the logging thread/queue");
+
+    dispatch_queue_t loggerQueue = NULL;
+
+    if ([logger respondsToSelector:@selector(loggerQueue)]) {
+        // Logger may be providing its own queue
+
+        loggerQueue = [logger loggerQueue];
+    }
+
+    if (loggerQueue == nil) {
+        // Automatically create queue for the logger.
+        // Use the logger name as the queue name if possible.
+
+        const char *loggerQueueName = NULL;
+
+        if ([logger respondsToSelector:@selector(loggerName)]) {
+            loggerQueueName = [[logger loggerName] UTF8String];
+        }
+
+        loggerQueue = dispatch_queue_create(loggerQueueName, NULL);
+    }
+
+    DDLoggerNode *loggerNode = [DDLoggerNode nodeWithLogger:logger loggerQueue:loggerQueue level:level];
+    [_loggers addObject:loggerNode];
+
+    if ([logger respondsToSelector:@selector(didAddLogger)]) {
+        dispatch_async(loggerNode->_loggerQueue, ^{ @autoreleasepool {
+            [logger didAddLogger];
+        } });
+    }
+}
+
++ (void)lt_removeLogger:(id <DDLogger>)logger {
+    // Find associated loggerNode in list of added loggers
+
+    NSAssert(dispatch_get_specific(GlobalLoggingQueueIdentityKey),
+             @"This method should only be run on the logging thread/queue");
+
+    DDLoggerNode *loggerNode = nil;
+
+    for (DDLoggerNode *node in _loggers) {
+        if (node->_logger == logger) {
+            loggerNode = node;
+            break;
+        }
+    }
+    
+    if (loggerNode == nil) {
+        NSLogDebug(@"DDLog: Request to remove logger which wasn't added");
+        return;
+    }
+    
+    // Notify logger
+    if ([logger respondsToSelector:@selector(willRemoveLogger)]) {
+        dispatch_async(loggerNode->_loggerQueue, ^{ @autoreleasepool {
+            [logger willRemoveLogger];
+        } });
+    }
+    
+    // Remove from loggers array
+    [_loggers removeObject:loggerNode];
+}
+
++ (void)lt_removeAllLoggers {
+    NSAssert(dispatch_get_specific(GlobalLoggingQueueIdentityKey),
+             @"This method should only be run on the logging thread/queue");
+    
+    // Notify all loggers
+    for (DDLoggerNode *loggerNode in _loggers) {
+        if ([loggerNode->_logger respondsToSelector:@selector(willRemoveLogger)]) {
+            dispatch_async(loggerNode->_loggerQueue, ^{ @autoreleasepool {
+                [loggerNode->_logger willRemoveLogger];
+            } });
+        }
+    }
+    
+    // Remove all loggers from array
+
+    [_loggers removeAllObjects];
+}
+
++ (NSArray *)lt_allLoggers {
+    NSAssert(dispatch_get_specific(GlobalLoggingQueueIdentityKey),
+             @"This method should only be run on the logging thread/queue");
+
+    NSMutableArray *theLoggers = [NSMutableArray new];
+
+    for (DDLoggerNode *loggerNode in _loggers) {
+        [theLoggers addObject:loggerNode->_logger];
+    }
+
+    return [theLoggers copy];
+}
+
++ (void)lt_log:(DDLogMessage *)logMessage {
+    // Execute the given log message on each of our loggers.
+
+    NSAssert(dispatch_get_specific(GlobalLoggingQueueIdentityKey),
+             @"This method should only be run on the logging thread/queue");
+
+    if (_numProcessors > 1) {
+        // Execute each logger concurrently, each within its own queue.
+        // All blocks are added to same group.
+        // After each block has been queued, wait on group.
+        //
+        // The waiting ensures that a slow logger doesn't end up with a large queue of pending log messages.
+        // This would defeat the purpose of the efforts we made earlier to restrict the max queue size.
+
+        for (DDLoggerNode *loggerNode in _loggers) {
+            // skip the loggers that shouldn't write this message based on the log level
+
+            if (!(logMessage->_flag & loggerNode->_level)) {
+                continue;
+            }
+            
+            dispatch_group_async(_loggingGroup, loggerNode->_loggerQueue, ^{ @autoreleasepool {
+                [loggerNode->_logger logMessage:logMessage];
+            } });
+        }
+        
+        dispatch_group_wait(_loggingGroup, DISPATCH_TIME_FOREVER);
+    } else {
+        // Execute each logger serialy, each within its own queue.
+        
+        for (DDLoggerNode *loggerNode in _loggers) {
+            // skip the loggers that shouldn't write this message based on the log level
+
+            if (!(logMessage->_flag & loggerNode->_level)) {
+                continue;
+            }
+            
+            dispatch_sync(loggerNode->_loggerQueue, ^{ @autoreleasepool {
+                [loggerNode->_logger logMessage:logMessage];
+            } });
+        }
+    }
+
+    // If our queue got too big, there may be blocked threads waiting to add log messages to the queue.
+    // Since we've now dequeued an item from the log, we may need to unblock the next thread.
+
+    // We are using a counting semaphore provided by GCD.
+    // The semaphore is initialized with our LOG_MAX_QUEUE_SIZE value.
+    // When a log message is queued this value is decremented.
+    // When a log message is dequeued this value is incremented.
+    // If the value ever drops below zero,
+    // the queueing thread blocks and waits in FIFO order for us to signal it.
+    //
+    // A dispatch semaphore is an efficient implementation of a traditional counting semaphore.
+    // Dispatch semaphores call down to the kernel only when the calling thread needs to be blocked.
+    // If the calling semaphore does not need to block, no kernel call is made.
+
+    dispatch_semaphore_signal(_queueSemaphore);
+}
+
++ (void)lt_flush {
+    // All log statements issued before the flush method was invoked have now been executed.
+    //
+    // Now we need to propogate the flush request to any loggers that implement the flush method.
+    // This is designed for loggers that buffer IO.
+    
+    NSAssert(dispatch_get_specific(GlobalLoggingQueueIdentityKey),
+             @"This method should only be run on the logging thread/queue");
+    
+    for (DDLoggerNode *loggerNode in _loggers) {
+        if ([loggerNode->_logger respondsToSelector:@selector(flush)]) {
+            dispatch_group_async(_loggingGroup, loggerNode->_loggerQueue, ^{ @autoreleasepool {
+                [loggerNode->_logger flush];
+            } });
+        }
+    }
+    
+    dispatch_group_wait(_loggingGroup, DISPATCH_TIME_FOREVER);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Utilities
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+NSString * DDExtractFileNameWithoutExtension(const char *filePath, BOOL copy) {
+    if (filePath == NULL) {
+        return nil;
+    }
+
+    char *lastSlash = NULL;
+    char *lastDot = NULL;
+
+    char *p = (char *)filePath;
+
+    while (*p != '\0') {
+        if (*p == '/') {
+            lastSlash = p;
+        } else if (*p == '.') {
+            lastDot = p;
+        }
+
+        p++;
+    }
+
+    char *subStr;
+    NSUInteger subLen;
+
+    if (lastSlash) {
+        if (lastDot) {
+            // lastSlash -> lastDot
+            subStr = lastSlash + 1;
+            subLen = (NSUInteger)(lastDot - subStr);
+        } else {
+            // lastSlash -> endOfString
+            subStr = lastSlash + 1;
+            subLen = (NSUInteger)(p - subStr);
+        }
+    } else {
+        if (lastDot) {
+            // startOfString -> lastDot
+            subStr = (char *)filePath;
+            subLen = (NSUInteger)(lastDot - subStr);
+        } else {
+            // startOfString -> endOfString
+            subStr = (char *)filePath;
+            subLen = (NSUInteger)(p - subStr);
+        }
+    }
+
+    if (copy) {
+        return [[NSString alloc] initWithBytes:subStr
+                                        length:subLen
+                                      encoding:NSUTF8StringEncoding];
+    } else {
+        // We can take advantage of the fact that __FILE__ is a string literal.
+        // Specifically, we don't need to waste time copying the string.
+        // We can just tell NSString to point to a range within the string literal.
+
+        return [[NSString alloc] initWithBytesNoCopy:subStr
+                                              length:subLen
+                                            encoding:NSUTF8StringEncoding
+                                        freeWhenDone:NO];
+    }
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation DDLoggerNode
+
+- (instancetype)initWithLogger:(id <DDLogger>)logger loggerQueue:(dispatch_queue_t)loggerQueue level:(DDLogLevel)level {
+    if ((self = [super init])) {
+        _logger = logger;
+
+        if (loggerQueue) {
+            _loggerQueue = loggerQueue;
+            #if !OS_OBJECT_USE_OBJC
+            dispatch_retain(loggerQueue);
+            #endif
+        }
+
+        _level = level;
+    }
+    return self;
+}
+
++ (DDLoggerNode *)nodeWithLogger:(id <DDLogger>)logger loggerQueue:(dispatch_queue_t)loggerQueue level:(DDLogLevel)level {
+    return [[DDLoggerNode alloc] initWithLogger:logger loggerQueue:loggerQueue level:level];
+}
+
+- (void)dealloc {
+    #if !OS_OBJECT_USE_OBJC
+    if (_loggerQueue) {
+        dispatch_release(_loggerQueue);
+    }
+    #endif
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation DDLogMessage
+
+// Can we use DISPATCH_CURRENT_QUEUE_LABEL ?
+// Can we use dispatch_get_current_queue (without it crashing) ?
+//
+// a) Compiling against newer SDK's (iOS 7+/OS X 10.9+) where DISPATCH_CURRENT_QUEUE_LABEL is defined
+//    on a (iOS 7.0+/OS X 10.9+) runtime version
+//
+// b) Systems where dispatch_get_current_queue is not yet deprecated and won't crash (< iOS 6.0/OS X 10.9)
+//
+//    dispatch_get_current_queue(void);
+//      __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_6,__MAC_10_9,__IPHONE_4_0,__IPHONE_6_0)
+
+#if TARGET_OS_IOS
+
+// Compiling for iOS
+
+    #define USE_DISPATCH_CURRENT_QUEUE_LABEL ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)
+    #define USE_DISPATCH_GET_CURRENT_QUEUE   ([[[UIDevice currentDevice] systemVersion] floatValue] >= 6.1)
+
+#elif TARGET_OS_WATCH || TARGET_OS_TV
+
+// Compiling for watchOS, tvOS
+
+#define USE_DISPATCH_CURRENT_QUEUE_LABEL YES
+#define USE_DISPATCH_GET_CURRENT_QUEUE   YES
+
+#else
+
+// Compiling for Mac OS X
+
+  #ifndef MAC_OS_X_VERSION_10_9
+    #define MAC_OS_X_VERSION_10_9            1090
+  #endif
+
+  #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9 // Mac OS X 10.9 or later required
+
+    #define USE_DISPATCH_CURRENT_QUEUE_LABEL YES
+    #define USE_DISPATCH_GET_CURRENT_QUEUE   NO
+
+  #else
+
+    #define USE_DISPATCH_CURRENT_QUEUE_LABEL ([NSTimer instancesRespondToSelector : @selector(tolerance)]) // OS X 10.9+
+    #define USE_DISPATCH_GET_CURRENT_QUEUE   (![NSTimer instancesRespondToSelector : @selector(tolerance)]) // < OS X 10.9
+
+  #endif
+
+#endif /* if TARGET_OS_IOS */
+
+// Should we use pthread_threadid_np ?
+// With iOS 8+/OSX 10.10+ NSLog uses pthread_threadid_np instead of pthread_mach_thread_np
+
+#if TARGET_OS_IOS
+
+// Compiling for iOS
+
+  #ifndef kCFCoreFoundationVersionNumber_iOS_8_0
+    #define kCFCoreFoundationVersionNumber_iOS_8_0 1140.10
+  #endif
+
+    #define USE_PTHREAD_THREADID_NP                (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_8_0)
+
+#elif TARGET_OS_WATCH || TARGET_OS_TV
+
+// Compiling for watchOS, tvOS
+
+#define USE_PTHREAD_THREADID_NP                    YES
+
+#else
+
+// Compiling for Mac OS X
+
+  #ifndef kCFCoreFoundationVersionNumber10_10
+    #define kCFCoreFoundationVersionNumber10_10    1151.16
+  #endif
+
+    #define USE_PTHREAD_THREADID_NP                (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber10_10)
+
+#endif /* if TARGET_OS_IOS */
+
+- (instancetype)initWithMessage:(NSString *)message
+                          level:(DDLogLevel)level
+                           flag:(DDLogFlag)flag
+                        context:(NSInteger)context
+                           file:(NSString *)file
+                       function:(NSString *)function
+                           line:(NSUInteger)line
+                            tag:(id)tag
+                        options:(DDLogMessageOptions)options
+                      timestamp:(NSDate *)timestamp {
+    if ((self = [super init])) {
+        _message      = [message copy];
+        _level        = level;
+        _flag         = flag;
+        _context      = context;
+
+        BOOL copyFile = (options & DDLogMessageCopyFile) == DDLogMessageCopyFile;
+        _file = copyFile ? [file copy] : file;
+
+        BOOL copyFunction = (options & DDLogMessageCopyFunction) == DDLogMessageCopyFunction;
+        _function = copyFunction ? [function copy] : function;
+
+        _line         = line;
+        _tag          = tag;
+        _options      = options;
+        _timestamp    = timestamp ?: [NSDate new];
+
+        if (USE_PTHREAD_THREADID_NP) {
+            __uint64_t tid;
+            pthread_threadid_np(NULL, &tid);
+            _threadID = [[NSString alloc] initWithFormat:@"%llu", tid];
+        } else {
+            _threadID = [[NSString alloc] initWithFormat:@"%x", pthread_mach_thread_np(pthread_self())];
+        }
+        _threadName   = NSThread.currentThread.name;
+
+        // Get the file name without extension
+        _fileName = [_file lastPathComponent];
+        NSUInteger dotLocation = [_fileName rangeOfString:@"." options:NSBackwardsSearch].location;
+        if (dotLocation != NSNotFound)
+        {
+            _fileName = [_fileName substringToIndex:dotLocation];
+        }
+        
+        // Try to get the current queue's label
+        if (USE_DISPATCH_CURRENT_QUEUE_LABEL) {
+            _queueLabel = [[NSString alloc] initWithFormat:@"%s", dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)];
+        } else if (USE_DISPATCH_GET_CURRENT_QUEUE) {
+            #pragma clang diagnostic push
+            #pragma clang diagnostic ignored "-Wdeprecated-declarations"
+            dispatch_queue_t currentQueue = dispatch_get_current_queue();
+            #pragma clang diagnostic pop
+            _queueLabel = [[NSString alloc] initWithFormat:@"%s", dispatch_queue_get_label(currentQueue)];
+        } else {
+            _queueLabel = @""; // iOS 6.x only
+        }
+    }
+    return self;
+}
+
+- (id)copyWithZone:(NSZone * __attribute__((unused)))zone {
+    DDLogMessage *newMessage = [DDLogMessage new];
+    
+    newMessage->_message = _message;
+    newMessage->_level = _level;
+    newMessage->_flag = _flag;
+    newMessage->_context = _context;
+    newMessage->_file = _file;
+    newMessage->_fileName = _fileName;
+    newMessage->_function = _function;
+    newMessage->_line = _line;
+    newMessage->_tag = _tag;
+    newMessage->_options = _options;
+    newMessage->_timestamp = _timestamp;
+    newMessage->_threadID = _threadID;
+    newMessage->_threadName = _threadName;
+    newMessage->_queueLabel = _queueLabel;
+
+    return newMessage;
+}
+
+@end
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation DDAbstractLogger
+
+- (instancetype)init {
+    if ((self = [super init])) {
+        const char *loggerQueueName = NULL;
+
+        if ([self respondsToSelector:@selector(loggerName)]) {
+            loggerQueueName = [[self loggerName] UTF8String];
+        }
+
+        _loggerQueue = dispatch_queue_create(loggerQueueName, NULL);
+
+        // We're going to use dispatch_queue_set_specific() to "mark" our loggerQueue.
+        // Later we can use dispatch_get_specific() to determine if we're executing on our loggerQueue.
+        // The documentation states:
+        //
+        // > Keys are only compared as pointers and are never dereferenced.
+        // > Thus, you can use a pointer to a static variable for a specific subsystem or
+        // > any other value that allows you to identify the value uniquely.
+        // > Specifying a pointer to a string constant is not recommended.
+        //
+        // So we're going to use the very convenient key of "self",
+        // which also works when multiple logger classes extend this class, as each will have a different "self" key.
+        //
+        // This is used primarily for thread-safety assertions (via the isOnInternalLoggerQueue method below).
+
+        void *key = (__bridge void *)self;
+        void *nonNullValue = (__bridge void *)self;
+
+        dispatch_queue_set_specific(_loggerQueue, key, nonNullValue, NULL);
+    }
+
+    return self;
+}
+
+- (void)dealloc {
+    #if !OS_OBJECT_USE_OBJC
+
+    if (_loggerQueue) {
+        dispatch_release(_loggerQueue);
+    }
+
+    #endif
+}
+
+- (void)logMessage:(DDLogMessage * __attribute__((unused)))logMessage {
+    // Override me
+}
+
+- (id <DDLogFormatter>)logFormatter {
+    // This method must be thread safe and intuitive.
+    // Therefore if somebody executes the following code:
+    //
+    // [logger setLogFormatter:myFormatter];
+    // formatter = [logger logFormatter];
+    //
+    // They would expect formatter to equal myFormatter.
+    // This functionality must be ensured by the getter and setter method.
+    //
+    // The thread safety must not come at a cost to the performance of the logMessage method.
+    // This method is likely called sporadically, while the logMessage method is called repeatedly.
+    // This means, the implementation of this method:
+    // - Must NOT require the logMessage method to acquire a lock.
+    // - Must NOT require the logMessage method to access an atomic property (also a lock of sorts).
+    //
+    // Thread safety is ensured by executing access to the formatter variable on the loggerQueue.
+    // This is the same queue that the logMessage method operates on.
+    //
+    // Note: The last time I benchmarked the performance of direct access vs atomic property access,
+    // direct access was over twice as fast on the desktop and over 6 times as fast on the iPhone.
+    //
+    // Furthermore, consider the following code:
+    //
+    // DDLogVerbose(@"log msg 1");
+    // DDLogVerbose(@"log msg 2");
+    // [logger setFormatter:myFormatter];
+    // DDLogVerbose(@"log msg 3");
+    //
+    // Our intuitive requirement means that the new formatter will only apply to the 3rd log message.
+    // This must remain true even when using asynchronous logging.
+    // We must keep in mind the various queue's that are in play here:
+    //
+    // loggerQueue : Our own private internal queue that the logMessage method runs on.
+    //               Operations are added to this queue from the global loggingQueue.
+    //
+    // globalLoggingQueue : The queue that all log messages go through before they arrive in our loggerQueue.
+    //
+    // All log statements go through the serial gloabalLoggingQueue before they arrive at our loggerQueue.
+    // Thus this method also goes through the serial globalLoggingQueue to ensure intuitive operation.
+
+    // IMPORTANT NOTE:
+    //
+    // Methods within the DDLogger implementation MUST access the formatter ivar directly.
+    // This method is designed explicitly for external access.
+    //
+    // Using "self." syntax to go through this method will cause immediate deadlock.
+    // This is the intended result. Fix it by accessing the ivar directly.
+    // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
+
+    NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+    NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
+
+    dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+
+    __block id <DDLogFormatter> result;
+
+    dispatch_sync(globalLoggingQueue, ^{
+        dispatch_sync(_loggerQueue, ^{
+            result = _logFormatter;
+        });
+    });
+
+    return result;
+}
+
+- (void)setLogFormatter:(id <DDLogFormatter>)logFormatter {
+    // The design of this method is documented extensively in the logFormatter message (above in code).
+
+    NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+    NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
+
+    dispatch_block_t block = ^{
+        @autoreleasepool {
+            if (_logFormatter != logFormatter) {
+                if ([_logFormatter respondsToSelector:@selector(willRemoveFromLogger:)]) {
+                    [_logFormatter willRemoveFromLogger:self];
+                }
+
+                _logFormatter = logFormatter;
+
+                if ([_logFormatter respondsToSelector:@selector(didAddToLogger:)]) {
+                    [_logFormatter didAddToLogger:self];
+                }
+            }
+        }
+    };
+
+    dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+
+    dispatch_async(globalLoggingQueue, ^{
+        dispatch_async(_loggerQueue, block);
+    });
+}
+
+- (dispatch_queue_t)loggerQueue {
+    return _loggerQueue;
+}
+
+- (NSString *)loggerName {
+    return NSStringFromClass([self class]);
+}
+
+- (BOOL)isOnGlobalLoggingQueue {
+    return (dispatch_get_specific(GlobalLoggingQueueIdentityKey) != NULL);
+}
+
+- (BOOL)isOnInternalLoggerQueue {
+    void *key = (__bridge void *)self;
+
+    return (dispatch_get_specific(key) != NULL);
+}
+
+@end
diff --git a/cocoalumberjack/Classes/DDLogMacros.h b/cocoalumberjack/Classes/DDLogMacros.h
new file mode 100644
index 0000000..975d00a
--- /dev/null
+++ b/cocoalumberjack/Classes/DDLogMacros.h
@@ -0,0 +1,82 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+// Disable legacy macros
+#ifndef DD_LEGACY_MACROS
+    #define DD_LEGACY_MACROS 0
+#endif
+
+#import "DDLog.h"
+
+/**
+ * The constant/variable/method responsible for controlling the current log level.
+ **/
+#ifndef LOG_LEVEL_DEF
+    #define LOG_LEVEL_DEF ddLogLevel
+#endif
+
+/**
+ * Whether async should be used by log messages, excluding error messages that are always sent sync.
+ **/
+#ifndef LOG_ASYNC_ENABLED
+    #define LOG_ASYNC_ENABLED YES
+#endif
+
+/**
+ * This is the single macro that all other macros below compile into.
+ * This big multiline macro makes all the other macros easier to read.
+ **/
+#define LOG_MACRO(isAsynchronous, lvl, flg, ctx, atag, fnct, frmt, ...) \
+        [DDLog log : isAsynchronous                                     \
+             level : lvl                                                \
+              flag : flg                                                \
+           context : ctx                                                \
+              file : __FILE__                                           \
+          function : fnct                                               \
+              line : __LINE__                                           \
+               tag : atag                                               \
+            format : (frmt), ## __VA_ARGS__]
+
+/**
+ * Define version of the macro that only execute if the log level is above the threshold.
+ * The compiled versions essentially look like this:
+ *
+ * if (logFlagForThisLogMsg & ddLogLevel) { execute log message }
+ *
+ * When LOG_LEVEL_DEF is defined as ddLogLevel.
+ *
+ * As shown further below, Lumberjack actually uses a bitmask as opposed to primitive log levels.
+ * This allows for a great amount of flexibility and some pretty advanced fine grained logging techniques.
+ *
+ * Note that when compiler optimizations are enabled (as they are for your release builds),
+ * the log messages above your logging threshold will automatically be compiled out.
+ *
+ * (If the compiler sees LOG_LEVEL_DEF/ddLogLevel declared as a constant, the compiler simply checks to see
+ *  if the 'if' statement would execute, and if not it strips it from the binary.)
+ *
+ * We also define shorthand versions for asynchronous and synchronous logging.
+ **/
+#define LOG_MAYBE(async, lvl, flg, ctx, tag, fnct, frmt, ...) \
+        do { if(lvl & flg) LOG_MACRO(async, lvl, flg, ctx, tag, fnct, frmt, ##__VA_ARGS__); } while(0)
+
+/**
+ * Ready to use log macros with no context or tag.
+ **/
+#define DDLogError(frmt, ...)   LOG_MAYBE(NO,                LOG_LEVEL_DEF, DDLogFlagError,   0, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
+#define DDLogWarn(frmt, ...)    LOG_MAYBE(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, DDLogFlagWarning, 0, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
+#define DDLogInfo(frmt, ...)    LOG_MAYBE(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, DDLogFlagInfo,    0, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
+#define DDLogDebug(frmt, ...)   LOG_MAYBE(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, DDLogFlagDebug,   0, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
+#define DDLogVerbose(frmt, ...) LOG_MAYBE(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, DDLogFlagVerbose, 0, nil, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
+
diff --git a/cocoalumberjack/Classes/DDTTYLogger.h b/cocoalumberjack/Classes/DDTTYLogger.h
new file mode 100644
index 0000000..c27415c
--- /dev/null
+++ b/cocoalumberjack/Classes/DDTTYLogger.h
@@ -0,0 +1,178 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+// Disable legacy macros
+#ifndef DD_LEGACY_MACROS
+    #define DD_LEGACY_MACROS 0
+#endif
+
+#import "DDLog.h"
+
+#define LOG_CONTEXT_ALL INT_MAX
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-function"
+#if TARGET_OS_IPHONE
+    // iOS
+    #import <UIKit/UIColor.h>
+    typedef UIColor DDColor;
+    static inline DDColor* DDMakeColor(CGFloat r, CGFloat g, CGFloat b) {return [DDColor colorWithRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:1.0f];}
+#elif defined(DD_CLI) || !__has_include(<AppKit/NSColor.h>)
+    // OS X CLI
+    #import "CLIColor.h"
+    typedef CLIColor DDColor;
+    static inline DDColor* DDMakeColor(CGFloat r, CGFloat g, CGFloat b) {return [DDColor colorWithCalibratedRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:1.0f];}
+#else
+    // OS X with AppKit
+    #import <AppKit/NSColor.h>
+    typedef NSColor DDColor;
+    static inline DDColor* DDMakeColor(CGFloat r, CGFloat g, CGFloat b) {return [DDColor colorWithCalibratedRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:1.0f];}
+#endif
+#pragma clang diagnostic pop
+
+
+/**
+ * This class provides a logger for Terminal output or Xcode console output,
+ * depending on where you are running your code.
+ *
+ * As described in the "Getting Started" page,
+ * the traditional NSLog() function directs it's output to two places:
+ *
+ * - Apple System Log (so it shows up in Console.app)
+ * - StdErr (if stderr is a TTY, so log statements show up in Xcode console)
+ *
+ * To duplicate NSLog() functionality you can simply add this logger and an asl logger.
+ * However, if you instead choose to use file logging (for faster performance),
+ * you may choose to use only a file logger and a tty logger.
+ **/
+@interface DDTTYLogger : DDAbstractLogger <DDLogger>
+
+/**
+ *  Singleton method
+ */
++ (instancetype)sharedInstance;
+
+/* Inherited from the DDLogger protocol:
+ *
+ * Formatters may optionally be added to any logger.
+ *
+ * If no formatter is set, the logger simply logs the message as it is given in logMessage,
+ * or it may use its own built in formatting style.
+ *
+ * More information about formatters can be found here:
+ * Documentation/CustomFormatters.md
+ *
+ * The actual implementation of these methods is inherited from DDAbstractLogger.
+
+   - (id <DDLogFormatter>)logFormatter;
+   - (void)setLogFormatter:(id <DDLogFormatter>)formatter;
+
+ */
+
+/**
+ * Want to use different colors for different log levels?
+ * Enable this property.
+ *
+ * If you run the application via the Terminal (not Xcode),
+ * the logger will map colors to xterm-256color or xterm-color (if available).
+ *
+ * Xcode does NOT natively support colors in the Xcode debugging console.
+ * You'll need to install the XcodeColors plugin to see colors in the Xcode console.
+ * https://github.com/robbiehanson/XcodeColors
+ *
+ * The default value is NO.
+ **/
+@property (readwrite, assign) BOOL colorsEnabled;
+
+/**
+ * When using a custom formatter you can set the `logMessage` method not to append
+ * `\n` character after each output. This allows for some greater flexibility with
+ * custom formatters. Default value is YES.
+ **/
+@property (nonatomic, readwrite, assign) BOOL automaticallyAppendNewlineForCustomFormatters;
+
+/**
+ * The default color set (foregroundColor, backgroundColor) is:
+ *
+ * - DDLogFlagError   = (red, nil)
+ * - DDLogFlagWarning = (orange, nil)
+ *
+ * You can customize the colors however you see fit.
+ * Please note that you are passing a flag, NOT a level.
+ *
+ * GOOD : [ttyLogger setForegroundColor:pink backgroundColor:nil forFlag:DDLogFlagInfo];  // <- Good :)
+ *  BAD : [ttyLogger setForegroundColor:pink backgroundColor:nil forFlag:DDLogLevelInfo]; // <- BAD! :(
+ *
+ * DDLogFlagInfo  = 0...00100
+ * DDLogLevelInfo = 0...00111 <- Would match DDLogFlagInfo and DDLogFlagWarning and DDLogFlagError
+ *
+ * If you run the application within Xcode, then the XcodeColors plugin is required.
+ *
+ * If you run the application from a shell, then DDTTYLogger will automatically map the given color to
+ * the closest available color. (xterm-256color or xterm-color which have 256 and 16 supported colors respectively.)
+ *
+ * This method invokes setForegroundColor:backgroundColor:forFlag:context: and applies it to `LOG_CONTEXT_ALL`.
+ **/
+- (void)setForegroundColor:(DDColor *)txtColor backgroundColor:(DDColor *)bgColor forFlag:(DDLogFlag)mask;
+
+/**
+ * Just like setForegroundColor:backgroundColor:flag, but allows you to specify a particular logging context.
+ *
+ * A logging context is often used to identify log messages coming from a 3rd party framework,
+ * although logging context's can be used for many different functions.
+ *
+ * Use LOG_CONTEXT_ALL to set the deafult color for all contexts that have no specific color set defined.
+ *
+ * Logging context's are explained in further detail here:
+ * Documentation/CustomContext.md
+ **/
+- (void)setForegroundColor:(DDColor *)txtColor backgroundColor:(DDColor *)bgColor forFlag:(DDLogFlag)mask context:(NSInteger)ctxt;
+
+/**
+ * Similar to the methods above, but allows you to map DDLogMessage->tag to a particular color profile.
+ * For example, you could do something like this:
+ *
+ * static NSString *const PurpleTag = @"PurpleTag";
+ *
+ * #define DDLogPurple(frmt, ...) LOG_OBJC_TAG_MACRO(NO, 0, 0, 0, PurpleTag, frmt, ##__VA_ARGS__)
+ * 
+ * And then where you configure CocoaLumberjack:
+ *
+ * purple = DDMakeColor((64/255.0), (0/255.0), (128/255.0));
+ *
+ * or any UIColor/NSColor constructor.
+ *
+ * Note: For CLI OS X projects that don't link with AppKit use CLIColor objects instead
+ *
+ * [[DDTTYLogger sharedInstance] setForegroundColor:purple backgroundColor:nil forTag:PurpleTag];
+ * [DDLog addLogger:[DDTTYLogger sharedInstance]];
+ *
+ * This would essentially give you a straight NSLog replacement that prints in purple:
+ *
+ * DDLogPurple(@"I'm a purple log message!");
+ **/
+- (void)setForegroundColor:(DDColor *)txtColor backgroundColor:(DDColor *)bgColor forTag:(id <NSCopying>)tag;
+
+/**
+ * Clearing color profiles.
+ **/
+- (void)clearColorsForFlag:(DDLogFlag)mask;
+- (void)clearColorsForFlag:(DDLogFlag)mask context:(NSInteger)context;
+- (void)clearColorsForTag:(id <NSCopying>)tag;
+- (void)clearColorsForAllFlags;
+- (void)clearColorsForAllTags;
+- (void)clearAllColors;
+
+@end
diff --git a/cocoalumberjack/Classes/DDTTYLogger.m b/cocoalumberjack/Classes/DDTTYLogger.m
new file mode 100644
index 0000000..41592ca
--- /dev/null
+++ b/cocoalumberjack/Classes/DDTTYLogger.m
@@ -0,0 +1,1481 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+#import "DDTTYLogger.h"
+
+#import <unistd.h>
+#import <sys/uio.h>
+
+#if !__has_feature(objc_arc)
+#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
+#endif
+
+// We probably shouldn't be using DDLog() statements within the DDLog implementation.
+// But we still want to leave our log statements for any future debugging,
+// and to allow other developers to trace the implementation (which is a great learning tool).
+//
+// So we use primitive logging macros around NSLog.
+// We maintain the NS prefix on the macros to be explicit about the fact that we're using NSLog.
+
+#ifndef DD_NSLOG_LEVEL
+    #define DD_NSLOG_LEVEL 2
+#endif
+
+#define NSLogError(frmt, ...)    do{ if(DD_NSLOG_LEVEL >= 1) NSLog((frmt), ##__VA_ARGS__); } while(0)
+#define NSLogWarn(frmt, ...)     do{ if(DD_NSLOG_LEVEL >= 2) NSLog((frmt), ##__VA_ARGS__); } while(0)
+#define NSLogInfo(frmt, ...)     do{ if(DD_NSLOG_LEVEL >= 3) NSLog((frmt), ##__VA_ARGS__); } while(0)
+#define NSLogDebug(frmt, ...)    do{ if(DD_NSLOG_LEVEL >= 4) NSLog((frmt), ##__VA_ARGS__); } while(0)
+#define NSLogVerbose(frmt, ...)  do{ if(DD_NSLOG_LEVEL >= 5) NSLog((frmt), ##__VA_ARGS__); } while(0)
+
+// Xcode does NOT natively support colors in the Xcode debugging console.
+// You'll need to install the XcodeColors plugin to see colors in the Xcode console.
+// https://github.com/robbiehanson/XcodeColors
+//
+// The following is documentation from the XcodeColors project:
+//
+//
+// How to apply color formatting to your log statements:
+//
+// To set the foreground color:
+// Insert the ESCAPE_SEQ into your string, followed by "fg124,12,255;" where r=124, g=12, b=255.
+//
+// To set the background color:
+// Insert the ESCAPE_SEQ into your string, followed by "bg12,24,36;" where r=12, g=24, b=36.
+//
+// To reset the foreground color (to default value):
+// Insert the ESCAPE_SEQ into your string, followed by "fg;"
+//
+// To reset the background color (to default value):
+// Insert the ESCAPE_SEQ into your string, followed by "bg;"
+//
+// To reset the foreground and background color (to default values) in one operation:
+// Insert the ESCAPE_SEQ into your string, followed by ";"
+
+#define XCODE_COLORS_ESCAPE_SEQ "\033["
+
+#define XCODE_COLORS_RESET_FG   XCODE_COLORS_ESCAPE_SEQ "fg;" // Clear any foreground color
+#define XCODE_COLORS_RESET_BG   XCODE_COLORS_ESCAPE_SEQ "bg;" // Clear any background color
+#define XCODE_COLORS_RESET      XCODE_COLORS_ESCAPE_SEQ ";"  // Clear any foreground or background color
+
+// If running in a shell, not all RGB colors will be supported.
+// In this case we automatically map to the closest available color.
+// In order to provide this mapping, we have a hard-coded set of the standard RGB values available in the shell.
+// However, not every shell is the same, and Apple likes to think different even when it comes to shell colors.
+//
+// Map to standard Terminal.app colors (1), or
+// map to standard xterm colors (0).
+
+#define MAP_TO_TERMINAL_APP_COLORS 1
+
+
+@interface DDTTYLoggerColorProfile : NSObject {
+    @public
+    DDLogFlag mask;
+    NSInteger context;
+
+    uint8_t fg_r;
+    uint8_t fg_g;
+    uint8_t fg_b;
+
+    uint8_t bg_r;
+    uint8_t bg_g;
+    uint8_t bg_b;
+
+    NSUInteger fgCodeIndex;
+    NSString *fgCodeRaw;
+
+    NSUInteger bgCodeIndex;
+    NSString *bgCodeRaw;
+
+    char fgCode[24];
+    size_t fgCodeLen;
+
+    char bgCode[24];
+    size_t bgCodeLen;
+
+    char resetCode[8];
+    size_t resetCodeLen;
+}
+
+- (instancetype)initWithForegroundColor:(DDColor *)fgColor backgroundColor:(DDColor *)bgColor flag:(DDLogFlag)mask context:(NSInteger)ctxt;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface DDTTYLogger () {
+    NSUInteger _calendarUnitFlags;
+    
+    NSString *_appName;
+    char *_app;
+    size_t _appLen;
+    
+    NSString *_processID;
+    char *_pid;
+    size_t _pidLen;
+    
+    BOOL _colorsEnabled;
+    NSMutableArray *_colorProfilesArray;
+    NSMutableDictionary *_colorProfilesDict;
+}
+
+@end
+
+
+@implementation DDTTYLogger
+
+static BOOL isaColorTTY;
+static BOOL isaColor256TTY;
+static BOOL isaXcodeColorTTY;
+
+static NSArray *codes_fg = nil;
+static NSArray *codes_bg = nil;
+static NSArray *colors   = nil;
+
+static DDTTYLogger *sharedInstance;
+
+/**
+ * Initializes the colors array, as well as the codes_fg and codes_bg arrays, for 16 color mode.
+ *
+ * This method is used when the application is running from within a shell that only supports 16 color mode.
+ * This method is not invoked if the application is running within Xcode, or via normal UI app launch.
+ **/
++ (void)initialize_colors_16 {
+    if (codes_fg || codes_bg || colors) {
+        return;
+    }
+
+    NSMutableArray *m_codes_fg = [NSMutableArray arrayWithCapacity:16];
+    NSMutableArray *m_codes_bg = [NSMutableArray arrayWithCapacity:16];
+    NSMutableArray *m_colors   = [NSMutableArray arrayWithCapacity:16];
+
+    // In a standard shell only 16 colors are supported.
+    //
+    // More information about ansi escape codes can be found online.
+    // http://en.wikipedia.org/wiki/ANSI_escape_code
+
+    [m_codes_fg addObject:@"30m"];   // normal - black
+    [m_codes_fg addObject:@"31m"];   // normal - red
+    [m_codes_fg addObject:@"32m"];   // normal - green
+    [m_codes_fg addObject:@"33m"];   // normal - yellow
+    [m_codes_fg addObject:@"34m"];   // normal - blue
+    [m_codes_fg addObject:@"35m"];   // normal - magenta
+    [m_codes_fg addObject:@"36m"];   // normal - cyan
+    [m_codes_fg addObject:@"37m"];   // normal - gray
+    [m_codes_fg addObject:@"1;30m"]; // bright - darkgray
+    [m_codes_fg addObject:@"1;31m"]; // bright - red
+    [m_codes_fg addObject:@"1;32m"]; // bright - green
+    [m_codes_fg addObject:@"1;33m"]; // bright - yellow
+    [m_codes_fg addObject:@"1;34m"]; // bright - blue
+    [m_codes_fg addObject:@"1;35m"]; // bright - magenta
+    [m_codes_fg addObject:@"1;36m"]; // bright - cyan
+    [m_codes_fg addObject:@"1;37m"]; // bright - white
+
+    [m_codes_bg addObject:@"40m"];   // normal - black
+    [m_codes_bg addObject:@"41m"];   // normal - red
+    [m_codes_bg addObject:@"42m"];   // normal - green
+    [m_codes_bg addObject:@"43m"];   // normal - yellow
+    [m_codes_bg addObject:@"44m"];   // normal - blue
+    [m_codes_bg addObject:@"45m"];   // normal - magenta
+    [m_codes_bg addObject:@"46m"];   // normal - cyan
+    [m_codes_bg addObject:@"47m"];   // normal - gray
+    [m_codes_bg addObject:@"1;40m"]; // bright - darkgray
+    [m_codes_bg addObject:@"1;41m"]; // bright - red
+    [m_codes_bg addObject:@"1;42m"]; // bright - green
+    [m_codes_bg addObject:@"1;43m"]; // bright - yellow
+    [m_codes_bg addObject:@"1;44m"]; // bright - blue
+    [m_codes_bg addObject:@"1;45m"]; // bright - magenta
+    [m_codes_bg addObject:@"1;46m"]; // bright - cyan
+    [m_codes_bg addObject:@"1;47m"]; // bright - white
+
+#if MAP_TO_TERMINAL_APP_COLORS
+
+    // Standard Terminal.app colors:
+    //
+    // These are the default colors used by Apple's Terminal.app.
+
+    [m_colors addObject:DDMakeColor(  0,   0,   0)]; // normal - black
+    [m_colors addObject:DDMakeColor(194,  54,  33)]; // normal - red
+    [m_colors addObject:DDMakeColor( 37, 188,  36)]; // normal - green
+    [m_colors addObject:DDMakeColor(173, 173,  39)]; // normal - yellow
+    [m_colors addObject:DDMakeColor( 73,  46, 225)]; // normal - blue
+    [m_colors addObject:DDMakeColor(211,  56, 211)]; // normal - magenta
+    [m_colors addObject:DDMakeColor( 51, 187, 200)]; // normal - cyan
+    [m_colors addObject:DDMakeColor(203, 204, 205)]; // normal - gray
+    [m_colors addObject:DDMakeColor(129, 131, 131)]; // bright - darkgray
+    [m_colors addObject:DDMakeColor(252,  57,  31)]; // bright - red
+    [m_colors addObject:DDMakeColor( 49, 231,  34)]; // bright - green
+    [m_colors addObject:DDMakeColor(234, 236,  35)]; // bright - yellow
+    [m_colors addObject:DDMakeColor( 88,  51, 255)]; // bright - blue
+    [m_colors addObject:DDMakeColor(249,  53, 248)]; // bright - magenta
+    [m_colors addObject:DDMakeColor( 20, 240, 240)]; // bright - cyan
+    [m_colors addObject:DDMakeColor(233, 235, 235)]; // bright - white
+
+#else /* if MAP_TO_TERMINAL_APP_COLORS */
+
+    // Standard xterm colors:
+    //
+    // These are the default colors used by most xterm shells.
+
+    [m_colors addObject:DDMakeColor(  0,   0,   0)]; // normal - black
+    [m_colors addObject:DDMakeColor(205,   0,   0)]; // normal - red
+    [m_colors addObject:DDMakeColor(  0, 205,   0)]; // normal - green
+    [m_colors addObject:DDMakeColor(205, 205,   0)]; // normal - yellow
+    [m_colors addObject:DDMakeColor(  0,   0, 238)]; // normal - blue
+    [m_colors addObject:DDMakeColor(205,   0, 205)]; // normal - magenta
+    [m_colors addObject:DDMakeColor(  0, 205, 205)]; // normal - cyan
+    [m_colors addObject:DDMakeColor(229, 229, 229)]; // normal - gray
+    [m_colors addObject:DDMakeColor(127, 127, 127)]; // bright - darkgray
+    [m_colors addObject:DDMakeColor(255,   0,   0)]; // bright - red
+    [m_colors addObject:DDMakeColor(  0, 255,   0)]; // bright - green
+    [m_colors addObject:DDMakeColor(255, 255,   0)]; // bright - yellow
+    [m_colors addObject:DDMakeColor( 92,  92, 255)]; // bright - blue
+    [m_colors addObject:DDMakeColor(255,   0, 255)]; // bright - magenta
+    [m_colors addObject:DDMakeColor(  0, 255, 255)]; // bright - cyan
+    [m_colors addObject:DDMakeColor(255, 255, 255)]; // bright - white
+
+#endif /* if MAP_TO_TERMINAL_APP_COLORS */
+
+    codes_fg = [m_codes_fg copy];
+    codes_bg = [m_codes_bg copy];
+    colors   = [m_colors   copy];
+
+    NSAssert([codes_fg count] == [codes_bg count], @"Invalid colors/codes array(s)");
+    NSAssert([codes_fg count] == [colors count],   @"Invalid colors/codes array(s)");
+}
+
+/**
+ * Initializes the colors array, as well as the codes_fg and codes_bg arrays, for 256 color mode.
+ *
+ * This method is used when the application is running from within a shell that supports 256 color mode.
+ * This method is not invoked if the application is running within Xcode, or via normal UI app launch.
+ **/
++ (void)initialize_colors_256 {
+    if (codes_fg || codes_bg || colors) {
+        return;
+    }
+
+    NSMutableArray *m_codes_fg = [NSMutableArray arrayWithCapacity:(256 - 16)];
+    NSMutableArray *m_codes_bg = [NSMutableArray arrayWithCapacity:(256 - 16)];
+    NSMutableArray *m_colors   = [NSMutableArray arrayWithCapacity:(256 - 16)];
+
+    #if MAP_TO_TERMINAL_APP_COLORS
+
+    // Standard Terminal.app colors:
+    //
+    // These are the colors the Terminal.app uses in xterm-256color mode.
+    // In this mode, the terminal supports 256 different colors, specified by 256 color codes.
+    //
+    // The first 16 color codes map to the original 16 color codes supported by the earlier xterm-color mode.
+    // These are actually configurable, and thus we ignore them for the purposes of mapping,
+    // as we can't rely on them being constant. They are largely duplicated anyway.
+    //
+    // The next 216 color codes are designed to run the spectrum, with several shades of every color.
+    // While the color codes are standardized, the actual RGB values for each color code is not.
+    // Apple's Terminal.app uses different RGB values from that of a standard xterm.
+    // Apple's choices in colors are designed to be a little nicer on the eyes.
+    //
+    // The last 24 color codes represent a grayscale.
+    //
+    // Unfortunately, unlike the standard xterm color chart,
+    // Apple's RGB values cannot be calculated using a simple formula (at least not that I know of).
+    // Also, I don't know of any ways to programmatically query the shell for the RGB values.
+    // So this big giant color chart had to be made by hand.
+    //
+    // More information about ansi escape codes can be found online.
+    // http://en.wikipedia.org/wiki/ANSI_escape_code
+
+    // Colors
+
+    [m_colors addObject:DDMakeColor( 47,  49,  49)];
+    [m_colors addObject:DDMakeColor( 60,  42, 144)];
+    [m_colors addObject:DDMakeColor( 66,  44, 183)];
+    [m_colors addObject:DDMakeColor( 73,  46, 222)];
+    [m_colors addObject:DDMakeColor( 81,  50, 253)];
+    [m_colors addObject:DDMakeColor( 88,  51, 255)];
+    
+    [m_colors addObject:DDMakeColor( 42, 128,  37)];
+    [m_colors addObject:DDMakeColor( 42, 127, 128)];
+    [m_colors addObject:DDMakeColor( 44, 126, 169)];
+    [m_colors addObject:DDMakeColor( 56, 125, 209)];
+    [m_colors addObject:DDMakeColor( 59, 124, 245)];
+    [m_colors addObject:DDMakeColor( 66, 123, 255)];
+    
+    [m_colors addObject:DDMakeColor( 51, 163,  41)];
+    [m_colors addObject:DDMakeColor( 39, 162, 121)];
+    [m_colors addObject:DDMakeColor( 42, 161, 162)];
+    [m_colors addObject:DDMakeColor( 53, 160, 202)];
+    [m_colors addObject:DDMakeColor( 45, 159, 240)];
+    [m_colors addObject:DDMakeColor( 58, 158, 255)];
+    
+    [m_colors addObject:DDMakeColor( 31, 196,  37)];
+    [m_colors addObject:DDMakeColor( 48, 196, 115)];
+    [m_colors addObject:DDMakeColor( 39, 195, 155)];
+    [m_colors addObject:DDMakeColor( 49, 195, 195)];
+    [m_colors addObject:DDMakeColor( 32, 194, 235)];
+    [m_colors addObject:DDMakeColor( 53, 193, 255)];
+    
+    [m_colors addObject:DDMakeColor( 50, 229,  35)];
+    [m_colors addObject:DDMakeColor( 40, 229, 109)];
+    [m_colors addObject:DDMakeColor( 27, 229, 149)];
+    [m_colors addObject:DDMakeColor( 49, 228, 189)];
+    [m_colors addObject:DDMakeColor( 33, 228, 228)];
+    [m_colors addObject:DDMakeColor( 53, 227, 255)];
+    
+    [m_colors addObject:DDMakeColor( 27, 254,  30)];
+    [m_colors addObject:DDMakeColor( 30, 254, 103)];
+    [m_colors addObject:DDMakeColor( 45, 254, 143)];
+    [m_colors addObject:DDMakeColor( 38, 253, 182)];
+    [m_colors addObject:DDMakeColor( 38, 253, 222)];
+    [m_colors addObject:DDMakeColor( 42, 253, 252)];
+    
+    [m_colors addObject:DDMakeColor(140,  48,  40)];
+    [m_colors addObject:DDMakeColor(136,  51, 136)];
+    [m_colors addObject:DDMakeColor(135,  52, 177)];
+    [m_colors addObject:DDMakeColor(134,  52, 217)];
+    [m_colors addObject:DDMakeColor(135,  56, 248)];
+    [m_colors addObject:DDMakeColor(134,  53, 255)];
+    
+    [m_colors addObject:DDMakeColor(125, 125,  38)];
+    [m_colors addObject:DDMakeColor(124, 125, 125)];
+    [m_colors addObject:DDMakeColor(122, 124, 166)];
+    [m_colors addObject:DDMakeColor(123, 124, 207)];
+    [m_colors addObject:DDMakeColor(123, 122, 247)];
+    [m_colors addObject:DDMakeColor(124, 121, 255)];
+    
+    [m_colors addObject:DDMakeColor(119, 160,  35)];
+    [m_colors addObject:DDMakeColor(117, 160, 120)];
+    [m_colors addObject:DDMakeColor(117, 160, 160)];
+    [m_colors addObject:DDMakeColor(115, 159, 201)];
+    [m_colors addObject:DDMakeColor(116, 158, 240)];
+    [m_colors addObject:DDMakeColor(117, 157, 255)];
+    
+    [m_colors addObject:DDMakeColor(113, 195,  39)];
+    [m_colors addObject:DDMakeColor(110, 194, 114)];
+    [m_colors addObject:DDMakeColor(111, 194, 154)];
+    [m_colors addObject:DDMakeColor(108, 194, 194)];
+    [m_colors addObject:DDMakeColor(109, 193, 234)];
+    [m_colors addObject:DDMakeColor(108, 192, 255)];
+    
+    [m_colors addObject:DDMakeColor(105, 228,  30)];
+    [m_colors addObject:DDMakeColor(103, 228, 109)];
+    [m_colors addObject:DDMakeColor(105, 228, 148)];
+    [m_colors addObject:DDMakeColor(100, 227, 188)];
+    [m_colors addObject:DDMakeColor( 99, 227, 227)];
+    [m_colors addObject:DDMakeColor( 99, 226, 253)];
+    
+    [m_colors addObject:DDMakeColor( 92, 253,  34)];
+    [m_colors addObject:DDMakeColor( 96, 253, 103)];
+    [m_colors addObject:DDMakeColor( 97, 253, 142)];
+    [m_colors addObject:DDMakeColor( 88, 253, 182)];
+    [m_colors addObject:DDMakeColor( 93, 253, 221)];
+    [m_colors addObject:DDMakeColor( 88, 254, 251)];
+    
+    [m_colors addObject:DDMakeColor(177,  53,  34)];
+    [m_colors addObject:DDMakeColor(174,  54, 131)];
+    [m_colors addObject:DDMakeColor(172,  55, 172)];
+    [m_colors addObject:DDMakeColor(171,  57, 213)];
+    [m_colors addObject:DDMakeColor(170,  55, 249)];
+    [m_colors addObject:DDMakeColor(170,  57, 255)];
+    
+    [m_colors addObject:DDMakeColor(165, 123,  37)];
+    [m_colors addObject:DDMakeColor(163, 123, 123)];
+    [m_colors addObject:DDMakeColor(162, 123, 164)];
+    [m_colors addObject:DDMakeColor(161, 122, 205)];
+    [m_colors addObject:DDMakeColor(161, 121, 241)];
+    [m_colors addObject:DDMakeColor(161, 121, 255)];
+    
+    [m_colors addObject:DDMakeColor(158, 159,  33)];
+    [m_colors addObject:DDMakeColor(157, 158, 118)];
+    [m_colors addObject:DDMakeColor(157, 158, 159)];
+    [m_colors addObject:DDMakeColor(155, 157, 199)];
+    [m_colors addObject:DDMakeColor(155, 157, 239)];
+    [m_colors addObject:DDMakeColor(154, 156, 255)];
+    
+    [m_colors addObject:DDMakeColor(152, 193,  40)];
+    [m_colors addObject:DDMakeColor(151, 193, 113)];
+    [m_colors addObject:DDMakeColor(150, 193, 153)];
+    [m_colors addObject:DDMakeColor(150, 192, 193)];
+    [m_colors addObject:DDMakeColor(148, 192, 232)];
+    [m_colors addObject:DDMakeColor(149, 191, 253)];
+    
+    [m_colors addObject:DDMakeColor(146, 227,  28)];
+    [m_colors addObject:DDMakeColor(144, 227, 108)];
+    [m_colors addObject:DDMakeColor(144, 227, 147)];
+    [m_colors addObject:DDMakeColor(144, 227, 187)];
+    [m_colors addObject:DDMakeColor(142, 226, 227)];
+    [m_colors addObject:DDMakeColor(142, 225, 252)];
+    
+    [m_colors addObject:DDMakeColor(138, 253,  36)];
+    [m_colors addObject:DDMakeColor(137, 253, 102)];
+    [m_colors addObject:DDMakeColor(136, 253, 141)];
+    [m_colors addObject:DDMakeColor(138, 254, 181)];
+    [m_colors addObject:DDMakeColor(135, 255, 220)];
+    [m_colors addObject:DDMakeColor(133, 255, 250)];
+    
+    [m_colors addObject:DDMakeColor(214,  57,  30)];
+    [m_colors addObject:DDMakeColor(211,  59, 126)];
+    [m_colors addObject:DDMakeColor(209,  57, 168)];
+    [m_colors addObject:DDMakeColor(208,  55, 208)];
+    [m_colors addObject:DDMakeColor(207,  58, 247)];
+    [m_colors addObject:DDMakeColor(206,  61, 255)];
+    
+    [m_colors addObject:DDMakeColor(204, 121,  32)];
+    [m_colors addObject:DDMakeColor(202, 121, 121)];
+    [m_colors addObject:DDMakeColor(201, 121, 161)];
+    [m_colors addObject:DDMakeColor(200, 120, 202)];
+    [m_colors addObject:DDMakeColor(200, 120, 241)];
+    [m_colors addObject:DDMakeColor(198, 119, 255)];
+    
+    [m_colors addObject:DDMakeColor(198, 157,  37)];
+    [m_colors addObject:DDMakeColor(196, 157, 116)];
+    [m_colors addObject:DDMakeColor(195, 156, 157)];
+    [m_colors addObject:DDMakeColor(195, 156, 197)];
+    [m_colors addObject:DDMakeColor(194, 155, 236)];
+    [m_colors addObject:DDMakeColor(193, 155, 255)];
+    
+    [m_colors addObject:DDMakeColor(191, 192,  36)];
+    [m_colors addObject:DDMakeColor(190, 191, 112)];
+    [m_colors addObject:DDMakeColor(189, 191, 152)];
+    [m_colors addObject:DDMakeColor(189, 191, 191)];
+    [m_colors addObject:DDMakeColor(188, 190, 230)];
+    [m_colors addObject:DDMakeColor(187, 190, 253)];
+    
+    [m_colors addObject:DDMakeColor(185, 226,  28)];
+    [m_colors addObject:DDMakeColor(184, 226, 106)];
+    [m_colors addObject:DDMakeColor(183, 225, 146)];
+    [m_colors addObject:DDMakeColor(183, 225, 186)];
+    [m_colors addObject:DDMakeColor(182, 225, 225)];
+    [m_colors addObject:DDMakeColor(181, 224, 252)];
+    
+    [m_colors addObject:DDMakeColor(178, 255,  35)];
+    [m_colors addObject:DDMakeColor(178, 255, 101)];
+    [m_colors addObject:DDMakeColor(177, 254, 141)];
+    [m_colors addObject:DDMakeColor(176, 254, 180)];
+    [m_colors addObject:DDMakeColor(176, 254, 220)];
+    [m_colors addObject:DDMakeColor(175, 253, 249)];
+    
+    [m_colors addObject:DDMakeColor(247,  56,  30)];
+    [m_colors addObject:DDMakeColor(245,  57, 122)];
+    [m_colors addObject:DDMakeColor(243,  59, 163)];
+    [m_colors addObject:DDMakeColor(244,  60, 204)];
+    [m_colors addObject:DDMakeColor(242,  59, 241)];
+    [m_colors addObject:DDMakeColor(240,  55, 255)];
+    
+    [m_colors addObject:DDMakeColor(241, 119,  36)];
+    [m_colors addObject:DDMakeColor(240, 120, 118)];
+    [m_colors addObject:DDMakeColor(238, 119, 158)];
+    [m_colors addObject:DDMakeColor(237, 119, 199)];
+    [m_colors addObject:DDMakeColor(237, 118, 238)];
+    [m_colors addObject:DDMakeColor(236, 118, 255)];
+    
+    [m_colors addObject:DDMakeColor(235, 154,  36)];
+    [m_colors addObject:DDMakeColor(235, 154, 114)];
+    [m_colors addObject:DDMakeColor(234, 154, 154)];
+    [m_colors addObject:DDMakeColor(232, 154, 194)];
+    [m_colors addObject:DDMakeColor(232, 153, 234)];
+    [m_colors addObject:DDMakeColor(232, 153, 255)];
+    
+    [m_colors addObject:DDMakeColor(230, 190,  30)];
+    [m_colors addObject:DDMakeColor(229, 189, 110)];
+    [m_colors addObject:DDMakeColor(228, 189, 150)];
+    [m_colors addObject:DDMakeColor(227, 189, 190)];
+    [m_colors addObject:DDMakeColor(227, 189, 229)];
+    [m_colors addObject:DDMakeColor(226, 188, 255)];
+    
+    [m_colors addObject:DDMakeColor(224, 224,  35)];
+    [m_colors addObject:DDMakeColor(223, 224, 105)];
+    [m_colors addObject:DDMakeColor(222, 224, 144)];
+    [m_colors addObject:DDMakeColor(222, 223, 184)];
+    [m_colors addObject:DDMakeColor(222, 223, 224)];
+    [m_colors addObject:DDMakeColor(220, 223, 253)];
+    
+    [m_colors addObject:DDMakeColor(217, 253,  28)];
+    [m_colors addObject:DDMakeColor(217, 253,  99)];
+    [m_colors addObject:DDMakeColor(216, 252, 139)];
+    [m_colors addObject:DDMakeColor(216, 252, 179)];
+    [m_colors addObject:DDMakeColor(215, 252, 218)];
+    [m_colors addObject:DDMakeColor(215, 251, 250)];
+    
+    [m_colors addObject:DDMakeColor(255,  61,  30)];
+    [m_colors addObject:DDMakeColor(255,  60, 118)];
+    [m_colors addObject:DDMakeColor(255,  58, 159)];
+    [m_colors addObject:DDMakeColor(255,  56, 199)];
+    [m_colors addObject:DDMakeColor(255,  55, 238)];
+    [m_colors addObject:DDMakeColor(255,  59, 255)];
+    
+    [m_colors addObject:DDMakeColor(255, 117,  29)];
+    [m_colors addObject:DDMakeColor(255, 117, 115)];
+    [m_colors addObject:DDMakeColor(255, 117, 155)];
+    [m_colors addObject:DDMakeColor(255, 117, 195)];
+    [m_colors addObject:DDMakeColor(255, 116, 235)];
+    [m_colors addObject:DDMakeColor(254, 116, 255)];
+    
+    [m_colors addObject:DDMakeColor(255, 152,  27)];
+    [m_colors addObject:DDMakeColor(255, 152, 111)];
+    [m_colors addObject:DDMakeColor(254, 152, 152)];
+    [m_colors addObject:DDMakeColor(255, 152, 192)];
+    [m_colors addObject:DDMakeColor(254, 151, 231)];
+    [m_colors addObject:DDMakeColor(253, 151, 253)];
+    
+    [m_colors addObject:DDMakeColor(255, 187,  33)];
+    [m_colors addObject:DDMakeColor(253, 187, 107)];
+    [m_colors addObject:DDMakeColor(252, 187, 148)];
+    [m_colors addObject:DDMakeColor(253, 187, 187)];
+    [m_colors addObject:DDMakeColor(254, 187, 227)];
+    [m_colors addObject:DDMakeColor(252, 186, 252)];
+    
+    [m_colors addObject:DDMakeColor(252, 222,  34)];
+    [m_colors addObject:DDMakeColor(251, 222, 103)];
+    [m_colors addObject:DDMakeColor(251, 222, 143)];
+    [m_colors addObject:DDMakeColor(250, 222, 182)];
+    [m_colors addObject:DDMakeColor(251, 221, 222)];
+    [m_colors addObject:DDMakeColor(252, 221, 252)];
+    
+    [m_colors addObject:DDMakeColor(251, 252,  15)];
+    [m_colors addObject:DDMakeColor(251, 252,  97)];
+    [m_colors addObject:DDMakeColor(249, 252, 137)];
+    [m_colors addObject:DDMakeColor(247, 252, 177)];
+    [m_colors addObject:DDMakeColor(247, 253, 217)];
+    [m_colors addObject:DDMakeColor(254, 255, 255)];
+    
+    // Grayscale
+    
+    [m_colors addObject:DDMakeColor( 52,  53,  53)];
+    [m_colors addObject:DDMakeColor( 57,  58,  59)];
+    [m_colors addObject:DDMakeColor( 66,  67,  67)];
+    [m_colors addObject:DDMakeColor( 75,  76,  76)];
+    [m_colors addObject:DDMakeColor( 83,  85,  85)];
+    [m_colors addObject:DDMakeColor( 92,  93,  94)];
+    
+    [m_colors addObject:DDMakeColor(101, 102, 102)];
+    [m_colors addObject:DDMakeColor(109, 111, 111)];
+    [m_colors addObject:DDMakeColor(118, 119, 119)];
+    [m_colors addObject:DDMakeColor(126, 127, 128)];
+    [m_colors addObject:DDMakeColor(134, 136, 136)];
+    [m_colors addObject:DDMakeColor(143, 144, 145)];
+    
+    [m_colors addObject:DDMakeColor(151, 152, 153)];
+    [m_colors addObject:DDMakeColor(159, 161, 161)];
+    [m_colors addObject:DDMakeColor(167, 169, 169)];
+    [m_colors addObject:DDMakeColor(176, 177, 177)];
+    [m_colors addObject:DDMakeColor(184, 185, 186)];
+    [m_colors addObject:DDMakeColor(192, 193, 194)];
+    
+    [m_colors addObject:DDMakeColor(200, 201, 202)];
+    [m_colors addObject:DDMakeColor(208, 209, 210)];
+    [m_colors addObject:DDMakeColor(216, 218, 218)];
+    [m_colors addObject:DDMakeColor(224, 226, 226)];
+    [m_colors addObject:DDMakeColor(232, 234, 234)];
+    [m_colors addObject:DDMakeColor(240, 242, 242)];
+    
+    // Color codes
+
+    int index = 16;
+
+    while (index < 256) {
+        [m_codes_fg addObject:[NSString stringWithFormat:@"38;5;%dm", index]];
+        [m_codes_bg addObject:[NSString stringWithFormat:@"48;5;%dm", index]];
+
+        index++;
+    }
+
+    #else /* if MAP_TO_TERMINAL_APP_COLORS */
+
+    // Standard xterm colors:
+    //
+    // These are the colors xterm shells use in xterm-256color mode.
+    // In this mode, the shell supports 256 different colors, specified by 256 color codes.
+    //
+    // The first 16 color codes map to the original 16 color codes supported by the earlier xterm-color mode.
+    // These are generally configurable, and thus we ignore them for the purposes of mapping,
+    // as we can't rely on them being constant. They are largely duplicated anyway.
+    //
+    // The next 216 color codes are designed to run the spectrum, with several shades of every color.
+    // The last 24 color codes represent a grayscale.
+    //
+    // While the color codes are standardized, the actual RGB values for each color code is not.
+    // However most standard xterms follow a well known color chart,
+    // which can easily be calculated using the simple formula below.
+    //
+    // More information about ansi escape codes can be found online.
+    // http://en.wikipedia.org/wiki/ANSI_escape_code
+
+    int index = 16;
+
+    int r; // red
+    int g; // green
+    int b; // blue
+
+    int ri; // r increment
+    int gi; // g increment
+    int bi; // b increment
+
+    // Calculate xterm colors (using standard algorithm)
+
+    int r = 0;
+    int g = 0;
+    int b = 0;
+
+    for (ri = 0; ri < 6; ri++) {
+        r = (ri == 0) ? 0 : 95 + (40 * (ri - 1));
+
+        for (gi = 0; gi < 6; gi++) {
+            g = (gi == 0) ? 0 : 95 + (40 * (gi - 1));
+
+            for (bi = 0; bi < 6; bi++) {
+                b = (bi == 0) ? 0 : 95 + (40 * (bi - 1));
+
+                [m_codes_fg addObject:[NSString stringWithFormat:@"38;5;%dm", index]];
+                [m_codes_bg addObject:[NSString stringWithFormat:@"48;5;%dm", index]];
+                [m_colors addObject:DDMakeColor(r, g, b)];
+
+                index++;
+            }
+        }
+    }
+
+    // Calculate xterm grayscale (using standard algorithm)
+
+    r = 8;
+    g = 8;
+    b = 8;
+
+    while (index < 256) {
+        [m_codes_fg addObject:[NSString stringWithFormat:@"38;5;%dm", index]];
+        [m_codes_bg addObject:[NSString stringWithFormat:@"48;5;%dm", index]];
+        [m_colors addObject:DDMakeColor(r, g, b)];
+
+        r += 10;
+        g += 10;
+        b += 10;
+
+        index++;
+    }
+
+    #endif /* if MAP_TO_TERMINAL_APP_COLORS */
+
+    codes_fg = [m_codes_fg copy];
+    codes_bg = [m_codes_bg copy];
+    colors   = [m_colors   copy];
+
+    NSAssert([codes_fg count] == [codes_bg count], @"Invalid colors/codes array(s)");
+    NSAssert([codes_fg count] == [colors count],   @"Invalid colors/codes array(s)");
+}
+
++ (void)getRed:(CGFloat *)rPtr green:(CGFloat *)gPtr blue:(CGFloat *)bPtr fromColor:(DDColor *)color {
+    #if TARGET_OS_IPHONE
+
+    // iOS
+
+    BOOL done = NO;
+
+    if ([color respondsToSelector:@selector(getRed:green:blue:alpha:)]) {
+        done = [color getRed:rPtr green:gPtr blue:bPtr alpha:NULL];
+    }
+
+    if (!done) {
+        // The method getRed:green:blue:alpha: was only available starting iOS 5.
+        // So in iOS 4 and earlier, we have to jump through hoops.
+
+        CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
+
+        unsigned char pixel[4];
+        CGContextRef context = CGBitmapContextCreate(&pixel, 1, 1, 8, 4, rgbColorSpace, (CGBitmapInfo)(kCGBitmapAlphaInfoMask & kCGImageAlphaNoneSkipLast));
+
+        CGContextSetFillColorWithColor(context, [color CGColor]);
+        CGContextFillRect(context, CGRectMake(0, 0, 1, 1));
+
+        if (rPtr) {
+            *rPtr = pixel[0] / 255.0f;
+        }
+
+        if (gPtr) {
+            *gPtr = pixel[1] / 255.0f;
+        }
+
+        if (bPtr) {
+            *bPtr = pixel[2] / 255.0f;
+        }
+
+        CGContextRelease(context);
+        CGColorSpaceRelease(rgbColorSpace);
+    }
+
+    #elif defined(DD_CLI) || !__has_include(<AppKit/NSColor.h>)
+
+    // OS X without AppKit
+
+    [color getRed:rPtr green:gPtr blue:bPtr alpha:NULL];
+
+    #else /* if TARGET_OS_IPHONE */
+
+    // OS X with AppKit
+
+    NSColor *safeColor = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
+
+    [safeColor getRed:rPtr green:gPtr blue:bPtr alpha:NULL];
+    #endif /* if TARGET_OS_IPHONE */
+}
+
+/**
+ * Maps the given color to the closest available color supported by the shell.
+ * The shell may support 256 colors, or only 16.
+ *
+ * This method loops through the known supported color set, and calculates the closest color.
+ * The array index of that color, within the colors array, is then returned.
+ * This array index may also be used as the index within the codes_fg and codes_bg arrays.
+ **/
++ (NSUInteger)codeIndexForColor:(DDColor *)inColor {
+    CGFloat inR, inG, inB;
+
+    [self getRed:&inR green:&inG blue:&inB fromColor:inColor];
+
+    NSUInteger bestIndex = 0;
+    CGFloat lowestDistance = 100.0f;
+
+    NSUInteger i = 0;
+
+    for (DDColor *color in colors) {
+        // Calculate Euclidean distance (lower value means closer to given color)
+
+        CGFloat r, g, b;
+        [self getRed:&r green:&g blue:&b fromColor:color];
+
+    #if CGFLOAT_IS_DOUBLE
+        CGFloat distance = sqrt(pow(r - inR, 2.0) + pow(g - inG, 2.0) + pow(b - inB, 2.0));
+    #else
+        CGFloat distance = sqrtf(powf(r - inR, 2.0f) + powf(g - inG, 2.0f) + powf(b - inB, 2.0f));
+    #endif
+
+        NSLogVerbose(@"DDTTYLogger: %3lu : %.3f,%.3f,%.3f & %.3f,%.3f,%.3f = %.6f",
+                     (unsigned long)i, inR, inG, inB, r, g, b, distance);
+
+        if (distance < lowestDistance) {
+            bestIndex = i;
+            lowestDistance = distance;
+
+            NSLogVerbose(@"DDTTYLogger: New best index = %lu", (unsigned long)bestIndex);
+        }
+
+        i++;
+    }
+
+    return bestIndex;
+}
+
++ (instancetype)sharedInstance {
+    static dispatch_once_t DDTTYLoggerOnceToken;
+
+    dispatch_once(&DDTTYLoggerOnceToken, ^{
+        // Xcode does NOT natively support colors in the Xcode debugging console.
+        // You'll need to install the XcodeColors plugin to see colors in the Xcode console.
+        //
+        // PS - Please read the header file before diving into the source code.
+
+        char *xcode_colors = getenv("XcodeColors");
+        char *term = getenv("TERM");
+
+        if (xcode_colors && (strcmp(xcode_colors, "YES") == 0)) {
+            isaXcodeColorTTY = YES;
+        } else if (term) {
+            if (strcasestr(term, "color") != NULL) {
+                isaColorTTY = YES;
+                isaColor256TTY = (strcasestr(term, "256") != NULL);
+
+                if (isaColor256TTY) {
+                    [self initialize_colors_256];
+                } else {
+                    [self initialize_colors_16];
+                }
+            }
+        }
+
+        NSLogInfo(@"DDTTYLogger: isaColorTTY = %@", (isaColorTTY ? @"YES" : @"NO"));
+        NSLogInfo(@"DDTTYLogger: isaColor256TTY: %@", (isaColor256TTY ? @"YES" : @"NO"));
+        NSLogInfo(@"DDTTYLogger: isaXcodeColorTTY: %@", (isaXcodeColorTTY ? @"YES" : @"NO"));
+
+        sharedInstance = [[[self class] alloc] init];
+    });
+
+    return sharedInstance;
+}
+
+- (instancetype)init {
+    if (sharedInstance != nil) {
+        return nil;
+    }
+
+    if ((self = [super init])) {
+        _calendarUnitFlags = (NSCalendarUnitYear     |
+                             NSCalendarUnitMonth    |
+                             NSCalendarUnitDay      |
+                             NSCalendarUnitHour     |
+                             NSCalendarUnitMinute   |
+                             NSCalendarUnitSecond);
+
+        // Initialze 'app' variable (char *)
+
+        _appName = [[NSProcessInfo processInfo] processName];
+
+        _appLen = [_appName lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+
+        if (_appLen == 0) {
+            _appName = @"<UnnamedApp>";
+            _appLen = [_appName lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+        }
+
+        _app = (char *)malloc(_appLen + 1);
+
+        if (_app == NULL) {
+            return nil;
+        }
+
+        BOOL processedAppName = [_appName getCString:_app maxLength:(_appLen + 1) encoding:NSUTF8StringEncoding];
+
+        if (NO == processedAppName) {
+            free(_app);
+            return nil;
+        }
+
+        // Initialize 'pid' variable (char *)
+
+        _processID = [NSString stringWithFormat:@"%i", (int)getpid()];
+
+        _pidLen = [_processID lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+        _pid = (char *)malloc(_pidLen + 1);
+
+        if (_pid == NULL) {
+            free(_app);
+            return nil;
+        }
+
+        BOOL processedID = [_processID getCString:_pid maxLength:(_pidLen + 1) encoding:NSUTF8StringEncoding];
+
+        if (NO == processedID) {
+            free(_app);
+            free(_pid);
+            return nil;
+        }
+
+        // Initialize color stuff
+
+        _colorsEnabled = NO;
+        _colorProfilesArray = [[NSMutableArray alloc] initWithCapacity:8];
+        _colorProfilesDict = [[NSMutableDictionary alloc] initWithCapacity:8];
+
+        _automaticallyAppendNewlineForCustomFormatters = YES;
+    }
+
+    return self;
+}
+
+- (void)loadDefaultColorProfiles {
+    [self setForegroundColor:DDMakeColor(214,  57,  30) backgroundColor:nil forFlag:DDLogFlagError];
+    [self setForegroundColor:DDMakeColor(204, 121,  32) backgroundColor:nil forFlag:DDLogFlagWarning];
+}
+
+- (BOOL)colorsEnabled {
+    // The design of this method is taken from the DDAbstractLogger implementation.
+    // For extensive documentation please refer to the DDAbstractLogger implementation.
+
+    // Note: The internal implementation MUST access the colorsEnabled variable directly,
+    // This method is designed explicitly for external access.
+    //
+    // Using "self." syntax to go through this method will cause immediate deadlock.
+    // This is the intended result. Fix it by accessing the ivar directly.
+    // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
+
+    NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+    NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
+
+    dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+
+    __block BOOL result;
+
+    dispatch_sync(globalLoggingQueue, ^{
+        dispatch_sync(self.loggerQueue, ^{
+            result = _colorsEnabled;
+        });
+    });
+
+    return result;
+}
+
+- (void)setColorsEnabled:(BOOL)newColorsEnabled {
+    dispatch_block_t block = ^{
+        @autoreleasepool {
+            _colorsEnabled = newColorsEnabled;
+
+            if ([_colorProfilesArray count] == 0) {
+                [self loadDefaultColorProfiles];
+            }
+        }
+    };
+
+    // The design of this method is taken from the DDAbstractLogger implementation.
+    // For extensive documentation please refer to the DDAbstractLogger implementation.
+
+    // Note: The internal implementation MUST access the colorsEnabled variable directly,
+    // This method is designed explicitly for external access.
+    //
+    // Using "self." syntax to go through this method will cause immediate deadlock.
+    // This is the intended result. Fix it by accessing the ivar directly.
+    // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
+
+    NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+    NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
+
+    dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+
+    dispatch_async(globalLoggingQueue, ^{
+        dispatch_async(self.loggerQueue, block);
+    });
+}
+
+- (void)setForegroundColor:(DDColor *)txtColor backgroundColor:(DDColor *)bgColor forFlag:(DDLogFlag)mask {
+    [self setForegroundColor:txtColor backgroundColor:bgColor forFlag:mask context:LOG_CONTEXT_ALL];
+}
+
+- (void)setForegroundColor:(DDColor *)txtColor backgroundColor:(DDColor *)bgColor forFlag:(DDLogFlag)mask context:(NSInteger)ctxt {
+    dispatch_block_t block = ^{
+        @autoreleasepool {
+            DDTTYLoggerColorProfile *newColorProfile =
+                [[DDTTYLoggerColorProfile alloc] initWithForegroundColor:txtColor
+                                                         backgroundColor:bgColor
+                                                                    flag:mask
+                                                                 context:ctxt];
+
+            NSLogInfo(@"DDTTYLogger: newColorProfile: %@", newColorProfile);
+
+            NSUInteger i = 0;
+
+            for (DDTTYLoggerColorProfile *colorProfile in _colorProfilesArray) {
+                if ((colorProfile->mask == mask) && (colorProfile->context == ctxt)) {
+                    break;
+                }
+
+                i++;
+            }
+
+            if (i < [_colorProfilesArray count]) {
+                _colorProfilesArray[i] = newColorProfile;
+            } else {
+                [_colorProfilesArray addObject:newColorProfile];
+            }
+        }
+    };
+
+    // The design of the setter logic below is taken from the DDAbstractLogger implementation.
+    // For documentation please refer to the DDAbstractLogger implementation.
+
+    if ([self isOnInternalLoggerQueue]) {
+        block();
+    } else {
+        dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+        NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+
+        dispatch_async(globalLoggingQueue, ^{
+            dispatch_async(self.loggerQueue, block);
+        });
+    }
+}
+
+- (void)setForegroundColor:(DDColor *)txtColor backgroundColor:(DDColor *)bgColor forTag:(id <NSCopying>)tag {
+    NSAssert([(id < NSObject >) tag conformsToProtocol: @protocol(NSCopying)], @"Invalid tag");
+
+    dispatch_block_t block = ^{
+        @autoreleasepool {
+            DDTTYLoggerColorProfile *newColorProfile =
+                [[DDTTYLoggerColorProfile alloc] initWithForegroundColor:txtColor
+                                                         backgroundColor:bgColor
+                                                                    flag:(DDLogFlag)0
+                                                                 context:0];
+
+            NSLogInfo(@"DDTTYLogger: newColorProfile: %@", newColorProfile);
+
+            _colorProfilesDict[tag] = newColorProfile;
+        }
+    };
+
+    // The design of the setter logic below is taken from the DDAbstractLogger implementation.
+    // For documentation please refer to the DDAbstractLogger implementation.
+
+    if ([self isOnInternalLoggerQueue]) {
+        block();
+    } else {
+        dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+        NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+
+        dispatch_async(globalLoggingQueue, ^{
+            dispatch_async(self.loggerQueue, block);
+        });
+    }
+}
+
+- (void)clearColorsForFlag:(DDLogFlag)mask {
+    [self clearColorsForFlag:mask context:0];
+}
+
+- (void)clearColorsForFlag:(DDLogFlag)mask context:(NSInteger)context {
+    dispatch_block_t block = ^{
+        @autoreleasepool {
+            NSUInteger i = 0;
+
+            for (DDTTYLoggerColorProfile *colorProfile in _colorProfilesArray) {
+                if ((colorProfile->mask == mask) && (colorProfile->context == context)) {
+                    break;
+                }
+
+                i++;
+            }
+
+            if (i < [_colorProfilesArray count]) {
+                [_colorProfilesArray removeObjectAtIndex:i];
+            }
+        }
+    };
+
+    // The design of the setter logic below is taken from the DDAbstractLogger implementation.
+    // For documentation please refer to the DDAbstractLogger implementation.
+
+    if ([self isOnInternalLoggerQueue]) {
+        block();
+    } else {
+        dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+        NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+
+        dispatch_async(globalLoggingQueue, ^{
+            dispatch_async(self.loggerQueue, block);
+        });
+    }
+}
+
+- (void)clearColorsForTag:(id <NSCopying>)tag {
+    NSAssert([(id < NSObject >) tag conformsToProtocol: @protocol(NSCopying)], @"Invalid tag");
+
+    dispatch_block_t block = ^{
+        @autoreleasepool {
+            [_colorProfilesDict removeObjectForKey:tag];
+        }
+    };
+
+    // The design of the setter logic below is taken from the DDAbstractLogger implementation.
+    // For documentation please refer to the DDAbstractLogger implementation.
+
+    if ([self isOnInternalLoggerQueue]) {
+        block();
+    } else {
+        dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+        NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+
+        dispatch_async(globalLoggingQueue, ^{
+            dispatch_async(self.loggerQueue, block);
+        });
+    }
+}
+
+- (void)clearColorsForAllFlags {
+    dispatch_block_t block = ^{
+        @autoreleasepool {
+            [_colorProfilesArray removeAllObjects];
+        }
+    };
+
+    // The design of the setter logic below is taken from the DDAbstractLogger implementation.
+    // For documentation please refer to the DDAbstractLogger implementation.
+
+    if ([self isOnInternalLoggerQueue]) {
+        block();
+    } else {
+        dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+        NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+
+        dispatch_async(globalLoggingQueue, ^{
+            dispatch_async(self.loggerQueue, block);
+        });
+    }
+}
+
+- (void)clearColorsForAllTags {
+    dispatch_block_t block = ^{
+        @autoreleasepool {
+            [_colorProfilesDict removeAllObjects];
+        }
+    };
+
+    // The design of the setter logic below is taken from the DDAbstractLogger implementation.
+    // For documentation please refer to the DDAbstractLogger implementation.
+
+    if ([self isOnInternalLoggerQueue]) {
+        block();
+    } else {
+        dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+        NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+
+        dispatch_async(globalLoggingQueue, ^{
+            dispatch_async(self.loggerQueue, block);
+        });
+    }
+}
+
+- (void)clearAllColors {
+    dispatch_block_t block = ^{
+        @autoreleasepool {
+            [_colorProfilesArray removeAllObjects];
+            [_colorProfilesDict removeAllObjects];
+        }
+    };
+
+    // The design of the setter logic below is taken from the DDAbstractLogger implementation.
+    // For documentation please refer to the DDAbstractLogger implementation.
+
+    if ([self isOnInternalLoggerQueue]) {
+        block();
+    } else {
+        dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
+        NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
+
+        dispatch_async(globalLoggingQueue, ^{
+            dispatch_async(self.loggerQueue, block);
+        });
+    }
+}
+
+- (void)logMessage:(DDLogMessage *)logMessage {
+    NSString *logMsg = logMessage->_message;
+    BOOL isFormatted = NO;
+
+    if (_logFormatter) {
+        logMsg = [_logFormatter formatLogMessage:logMessage];
+        isFormatted = logMsg != logMessage->_message;
+    }
+
+    if (logMsg) {
+        // Search for a color profile associated with the log message
+
+        DDTTYLoggerColorProfile *colorProfile = nil;
+
+        if (_colorsEnabled) {
+            if (logMessage->_tag) {
+                colorProfile = _colorProfilesDict[logMessage->_tag];
+            }
+
+            if (colorProfile == nil) {
+                for (DDTTYLoggerColorProfile *cp in _colorProfilesArray) {
+                    if (logMessage->_flag & cp->mask) {
+                        // Color profile set for this context?
+                        if (logMessage->_context == cp->context) {
+                            colorProfile = cp;
+
+                            // Stop searching
+                            break;
+                        }
+
+                        // Check if LOG_CONTEXT_ALL was specified as a default color for this flag
+                        if (cp->context == LOG_CONTEXT_ALL) {
+                            colorProfile = cp;
+
+                            // We don't break to keep searching for more specific color profiles for the context
+                        }
+                    }
+                }
+            }
+        }
+
+        // Convert log message to C string.
+        //
+        // We use the stack instead of the heap for speed if possible.
+        // But we're extra cautious to avoid a stack overflow.
+
+        NSUInteger msgLen = [logMsg lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+        const BOOL useStack = msgLen < (1024 * 4);
+
+        char msgStack[useStack ? (msgLen + 1) : 1]; // Analyzer doesn't like zero-size array, hence the 1
+        char *msg = useStack ? msgStack : (char *)malloc(msgLen + 1);
+
+        if (msg == NULL) {
+            return;
+        }
+
+        BOOL logMsgEnc = [logMsg getCString:msg maxLength:(msgLen + 1) encoding:NSUTF8StringEncoding];
+
+        if (!logMsgEnc) {
+            if (!useStack && msg != NULL) {
+                free(msg);
+            }
+
+            return;
+        }
+
+        // Write the log message to STDERR
+
+        if (isFormatted) {
+            // The log message has already been formatted.
+            int iovec_len = (_automaticallyAppendNewlineForCustomFormatters) ? 5 : 4;
+            struct iovec v[iovec_len];
+
+            if (colorProfile) {
+                v[0].iov_base = colorProfile->fgCode;
+                v[0].iov_len = colorProfile->fgCodeLen;
+
+                v[1].iov_base = colorProfile->bgCode;
+                v[1].iov_len = colorProfile->bgCodeLen;
+
+                v[iovec_len - 1].iov_base = colorProfile->resetCode;
+                v[iovec_len - 1].iov_len = colorProfile->resetCodeLen;
+            } else {
+                v[0].iov_base = "";
+                v[0].iov_len = 0;
+
+                v[1].iov_base = "";
+                v[1].iov_len = 0;
+
+                v[iovec_len - 1].iov_base = "";
+                v[iovec_len - 1].iov_len = 0;
+            }
+
+            v[2].iov_base = (char *)msg;
+            v[2].iov_len = msgLen;
+
+            if (iovec_len == 5) {
+                v[3].iov_base = "\n";
+                v[3].iov_len = (msg[msgLen] == '\n') ? 0 : 1;
+            }
+
+            writev(STDERR_FILENO, v, iovec_len);
+        } else {
+            // The log message is unformatted, so apply standard NSLog style formatting.
+
+            int len;
+            char ts[24] = "";
+            size_t tsLen = 0;
+
+            // Calculate timestamp.
+            // The technique below is faster than using NSDateFormatter.
+            if (logMessage->_timestamp) {
+                NSDateComponents *components = [[NSCalendar autoupdatingCurrentCalendar] components:_calendarUnitFlags fromDate:logMessage->_timestamp];
+
+                NSTimeInterval epoch = [logMessage->_timestamp timeIntervalSinceReferenceDate];
+                int milliseconds = (int)((epoch - floor(epoch)) * 1000);
+
+                len = snprintf(ts, 24, "%04ld-%02ld-%02ld %02ld:%02ld:%02ld:%03d", // yyyy-MM-dd HH:mm:ss:SSS
+                               (long)components.year,
+                               (long)components.month,
+                               (long)components.day,
+                               (long)components.hour,
+                               (long)components.minute,
+                               (long)components.second, milliseconds);
+
+                tsLen = (NSUInteger)MAX(MIN(24 - 1, len), 0);
+            }
+
+            // Calculate thread ID
+            //
+            // How many characters do we need for the thread id?
+            // logMessage->machThreadID is of type mach_port_t, which is an unsigned int.
+            //
+            // 1 hex char = 4 bits
+            // 8 hex chars for 32 bit, plus ending '\0' = 9
+
+            char tid[9];
+            len = snprintf(tid, 9, "%s", [logMessage->_threadID cStringUsingEncoding:NSUTF8StringEncoding]);
+
+            size_t tidLen = (NSUInteger)MAX(MIN(9 - 1, len), 0);
+
+            // Here is our format: "%s %s[%i:%s] %s", timestamp, appName, processID, threadID, logMsg
+
+            struct iovec v[13];
+
+            if (colorProfile) {
+                v[0].iov_base = colorProfile->fgCode;
+                v[0].iov_len = colorProfile->fgCodeLen;
+
+                v[1].iov_base = colorProfile->bgCode;
+                v[1].iov_len = colorProfile->bgCodeLen;
+
+                v[12].iov_base = colorProfile->resetCode;
+                v[12].iov_len = colorProfile->resetCodeLen;
+            } else {
+                v[0].iov_base = "";
+                v[0].iov_len = 0;
+
+                v[1].iov_base = "";
+                v[1].iov_len = 0;
+
+                v[12].iov_base = "";
+                v[12].iov_len = 0;
+            }
+
+            v[2].iov_base = ts;
+            v[2].iov_len = tsLen;
+
+            v[3].iov_base = " ";
+            v[3].iov_len = 1;
+
+            v[4].iov_base = _app;
+            v[4].iov_len = _appLen;
+
+            v[5].iov_base = "[";
+            v[5].iov_len = 1;
+
+            v[6].iov_base = _pid;
+            v[6].iov_len = _pidLen;
+
+            v[7].iov_base = ":";
+            v[7].iov_len = 1;
+
+            v[8].iov_base = tid;
+            v[8].iov_len = MIN((size_t)8, tidLen); // snprintf doesn't return what you might think
+
+            v[9].iov_base = "] ";
+            v[9].iov_len = 2;
+
+            v[10].iov_base = (char *)msg;
+            v[10].iov_len = msgLen;
+
+            v[11].iov_base = "\n";
+            v[11].iov_len = (msg[msgLen] == '\n') ? 0 : 1;
+
+            writev(STDERR_FILENO, v, 13);
+        }
+
+        if (!useStack) {
+            free(msg);
+        }
+    }
+}
+
+- (NSString *)loggerName {
+    return @"cocoa.lumberjack.ttyLogger";
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation DDTTYLoggerColorProfile
+
+- (instancetype)initWithForegroundColor:(DDColor *)fgColor backgroundColor:(DDColor *)bgColor flag:(DDLogFlag)aMask context:(NSInteger)ctxt {
+    if ((self = [super init])) {
+        mask = aMask;
+        context = ctxt;
+
+        CGFloat r, g, b;
+
+        if (fgColor) {
+            [DDTTYLogger getRed:&r green:&g blue:&b fromColor:fgColor];
+
+            fg_r = (uint8_t)(r * 255.0f);
+            fg_g = (uint8_t)(g * 255.0f);
+            fg_b = (uint8_t)(b * 255.0f);
+        }
+
+        if (bgColor) {
+            [DDTTYLogger getRed:&r green:&g blue:&b fromColor:bgColor];
+
+            bg_r = (uint8_t)(r * 255.0f);
+            bg_g = (uint8_t)(g * 255.0f);
+            bg_b = (uint8_t)(b * 255.0f);
+        }
+
+        if (fgColor && isaColorTTY) {
+            // Map foreground color to closest available shell color
+
+            fgCodeIndex = [DDTTYLogger codeIndexForColor:fgColor];
+            fgCodeRaw   = codes_fg[fgCodeIndex];
+
+            NSString *escapeSeq = @"\033[";
+
+            NSUInteger len1 = [escapeSeq lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+            NSUInteger len2 = [fgCodeRaw lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+
+            BOOL escapeSeqEnc = [escapeSeq getCString:(fgCode)      maxLength:(len1 + 1) encoding:NSUTF8StringEncoding];
+            BOOL fgCodeRawEsc = [fgCodeRaw getCString:(fgCode + len1) maxLength:(len2 + 1) encoding:NSUTF8StringEncoding];
+
+            if (!escapeSeqEnc || !fgCodeRawEsc) {
+                return nil;
+            }
+
+            fgCodeLen = len1 + len2;
+        } else if (fgColor && isaXcodeColorTTY) {
+            // Convert foreground color to color code sequence
+
+            const char *escapeSeq = XCODE_COLORS_ESCAPE_SEQ;
+
+            int result = snprintf(fgCode, 24, "%sfg%u,%u,%u;", escapeSeq, fg_r, fg_g, fg_b);
+            fgCodeLen = (NSUInteger)MAX(MIN(result, (24 - 1)), 0);
+        } else {
+            // No foreground color or no color support
+
+            fgCode[0] = '\0';
+            fgCodeLen = 0;
+        }
+
+        if (bgColor && isaColorTTY) {
+            // Map background color to closest available shell color
+
+            bgCodeIndex = [DDTTYLogger codeIndexForColor:bgColor];
+            bgCodeRaw   = codes_bg[bgCodeIndex];
+
+            NSString *escapeSeq = @"\033[";
+
+            NSUInteger len1 = [escapeSeq lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+            NSUInteger len2 = [bgCodeRaw lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+
+            BOOL escapeSeqEnc = [escapeSeq getCString:(bgCode)      maxLength:(len1 + 1) encoding:NSUTF8StringEncoding];
+            BOOL bgCodeRawEsc = [bgCodeRaw getCString:(bgCode + len1) maxLength:(len2 + 1) encoding:NSUTF8StringEncoding];
+
+            if (!escapeSeqEnc || !bgCodeRawEsc) {
+                return nil;
+            }
+
+            bgCodeLen = len1 + len2;
+        } else if (bgColor && isaXcodeColorTTY) {
+            // Convert background color to color code sequence
+
+            const char *escapeSeq = XCODE_COLORS_ESCAPE_SEQ;
+
+            int result = snprintf(bgCode, 24, "%sbg%u,%u,%u;", escapeSeq, bg_r, bg_g, bg_b);
+            bgCodeLen = (NSUInteger)MAX(MIN(result, (24 - 1)), 0);
+        } else {
+            // No background color or no color support
+
+            bgCode[0] = '\0';
+            bgCodeLen = 0;
+        }
+
+        if (isaColorTTY) {
+            resetCodeLen = (NSUInteger)MAX(snprintf(resetCode, 8, "\033[0m"), 0);
+        } else if (isaXcodeColorTTY) {
+            resetCodeLen = (NSUInteger)MAX(snprintf(resetCode, 8, XCODE_COLORS_RESET), 0);
+        } else {
+            resetCode[0] = '\0';
+            resetCodeLen = 0;
+        }
+    }
+
+    return self;
+}
+
+- (NSString *)description {
+    return [NSString stringWithFormat:
+            @"<DDTTYLoggerColorProfile: %p mask:%i ctxt:%ld fg:%u,%u,%u bg:%u,%u,%u fgCode:%@ bgCode:%@>",
+            self, (int)mask, (long)context, fg_r, fg_g, fg_b, bg_r, bg_g, bg_b, fgCodeRaw, bgCodeRaw];
+}
+
+@end
diff --git a/cocoalumberjack/Classes/Extensions/._DDContextFilterLogFormatter.h b/cocoalumberjack/Classes/Extensions/._DDContextFilterLogFormatter.h
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/Extensions/._DDContextFilterLogFormatter.h
Binary files differ
diff --git a/cocoalumberjack/Classes/Extensions/._DDContextFilterLogFormatter.m b/cocoalumberjack/Classes/Extensions/._DDContextFilterLogFormatter.m
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/Extensions/._DDContextFilterLogFormatter.m
Binary files differ
diff --git a/cocoalumberjack/Classes/Extensions/._DDDispatchQueueLogFormatter.h b/cocoalumberjack/Classes/Extensions/._DDDispatchQueueLogFormatter.h
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/Extensions/._DDDispatchQueueLogFormatter.h
Binary files differ
diff --git a/cocoalumberjack/Classes/Extensions/._DDDispatchQueueLogFormatter.m b/cocoalumberjack/Classes/Extensions/._DDDispatchQueueLogFormatter.m
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/Extensions/._DDDispatchQueueLogFormatter.m
Binary files differ
diff --git a/cocoalumberjack/Classes/Extensions/._DDMultiFormatter.h b/cocoalumberjack/Classes/Extensions/._DDMultiFormatter.h
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/Extensions/._DDMultiFormatter.h
Binary files differ
diff --git a/cocoalumberjack/Classes/Extensions/._DDMultiFormatter.m b/cocoalumberjack/Classes/Extensions/._DDMultiFormatter.m
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Classes/Extensions/._DDMultiFormatter.m
Binary files differ
diff --git a/cocoalumberjack/Classes/Extensions/DDContextFilterLogFormatter.h b/cocoalumberjack/Classes/Extensions/DDContextFilterLogFormatter.h
new file mode 100644
index 0000000..1657f1f
--- /dev/null
+++ b/cocoalumberjack/Classes/Extensions/DDContextFilterLogFormatter.h
@@ -0,0 +1,117 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+#import <Foundation/Foundation.h>
+
+// Disable legacy macros
+#ifndef DD_LEGACY_MACROS
+    #define DD_LEGACY_MACROS 0
+#endif
+
+#import "DDLog.h"
+
+/**
+ * This class provides a log formatter that filters log statements from a logging context not on the whitelist.
+ *
+ * A log formatter can be added to any logger to format and/or filter its output.
+ * You can learn more about log formatters here:
+ * Documentation/CustomFormatters.md
+ *
+ * You can learn more about logging context's here:
+ * Documentation/CustomContext.md
+ *
+ * But here's a quick overview / refresher:
+ *
+ * Every log statement has a logging context.
+ * These come from the underlying logging macros defined in DDLog.h.
+ * The default logging context is zero.
+ * You can define multiple logging context's for use in your application.
+ * For example, logically separate parts of your app each have a different logging context.
+ * Also 3rd party frameworks that make use of Lumberjack generally use their own dedicated logging context.
+ **/
+@interface DDContextWhitelistFilterLogFormatter : NSObject <DDLogFormatter>
+
+/**
+ *  Designated default initializer
+ */
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
+
+/**
+ *  Add a context to the whitelist
+ *
+ *  @param loggingContext the context
+ */
+- (void)addToWhitelist:(NSUInteger)loggingContext;
+
+/**
+ *  Remove context from whitelist
+ *
+ *  @param loggingContext the context
+ */
+- (void)removeFromWhitelist:(NSUInteger)loggingContext;
+
+/**
+ *  Return the whitelist
+ */
+@property (readonly, copy) NSArray *whitelist;
+
+/**
+ *  Check if a context is on the whitelist
+ *
+ *  @param loggingContext the context
+ */
+- (BOOL)isOnWhitelist:(NSUInteger)loggingContext;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * This class provides a log formatter that filters log statements from a logging context on the blacklist.
+ **/
+@interface DDContextBlacklistFilterLogFormatter : NSObject <DDLogFormatter>
+
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
+
+/**
+ *  Add a context to the blacklist
+ *
+ *  @param loggingContext the context
+ */
+- (void)addToBlacklist:(NSUInteger)loggingContext;
+
+/**
+ *  Remove context from blacklist
+ *
+ *  @param loggingContext the context
+ */
+- (void)removeFromBlacklist:(NSUInteger)loggingContext;
+
+/**
+ *  Return the blacklist
+ */
+@property (readonly, copy) NSArray *blacklist;
+
+
+/**
+ *  Check if a context is on the blacklist
+ *
+ *  @param loggingContext the context
+ */
+- (BOOL)isOnBlacklist:(NSUInteger)loggingContext;
+
+@end
diff --git a/cocoalumberjack/Classes/Extensions/DDContextFilterLogFormatter.m b/cocoalumberjack/Classes/Extensions/DDContextFilterLogFormatter.m
new file mode 100644
index 0000000..b6d6c8a
--- /dev/null
+++ b/cocoalumberjack/Classes/Extensions/DDContextFilterLogFormatter.m
@@ -0,0 +1,192 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+#import "DDContextFilterLogFormatter.h"
+#import <libkern/OSAtomic.h>
+
+#if !__has_feature(objc_arc)
+#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
+#endif
+
+@interface DDLoggingContextSet : NSObject
+
+- (void)addToSet:(NSUInteger)loggingContext;
+- (void)removeFromSet:(NSUInteger)loggingContext;
+
+@property (readonly, copy) NSArray *currentSet;
+
+- (BOOL)isInSet:(NSUInteger)loggingContext;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface DDContextWhitelistFilterLogFormatter () {
+    DDLoggingContextSet *_contextSet;
+}
+
+@end
+
+
+@implementation DDContextWhitelistFilterLogFormatter
+
+- (instancetype)init {
+    if ((self = [super init])) {
+        _contextSet = [[DDLoggingContextSet alloc] init];
+    }
+
+    return self;
+}
+
+- (void)addToWhitelist:(NSUInteger)loggingContext {
+    [_contextSet addToSet:loggingContext];
+}
+
+- (void)removeFromWhitelist:(NSUInteger)loggingContext {
+    [_contextSet removeFromSet:loggingContext];
+}
+
+- (NSArray *)whitelist {
+    return [_contextSet currentSet];
+}
+
+- (BOOL)isOnWhitelist:(NSUInteger)loggingContext {
+    return [_contextSet isInSet:loggingContext];
+}
+
+- (NSString *)formatLogMessage:(DDLogMessage *)logMessage {
+    if ([self isOnWhitelist:logMessage->_context]) {
+        return logMessage->_message;
+    } else {
+        return nil;
+    }
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface DDContextBlacklistFilterLogFormatter () {
+    DDLoggingContextSet *_contextSet;
+}
+
+@end
+
+
+@implementation DDContextBlacklistFilterLogFormatter
+
+- (instancetype)init {
+    if ((self = [super init])) {
+        _contextSet = [[DDLoggingContextSet alloc] init];
+    }
+
+    return self;
+}
+
+- (void)addToBlacklist:(NSUInteger)loggingContext {
+    [_contextSet addToSet:loggingContext];
+}
+
+- (void)removeFromBlacklist:(NSUInteger)loggingContext {
+    [_contextSet removeFromSet:loggingContext];
+}
+
+- (NSArray *)blacklist {
+    return [_contextSet currentSet];
+}
+
+- (BOOL)isOnBlacklist:(NSUInteger)loggingContext {
+    return [_contextSet isInSet:loggingContext];
+}
+
+- (NSString *)formatLogMessage:(DDLogMessage *)logMessage {
+    if ([self isOnBlacklist:logMessage->_context]) {
+        return nil;
+    } else {
+        return logMessage->_message;
+    }
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+@interface DDLoggingContextSet () {
+    OSSpinLock _lock;
+    NSMutableSet *_set;
+}
+
+@end
+
+
+@implementation DDLoggingContextSet
+
+- (instancetype)init {
+    if ((self = [super init])) {
+        _set = [[NSMutableSet alloc] init];
+        _lock = OS_SPINLOCK_INIT;
+    }
+
+    return self;
+}
+
+- (void)addToSet:(NSUInteger)loggingContext {
+    OSSpinLockLock(&_lock);
+    {
+        [_set addObject:@(loggingContext)];
+    }
+    OSSpinLockUnlock(&_lock);
+}
+
+- (void)removeFromSet:(NSUInteger)loggingContext {
+    OSSpinLockLock(&_lock);
+    {
+        [_set removeObject:@(loggingContext)];
+    }
+    OSSpinLockUnlock(&_lock);
+}
+
+- (NSArray *)currentSet {
+    NSArray *result = nil;
+
+    OSSpinLockLock(&_lock);
+    {
+        result = [_set allObjects];
+    }
+    OSSpinLockUnlock(&_lock);
+
+    return result;
+}
+
+- (BOOL)isInSet:(NSUInteger)loggingContext {
+    BOOL result = NO;
+
+    OSSpinLockLock(&_lock);
+    {
+        result = [_set containsObject:@(loggingContext)];
+    }
+    OSSpinLockUnlock(&_lock);
+
+    return result;
+}
+
+@end
diff --git a/cocoalumberjack/Classes/Extensions/DDDispatchQueueLogFormatter.h b/cocoalumberjack/Classes/Extensions/DDDispatchQueueLogFormatter.h
new file mode 100644
index 0000000..129f6e1
--- /dev/null
+++ b/cocoalumberjack/Classes/Extensions/DDDispatchQueueLogFormatter.h
@@ -0,0 +1,178 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+#import <Foundation/Foundation.h>
+#import <libkern/OSAtomic.h>
+
+// Disable legacy macros
+#ifndef DD_LEGACY_MACROS
+    #define DD_LEGACY_MACROS 0
+#endif
+
+#import "DDLog.h"
+
+/**
+ *  Log formatter mode
+ */
+typedef NS_ENUM(NSUInteger, DDDispatchQueueLogFormatterMode){
+    /**
+     *  This is the default option, means the formatter can be reused between multiple loggers and therefore is thread-safe.
+     *  There is, of course, a performance cost for the thread-safety
+     */
+    DDDispatchQueueLogFormatterModeShareble = 0,
+    /**
+     *  If the formatter will only be used by a single logger, then the thread-safety can be removed
+     *  @note: there is an assert checking if the formatter is added to multiple loggers and the mode is non-shareble
+     */
+    DDDispatchQueueLogFormatterModeNonShareble,
+};
+
+
+/**
+ * This class provides a log formatter that prints the dispatch_queue label instead of the mach_thread_id.
+ *
+ * A log formatter can be added to any logger to format and/or filter its output.
+ * You can learn more about log formatters here:
+ * Documentation/CustomFormatters.md
+ *
+ * A typical `NSLog` (or `DDTTYLogger`) prints detailed info as `[<process_id>:<thread_id>]`.
+ * For example:
+ *
+ * `2011-10-17 20:21:45.435 AppName[19928:5207] Your log message here`
+ *
+ * Where:
+ * `- 19928 = process id`
+ * `-  5207 = thread id (mach_thread_id printed in hex)`
+ *
+ * When using grand central dispatch (GCD), this information is less useful.
+ * This is because a single serial dispatch queue may be run on any thread from an internally managed thread pool.
+ * For example:
+ *
+ * `2011-10-17 20:32:31.111 AppName[19954:4d07] Message from my_serial_dispatch_queue`
+ * `2011-10-17 20:32:31.112 AppName[19954:5207] Message from my_serial_dispatch_queue`
+ * `2011-10-17 20:32:31.113 AppName[19954:2c55] Message from my_serial_dispatch_queue`
+ *
+ * This formatter allows you to replace the standard `[box:info]` with the dispatch_queue name.
+ * For example:
+ *
+ * `2011-10-17 20:32:31.111 AppName[img-scaling] Message from my_serial_dispatch_queue`
+ * `2011-10-17 20:32:31.112 AppName[img-scaling] Message from my_serial_dispatch_queue`
+ * `2011-10-17 20:32:31.113 AppName[img-scaling] Message from my_serial_dispatch_queue`
+ *
+ * If the dispatch_queue doesn't have a set name, then it falls back to the thread name.
+ * If the current thread doesn't have a set name, then it falls back to the mach_thread_id in hex (like normal).
+ *
+ * Note: If manually creating your own background threads (via `NSThread/alloc/init` or `NSThread/detachNeThread`),
+ * you can use `[[NSThread currentThread] setName:(NSString *)]`.
+ **/
+@interface DDDispatchQueueLogFormatter : NSObject <DDLogFormatter>
+
+/**
+ * Standard init method.
+ * Configure using properties as desired.
+ **/
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
+
+/**
+ *  Initializer with ability to set the queue mode
+ *
+ *  @param mode choose between DDDispatchQueueLogFormatterModeShareble and DDDispatchQueueLogFormatterModeNonShareble, depending if the formatter is shared between several loggers or not
+ */
+- (instancetype)initWithMode:(DDDispatchQueueLogFormatterMode)mode;
+
+/**
+ * The minQueueLength restricts the minimum size of the [detail box].
+ * If the minQueueLength is set to 0, there is no restriction.
+ *
+ * For example, say a dispatch_queue has a label of "diskIO":
+ *
+ * If the minQueueLength is 0: [diskIO]
+ * If the minQueueLength is 4: [diskIO]
+ * If the minQueueLength is 5: [diskIO]
+ * If the minQueueLength is 6: [diskIO]
+ * If the minQueueLength is 7: [diskIO ]
+ * If the minQueueLength is 8: [diskIO  ]
+ *
+ * The default minQueueLength is 0 (no minimum, so [detail box] won't be padded).
+ *
+ * If you want every [detail box] to have the exact same width,
+ * set both minQueueLength and maxQueueLength to the same value.
+ **/
+@property (assign, atomic) NSUInteger minQueueLength;
+
+/**
+ * The maxQueueLength restricts the number of characters that will be inside the [detail box].
+ * If the maxQueueLength is 0, there is no restriction.
+ *
+ * For example, say a dispatch_queue has a label of "diskIO":
+ *
+ * If the maxQueueLength is 0: [diskIO]
+ * If the maxQueueLength is 4: [disk]
+ * If the maxQueueLength is 5: [diskI]
+ * If the maxQueueLength is 6: [diskIO]
+ * If the maxQueueLength is 7: [diskIO]
+ * If the maxQueueLength is 8: [diskIO]
+ *
+ * The default maxQueueLength is 0 (no maximum, so [detail box] won't be truncated).
+ *
+ * If you want every [detail box] to have the exact same width,
+ * set both minQueueLength and maxQueueLength to the same value.
+ **/
+@property (assign, atomic) NSUInteger maxQueueLength;
+
+/**
+ * Sometimes queue labels have long names like "com.apple.main-queue",
+ * but you'd prefer something shorter like simply "main".
+ *
+ * This method allows you to set such preferred replacements.
+ * The above example is set by default.
+ *
+ * To remove/undo a previous replacement, invoke this method with nil for the 'shortLabel' parameter.
+ **/
+- (NSString *)replacementStringForQueueLabel:(NSString *)longLabel;
+
+/**
+ *  See the `replacementStringForQueueLabel:` description
+ */
+- (void)setReplacementString:(NSString *)shortLabel forQueueLabel:(NSString *)longLabel;
+
+@end
+
+/**
+ *  Category on `DDDispatchQueueLogFormatter` to make method declarations easier to extend/modify
+ **/
+@interface DDDispatchQueueLogFormatter (OverridableMethods)
+
+/**
+ *  Date formatter default configuration
+ */
+- (void)configureDateFormatter:(NSDateFormatter *)dateFormatter;
+
+/**
+ *  Formatter method to transfrom from date to string
+ */
+- (NSString *)stringFromDate:(NSDate *)date;
+
+/**
+ *  Method to compute the queue thread label
+ */
+- (NSString *)queueThreadLabelForLogMessage:(DDLogMessage *)logMessage;
+
+/**
+ *  The actual method that formats a message (transforms a `DDLogMessage` model into a printable string)
+ */
+- (NSString *)formatLogMessage:(DDLogMessage *)logMessage;
+
+@end
diff --git a/cocoalumberjack/Classes/Extensions/DDDispatchQueueLogFormatter.m b/cocoalumberjack/Classes/Extensions/DDDispatchQueueLogFormatter.m
new file mode 100644
index 0000000..c0c3b2e
--- /dev/null
+++ b/cocoalumberjack/Classes/Extensions/DDDispatchQueueLogFormatter.m
@@ -0,0 +1,278 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+#import "DDDispatchQueueLogFormatter.h"
+#import <libkern/OSAtomic.h>
+#import <objc/runtime.h>
+
+
+#if !__has_feature(objc_arc)
+#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
+#endif
+
+@interface DDDispatchQueueLogFormatter () {
+    DDDispatchQueueLogFormatterMode _mode;
+    NSString *_dateFormatterKey;
+    
+    int32_t _atomicLoggerCount;
+    NSDateFormatter *_threadUnsafeDateFormatter; // Use [self stringFromDate]
+    
+    OSSpinLock _lock;
+    
+    NSUInteger _minQueueLength;           // _prefix == Only access via atomic property
+    NSUInteger _maxQueueLength;           // _prefix == Only access via atomic property
+    NSMutableDictionary *_replacements;   // _prefix == Only access from within spinlock
+}
+
+@end
+
+
+@implementation DDDispatchQueueLogFormatter
+
+- (instancetype)init {
+    if ((self = [super init])) {
+        _mode = DDDispatchQueueLogFormatterModeShareble;
+
+        // We need to carefully pick the name for storing in thread dictionary to not
+        // use a formatter configured by subclass and avoid surprises.
+        Class cls = [self class];
+        Class superClass = class_getSuperclass(cls);
+        SEL configMethodName = @selector(configureDateFormatter:);
+        Method configMethod = class_getInstanceMethod(cls, configMethodName);
+        while (class_getInstanceMethod(superClass, configMethodName) == configMethod) {
+            cls = superClass;
+            superClass = class_getSuperclass(cls);
+        }
+        // now `cls` is the class that provides implementation for `configureDateFormatter:`
+        _dateFormatterKey = [NSString stringWithFormat:@"%s_NSDateFormatter", class_getName(cls)];
+
+        _atomicLoggerCount = 0;
+        _threadUnsafeDateFormatter = nil;
+
+        _minQueueLength = 0;
+        _maxQueueLength = 0;
+        _lock = OS_SPINLOCK_INIT;
+        _replacements = [[NSMutableDictionary alloc] init];
+
+        // Set default replacements:
+
+        _replacements[@"com.apple.main-thread"] = @"main";
+    }
+
+    return self;
+}
+
+- (instancetype)initWithMode:(DDDispatchQueueLogFormatterMode)mode {
+    if ((self = [self init])) {
+        _mode = mode;
+    }
+    return self;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark Configuration
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@synthesize minQueueLength = _minQueueLength;
+@synthesize maxQueueLength = _maxQueueLength;
+
+- (NSString *)replacementStringForQueueLabel:(NSString *)longLabel {
+    NSString *result = nil;
+
+    OSSpinLockLock(&_lock);
+    {
+        result = _replacements[longLabel];
+    }
+    OSSpinLockUnlock(&_lock);
+
+    return result;
+}
+
+- (void)setReplacementString:(NSString *)shortLabel forQueueLabel:(NSString *)longLabel {
+    OSSpinLockLock(&_lock);
+    {
+        if (shortLabel) {
+            _replacements[longLabel] = shortLabel;
+        } else {
+            [_replacements removeObjectForKey:longLabel];
+        }
+    }
+    OSSpinLockUnlock(&_lock);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark DDLogFormatter
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+- (NSDateFormatter *)createDateFormatter {
+    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
+    [self configureDateFormatter:formatter];
+    return formatter;
+}
+
+- (void)configureDateFormatter:(NSDateFormatter *)dateFormatter {
+    [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
+    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss:SSS"];
+    [dateFormatter setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]];
+
+    NSString *calendarIdentifier = nil;
+#if defined(__IPHONE_8_0) || defined(__MAC_10_10)
+    calendarIdentifier = NSCalendarIdentifierGregorian;
+#else
+    calendarIdentifier = NSGregorianCalendar;
+#endif
+
+    [dateFormatter setCalendar:[[NSCalendar alloc] initWithCalendarIdentifier:calendarIdentifier]];
+}
+
+- (NSString *)stringFromDate:(NSDate *)date {
+
+    NSDateFormatter *dateFormatter = nil;
+    if (_mode == DDDispatchQueueLogFormatterModeNonShareble) {
+        // Single-threaded mode.
+
+        dateFormatter = _threadUnsafeDateFormatter;
+        if (dateFormatter == nil) {
+            dateFormatter = [self createDateFormatter];
+            _threadUnsafeDateFormatter = dateFormatter;
+        }
+    } else {
+        // Multi-threaded mode.
+        // NSDateFormatter is NOT thread-safe.
+
+        NSString *key = _dateFormatterKey;
+
+        NSMutableDictionary *threadDictionary = [[NSThread currentThread] threadDictionary];
+        dateFormatter = threadDictionary[key];
+
+        if (dateFormatter == nil) {
+            dateFormatter = [self createDateFormatter];
+            threadDictionary[key] = dateFormatter;
+        }
+    }
+
+    return [dateFormatter stringFromDate:date];
+}
+
+- (NSString *)queueThreadLabelForLogMessage:(DDLogMessage *)logMessage {
+    // As per the DDLogFormatter contract, this method is always invoked on the same thread/dispatch_queue
+
+    NSUInteger minQueueLength = self.minQueueLength;
+    NSUInteger maxQueueLength = self.maxQueueLength;
+
+    // Get the name of the queue, thread, or machID (whichever we are to use).
+
+    NSString *queueThreadLabel = nil;
+
+    BOOL useQueueLabel = YES;
+    BOOL useThreadName = NO;
+
+    if (logMessage->_queueLabel) {
+        // If you manually create a thread, it's dispatch_queue will have one of the thread names below.
+        // Since all such threads have the same name, we'd prefer to use the threadName or the machThreadID.
+
+        NSArray *names = @[
+            @"com.apple.root.low-priority",
+            @"com.apple.root.default-priority",
+            @"com.apple.root.high-priority",
+            @"com.apple.root.low-overcommit-priority",
+            @"com.apple.root.default-overcommit-priority",
+            @"com.apple.root.high-overcommit-priority"
+        ];
+
+        for (NSString * name in names) {
+            if ([logMessage->_queueLabel isEqualToString:name]) {
+                useQueueLabel = NO;
+                useThreadName = [logMessage->_threadName length] > 0;
+                break;
+            }
+        }
+    } else {
+        useQueueLabel = NO;
+        useThreadName = [logMessage->_threadName length] > 0;
+    }
+
+    if (useQueueLabel || useThreadName) {
+        NSString *fullLabel;
+        NSString *abrvLabel;
+
+        if (useQueueLabel) {
+            fullLabel = logMessage->_queueLabel;
+        } else {
+            fullLabel = logMessage->_threadName;
+        }
+
+        OSSpinLockLock(&_lock);
+        {
+            abrvLabel = _replacements[fullLabel];
+        }
+        OSSpinLockUnlock(&_lock);
+
+        if (abrvLabel) {
+            queueThreadLabel = abrvLabel;
+        } else {
+            queueThreadLabel = fullLabel;
+        }
+    } else {
+        queueThreadLabel = logMessage->_threadID;
+    }
+
+    // Now use the thread label in the output
+
+    NSUInteger labelLength = [queueThreadLabel length];
+
+    // labelLength > maxQueueLength : truncate
+    // labelLength < minQueueLength : padding
+    //                              : exact
+
+    if ((maxQueueLength > 0) && (labelLength > maxQueueLength)) {
+        // Truncate
+
+        return [queueThreadLabel substringToIndex:maxQueueLength];
+    } else if (labelLength < minQueueLength) {
+        // Padding
+
+        NSUInteger numSpaces = minQueueLength - labelLength;
+
+        char spaces[numSpaces + 1];
+        memset(spaces, ' ', numSpaces);
+        spaces[numSpaces] = '\0';
+
+        return [NSString stringWithFormat:@"%@%s", queueThreadLabel, spaces];
+    } else {
+        // Exact
+
+        return queueThreadLabel;
+    }
+}
+
+- (NSString *)formatLogMessage:(DDLogMessage *)logMessage {
+    NSString *timestamp = [self stringFromDate:(logMessage->_timestamp)];
+    NSString *queueThreadLabel = [self queueThreadLabelForLogMessage:logMessage];
+
+    return [NSString stringWithFormat:@"%@ [%@] %@", timestamp, queueThreadLabel, logMessage->_message];
+}
+
+- (void)didAddToLogger:(id <DDLogger>  __attribute__((unused)))logger {
+    int32_t count = 0;
+    count = OSAtomicIncrement32(&_atomicLoggerCount);
+    NSAssert(count <= 1 || _mode == DDDispatchQueueLogFormatterModeShareble, @"Can't reuse formatter with multiple loggers in non-shareable mode.");
+}
+
+- (void)willRemoveFromLogger:(id <DDLogger> __attribute__((unused)))logger {
+    OSAtomicDecrement32(&_atomicLoggerCount);
+}
+
+@end
diff --git a/cocoalumberjack/Classes/Extensions/DDMultiFormatter.h b/cocoalumberjack/Classes/Extensions/DDMultiFormatter.h
new file mode 100644
index 0000000..1d6ceea
--- /dev/null
+++ b/cocoalumberjack/Classes/Extensions/DDMultiFormatter.h
@@ -0,0 +1,56 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+#import <Foundation/Foundation.h>
+
+// Disable legacy macros
+#ifndef DD_LEGACY_MACROS
+    #define DD_LEGACY_MACROS 0
+#endif
+
+#import "DDLog.h"
+
+/**
+ * This formatter can be used to chain different formatters together.
+ * The log message will processed in the order of the formatters added.
+ **/
+@interface DDMultiFormatter : NSObject <DDLogFormatter>
+
+/**
+ *  Array of chained formatters
+ */
+@property (readonly) NSArray *formatters;
+
+/**
+ *  Add a new formatter
+ */
+- (void)addFormatter:(id<DDLogFormatter>)formatter;
+
+/**
+ *  Remove a formatter
+ */
+- (void)removeFormatter:(id<DDLogFormatter>)formatter;
+
+/**
+ *  Remove all existing formatters
+ */
+- (void)removeAllFormatters;
+
+/**
+ *  Check if a certain formatter is used
+ */
+- (BOOL)isFormattingWithFormatter:(id<DDLogFormatter>)formatter;
+
+@end
diff --git a/cocoalumberjack/Classes/Extensions/DDMultiFormatter.m b/cocoalumberjack/Classes/Extensions/DDMultiFormatter.m
new file mode 100644
index 0000000..c647da3
--- /dev/null
+++ b/cocoalumberjack/Classes/Extensions/DDMultiFormatter.m
@@ -0,0 +1,144 @@
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2010-2015, Deusty, LLC
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// * Neither the name of Deusty nor the names of its contributors may be used
+//   to endorse or promote products derived from this software without specific
+//   prior written permission of Deusty, LLC.
+
+#import "DDMultiFormatter.h"
+
+
+#if TARGET_OS_IOS
+// Compiling for iOS
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000 // iOS 6.0 or later
+#define NEEDS_DISPATCH_RETAIN_RELEASE 0
+#else                                         // iOS 5.X or earlier
+#define NEEDS_DISPATCH_RETAIN_RELEASE 1
+#endif
+#elif TARGET_OS_WATCH || TARGET_OS_TV
+// Compiling for watchOS, tvOS
+#define NEEDS_DISPATCH_RETAIN_RELEASE 0
+#else
+// Compiling for Mac OS X
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1080     // Mac OS X 10.8 or later
+#define NEEDS_DISPATCH_RETAIN_RELEASE 0
+#else                                         // Mac OS X 10.7 or earlier
+#define NEEDS_DISPATCH_RETAIN_RELEASE 1
+#endif
+#endif
+
+
+#if !__has_feature(objc_arc)
+#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
+#endif
+
+
+@interface DDMultiFormatter () {
+    dispatch_queue_t _queue;
+    NSMutableArray *_formatters;
+}
+
+- (DDLogMessage *)logMessageForLine:(NSString *)line originalMessage:(DDLogMessage *)message;
+
+@end
+
+
+@implementation DDMultiFormatter
+
+- (instancetype)init {
+    self = [super init];
+
+    if (self) {
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+        _queue = dispatch_queue_create("cocoa.lumberjack.multiformatter", DISPATCH_QUEUE_CONCURRENT);
+#else
+        _queue = dispatch_queue_create("cocoa.lumberjack.multiformatter", NULL);
+#endif
+        _formatters = [NSMutableArray new];
+    }
+
+    return self;
+}
+
+#if NEEDS_DISPATCH_RETAIN_RELEASE
+- (void)dealloc {
+    dispatch_release(_queue);
+}
+
+#endif
+
+#pragma mark Processing
+
+- (NSString *)formatLogMessage:(DDLogMessage *)logMessage {
+    __block NSString *line = logMessage->_message;
+
+    dispatch_sync(_queue, ^{
+        for (id<DDLogFormatter> formatter in _formatters) {
+            DDLogMessage *message = [self logMessageForLine:line originalMessage:logMessage];
+            line = [formatter formatLogMessage:message];
+
+            if (!line) {
+                break;
+            }
+        }
+    });
+
+    return line;
+}
+
+- (DDLogMessage *)logMessageForLine:(NSString *)line originalMessage:(DDLogMessage *)message {
+    DDLogMessage *newMessage = [message copy];
+
+    newMessage->_message = line;
+    return newMessage;
+}
+
+#pragma mark Formatters
+
+- (NSArray *)formatters {
+    __block NSArray *formatters;
+
+    dispatch_sync(_queue, ^{
+        formatters = [_formatters copy];
+    });
+
+    return formatters;
+}
+
+- (void)addFormatter:(id<DDLogFormatter>)formatter {
+    dispatch_barrier_async(_queue, ^{
+        [_formatters addObject:formatter];
+    });
+}
+
+- (void)removeFormatter:(id<DDLogFormatter>)formatter {
+    dispatch_barrier_async(_queue, ^{
+        [_formatters removeObject:formatter];
+    });
+}
+
+- (void)removeAllFormatters {
+    dispatch_barrier_async(_queue, ^{
+        [_formatters removeAllObjects];
+    });
+}
+
+- (BOOL)isFormattingWithFormatter:(id<DDLogFormatter>)formatter {
+    __block BOOL hasFormatter;
+
+    dispatch_sync(_queue, ^{
+        hasFormatter = [_formatters containsObject:formatter];
+    });
+
+    return hasFormatter;
+}
+
+@end
diff --git a/cocoalumberjack/CocoaLumberjack.podspec b/cocoalumberjack/CocoaLumberjack.podspec
new file mode 100644
index 0000000..c80a8ef
--- /dev/null
+++ b/cocoalumberjack/CocoaLumberjack.podspec
@@ -0,0 +1,60 @@
+
+Pod::Spec.new do |s|
+
+  s.name     = 'CocoaLumberjack'
+  s.version  = '2.2.1nest'
+  s.license  = 'BSD'
+  s.summary  = 'A fast & simple, yet powerful & flexible logging framework for Mac and iOS.'
+  s.homepage = 'https://github.com/CocoaLumberjack/CocoaLumberjack'
+  s.author   = { 'Robbie Hanson' => 'robbiehanson@deusty.com' }
+  s.source   = { :git => 'https://github.com/CocoaLumberjack/CocoaLumberjack.git',
+                 :tag => "#{s.version}" }
+
+  s.description = 'It is similar in concept to other popular logging frameworks such as log4j, '   \
+                  'yet is designed specifically for objective-c, and takes advantage of features ' \
+                  'such as multi-threading, grand central dispatch (if available), lockless '      \
+                  'atomic operations, and the dynamic nature of the objective-c runtime.'
+
+  s.requires_arc   = true
+
+  s.preserve_paths = 'README.md', 'Classes/CocoaLumberjack.swift', 'Framework/Lumberjack/CocoaLumberjack.modulemap'
+  s.ios.deployment_target = '5.0'
+  s.osx.deployment_target = '10.7'
+  s.watchos.deployment_target = '2.0'
+  s.tvos.deployment_target = '9.0'
+  
+  s.public_header_files = 'Classes/*.h'
+  
+  s.module_map = 'Framework/Lumberjack/CocoaLumberjack.modulemap'
+  s.default_subspecs = 'Default', 'Extensions'
+
+  s.subspec 'Default' do |ss|
+    ss.source_files = 'Classes/CocoaLumberjack.{h,m}'
+    ss.dependency 'CocoaLumberjack/Core'
+  end
+
+  s.subspec 'Core' do |ss|
+    ss.source_files = 'Classes/DD*.{h,m}'
+  end
+
+  s.subspec 'Extensions' do |ss|
+    ss.source_files = 'Classes/Extensions/*.{h,m}'
+    ss.dependency 'CocoaLumberjack/Default'
+  end
+  
+  s.subspec 'CLI' do |ss|
+    ss.osx.deployment_target = '10.7'
+    ss.source_files = 'Classes/CLI/*.{h,m}'
+    ss.dependency 'CocoaLumberjack/Default'
+  end
+
+  s.subspec 'Swift' do |ss|
+    ss.ios.deployment_target = '8.0'
+    ss.osx.deployment_target = '10.10'
+    ss.watchos.deployment_target = '2.0'
+    ss.tvos.deployment_target = '9.0'
+    ss.source_files = 'Classes/CocoaLumberjack.swift'
+    ss.dependency 'CocoaLumberjack/Extensions'
+  end
+  
+end
diff --git a/cocoalumberjack/Demos/._Benchmark b/cocoalumberjack/Demos/._Benchmark
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/._Benchmark
Binary files differ
diff --git a/cocoalumberjack/Demos/._CLI b/cocoalumberjack/Demos/._CLI
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/._CLI
Binary files differ
diff --git a/cocoalumberjack/Demos/._CaptureASL b/cocoalumberjack/Demos/._CaptureASL
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/._CaptureASL
Binary files differ
diff --git a/cocoalumberjack/Demos/._ContextFilter b/cocoalumberjack/Demos/._ContextFilter
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/._ContextFilter
Binary files differ
diff --git a/cocoalumberjack/Demos/._CoreDataLogger b/cocoalumberjack/Demos/._CoreDataLogger
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/._CoreDataLogger
Binary files differ
diff --git a/cocoalumberjack/Demos/._CustomFormatters b/cocoalumberjack/Demos/._CustomFormatters
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/._CustomFormatters
Binary files differ
diff --git a/cocoalumberjack/Demos/._CustomLogLevels b/cocoalumberjack/Demos/._CustomLogLevels
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/._CustomLogLevels
Binary files differ
diff --git a/cocoalumberjack/Demos/._Demos.xcworkspace b/cocoalumberjack/Demos/._Demos.xcworkspace
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/._Demos.xcworkspace
Binary files differ
diff --git a/cocoalumberjack/Demos/._DispatchQueueLogger b/cocoalumberjack/Demos/._DispatchQueueLogger
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/._DispatchQueueLogger
Binary files differ
diff --git a/cocoalumberjack/Demos/._FineGrainedLogging b/cocoalumberjack/Demos/._FineGrainedLogging
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/._FineGrainedLogging
Binary files differ
diff --git a/cocoalumberjack/Demos/._GlobalLogLevel b/cocoalumberjack/Demos/._GlobalLogLevel
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/._GlobalLogLevel
Binary files differ
diff --git a/cocoalumberjack/Demos/._LogFileCompressor b/cocoalumberjack/Demos/._LogFileCompressor
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/._LogFileCompressor
Binary files differ
diff --git a/cocoalumberjack/Demos/._NonArcTest b/cocoalumberjack/Demos/._NonArcTest
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/._NonArcTest
Binary files differ
diff --git a/cocoalumberjack/Demos/._OverflowTestMac b/cocoalumberjack/Demos/._OverflowTestMac
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/._OverflowTestMac
Binary files differ
diff --git a/cocoalumberjack/Demos/._PerUserLogLevels b/cocoalumberjack/Demos/._PerUserLogLevels
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/._PerUserLogLevels
Binary files differ
diff --git a/cocoalumberjack/Demos/._RegisteredDynamicLogging b/cocoalumberjack/Demos/._RegisteredDynamicLogging
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/._RegisteredDynamicLogging
Binary files differ
diff --git a/cocoalumberjack/Demos/._RollingTestMac b/cocoalumberjack/Demos/._RollingTestMac
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/._RollingTestMac
Binary files differ
diff --git a/cocoalumberjack/Demos/._SQLiteLogger b/cocoalumberjack/Demos/._SQLiteLogger
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/._SQLiteLogger
Binary files differ
diff --git a/cocoalumberjack/Demos/._TestXcodeColors b/cocoalumberjack/Demos/._TestXcodeColors
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/._TestXcodeColors
Binary files differ
diff --git a/cocoalumberjack/Demos/._UniversalApp b/cocoalumberjack/Demos/._UniversalApp
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/._UniversalApp
Binary files differ
diff --git a/cocoalumberjack/Demos/._WebServerIPhone b/cocoalumberjack/Demos/._WebServerIPhone
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/._WebServerIPhone
Binary files differ
diff --git a/cocoalumberjack/Demos/Benchmark/._Desktop b/cocoalumberjack/Demos/Benchmark/._Desktop
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/._Desktop
Binary files differ
diff --git a/cocoalumberjack/Demos/Benchmark/._Mobile b/cocoalumberjack/Demos/Benchmark/._Mobile
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/._Mobile
Binary files differ
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/._BenchmarkMac b/cocoalumberjack/Demos/Benchmark/Desktop/._BenchmarkMac
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/._BenchmarkMac
Binary files differ
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/._BenchmarkMac.xcodeproj b/cocoalumberjack/Demos/Benchmark/Desktop/._BenchmarkMac.xcodeproj
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/._BenchmarkMac.xcodeproj
Binary files differ
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/._Podfile b/cocoalumberjack/Demos/Benchmark/Desktop/._Podfile
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/._Podfile
Binary files differ
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/._ReadMe.txt b/cocoalumberjack/Demos/Benchmark/Desktop/._ReadMe.txt
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/._ReadMe.txt
Binary files differ
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac.xcodeproj/._project.pbxproj b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac.xcodeproj/._project.pbxproj
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac.xcodeproj/._project.pbxproj
Binary files differ
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac.xcodeproj/._xcshareddata b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac.xcodeproj/._xcshareddata
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac.xcodeproj/._xcshareddata
Binary files differ
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac.xcodeproj/project.pbxproj b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..62b8bf9
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac.xcodeproj/project.pbxproj
@@ -0,0 +1,404 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		DCC29DE114730AA9005E8FD4 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC29DE014730AA9005E8FD4 /* Cocoa.framework */; };
+		DCC29DEB14730AA9005E8FD4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = DCC29DE914730AA9005E8FD4 /* InfoPlist.strings */; };
+		DCC29DED14730AA9005E8FD4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC29DEC14730AA9005E8FD4 /* main.m */; };
+		DCC29DF114730AA9005E8FD4 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = DCC29DEF14730AA9005E8FD4 /* Credits.rtf */; };
+		DCC29DF414730AA9005E8FD4 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC29DF314730AA9005E8FD4 /* AppDelegate.m */; };
+		DCC29DF714730AA9005E8FD4 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = DCC29DF514730AA9005E8FD4 /* MainMenu.xib */; };
+		DCC29E1F14730B05005E8FD4 /* BaseNSLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC29E1814730B05005E8FD4 /* BaseNSLogging.m */; };
+		DCC29E2014730B05005E8FD4 /* DynamicLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC29E1A14730B05005E8FD4 /* DynamicLogging.m */; };
+		DCC29E2114730B05005E8FD4 /* PerformanceTesting.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC29E1C14730B05005E8FD4 /* PerformanceTesting.m */; };
+		DCC29E2214730B05005E8FD4 /* StaticLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC29E1E14730B05005E8FD4 /* StaticLogging.m */; };
+		F434A3AE9AE44303AA5DB377 /* libPods-BM_osx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B87C32CF2EF4298BD9B0199 /* libPods-BM_osx.a */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+		3B87C32CF2EF4298BD9B0199 /* libPods-BM_osx.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-BM_osx.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+		5EE3DC55E808453403A4E009 /* Pods-BM_osx.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BM_osx.debug.xcconfig"; path = "Pods/Target Support Files/Pods-BM_osx/Pods-BM_osx.debug.xcconfig"; sourceTree = "<group>"; };
+		A4CB8540E4C50155D1D220D9 /* Pods-BM_osx.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BM_osx.release.xcconfig"; path = "Pods/Target Support Files/Pods-BM_osx/Pods-BM_osx.release.xcconfig"; sourceTree = "<group>"; };
+		DCC29DDC14730AA9005E8FD4 /* BenchmarkMac.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BenchmarkMac.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		DCC29DE014730AA9005E8FD4 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
+		DCC29DE314730AA9005E8FD4 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
+		DCC29DE414730AA9005E8FD4 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
+		DCC29DE514730AA9005E8FD4 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+		DCC29DE814730AA9005E8FD4 /* BenchmarkMac-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "BenchmarkMac-Info.plist"; sourceTree = "<group>"; };
+		DCC29DEA14730AA9005E8FD4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+		DCC29DEC14730AA9005E8FD4 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+		DCC29DEE14730AA9005E8FD4 /* BenchmarkMac-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BenchmarkMac-Prefix.pch"; sourceTree = "<group>"; };
+		DCC29DF014730AA9005E8FD4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = "<group>"; };
+		DCC29DF214730AA9005E8FD4 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+		DCC29DF314730AA9005E8FD4 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+		DCC29DF614730AA9005E8FD4 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = "<group>"; };
+		DCC29E1714730B05005E8FD4 /* BaseNSLogging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BaseNSLogging.h; sourceTree = "<group>"; };
+		DCC29E1814730B05005E8FD4 /* BaseNSLogging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BaseNSLogging.m; sourceTree = "<group>"; };
+		DCC29E1914730B05005E8FD4 /* DynamicLogging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DynamicLogging.h; sourceTree = "<group>"; };
+		DCC29E1A14730B05005E8FD4 /* DynamicLogging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DynamicLogging.m; sourceTree = "<group>"; };
+		DCC29E1B14730B05005E8FD4 /* PerformanceTesting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PerformanceTesting.h; sourceTree = "<group>"; };
+		DCC29E1C14730B05005E8FD4 /* PerformanceTesting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PerformanceTesting.m; sourceTree = "<group>"; };
+		DCC29E1D14730B05005E8FD4 /* StaticLogging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaticLogging.h; sourceTree = "<group>"; };
+		DCC29E1E14730B05005E8FD4 /* StaticLogging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StaticLogging.m; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		DCC29DD914730AA9005E8FD4 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				DCC29DE114730AA9005E8FD4 /* Cocoa.framework in Frameworks */,
+				F434A3AE9AE44303AA5DB377 /* libPods-BM_osx.a in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		8B2D89AB0547F7D910983389 /* Pods */ = {
+			isa = PBXGroup;
+			children = (
+				5EE3DC55E808453403A4E009 /* Pods-BM_osx.debug.xcconfig */,
+				A4CB8540E4C50155D1D220D9 /* Pods-BM_osx.release.xcconfig */,
+			);
+			name = Pods;
+			sourceTree = "<group>";
+		};
+		DCC29DD114730AA9005E8FD4 = {
+			isa = PBXGroup;
+			children = (
+				DCC29E1614730AC6005E8FD4 /* Benchmarking */,
+				DCC29DE614730AA9005E8FD4 /* BenchmarkMac */,
+				DCC29DDF14730AA9005E8FD4 /* Frameworks */,
+				DCC29DDD14730AA9005E8FD4 /* Products */,
+				8B2D89AB0547F7D910983389 /* Pods */,
+			);
+			sourceTree = "<group>";
+		};
+		DCC29DDD14730AA9005E8FD4 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				DCC29DDC14730AA9005E8FD4 /* BenchmarkMac.app */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		DCC29DDF14730AA9005E8FD4 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				DCC29DE014730AA9005E8FD4 /* Cocoa.framework */,
+				DCC29DE214730AA9005E8FD4 /* Other Frameworks */,
+				3B87C32CF2EF4298BD9B0199 /* libPods-BM_osx.a */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		DCC29DE214730AA9005E8FD4 /* Other Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				DCC29DE314730AA9005E8FD4 /* AppKit.framework */,
+				DCC29DE414730AA9005E8FD4 /* CoreData.framework */,
+				DCC29DE514730AA9005E8FD4 /* Foundation.framework */,
+			);
+			name = "Other Frameworks";
+			sourceTree = "<group>";
+		};
+		DCC29DE614730AA9005E8FD4 /* BenchmarkMac */ = {
+			isa = PBXGroup;
+			children = (
+				DCC29DF214730AA9005E8FD4 /* AppDelegate.h */,
+				DCC29DF314730AA9005E8FD4 /* AppDelegate.m */,
+				DCC29DF514730AA9005E8FD4 /* MainMenu.xib */,
+				DCC29DE714730AA9005E8FD4 /* Supporting Files */,
+			);
+			path = BenchmarkMac;
+			sourceTree = "<group>";
+		};
+		DCC29DE714730AA9005E8FD4 /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				DCC29DE814730AA9005E8FD4 /* BenchmarkMac-Info.plist */,
+				DCC29DE914730AA9005E8FD4 /* InfoPlist.strings */,
+				DCC29DEC14730AA9005E8FD4 /* main.m */,
+				DCC29DEE14730AA9005E8FD4 /* BenchmarkMac-Prefix.pch */,
+				DCC29DEF14730AA9005E8FD4 /* Credits.rtf */,
+			);
+			name = "Supporting Files";
+			sourceTree = "<group>";
+		};
+		DCC29E1614730AC6005E8FD4 /* Benchmarking */ = {
+			isa = PBXGroup;
+			children = (
+				DCC29E1714730B05005E8FD4 /* BaseNSLogging.h */,
+				DCC29E1814730B05005E8FD4 /* BaseNSLogging.m */,
+				DCC29E1914730B05005E8FD4 /* DynamicLogging.h */,
+				DCC29E1A14730B05005E8FD4 /* DynamicLogging.m */,
+				DCC29E1B14730B05005E8FD4 /* PerformanceTesting.h */,
+				DCC29E1C14730B05005E8FD4 /* PerformanceTesting.m */,
+				DCC29E1D14730B05005E8FD4 /* StaticLogging.h */,
+				DCC29E1E14730B05005E8FD4 /* StaticLogging.m */,
+			);
+			name = Benchmarking;
+			path = ../../../Benchmarking;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		DCC29DDB14730AA9005E8FD4 /* BenchmarkMac */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = DCC29DFA14730AA9005E8FD4 /* Build configuration list for PBXNativeTarget "BenchmarkMac" */;
+			buildPhases = (
+				CCC3BE78F0DF486A86ECB56A /* Check Pods Manifest.lock */,
+				DCC29DD814730AA9005E8FD4 /* Sources */,
+				DCC29DD914730AA9005E8FD4 /* Frameworks */,
+				DCC29DDA14730AA9005E8FD4 /* Resources */,
+				8506515FE7184EE6BF1F427F /* Copy Pods Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = BenchmarkMac;
+			productName = BenchmarkMac;
+			productReference = DCC29DDC14730AA9005E8FD4 /* BenchmarkMac.app */;
+			productType = "com.apple.product-type.application";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		DCC29DD314730AA9005E8FD4 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 0610;
+			};
+			buildConfigurationList = DCC29DD614730AA9005E8FD4 /* Build configuration list for PBXProject "BenchmarkMac" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+			);
+			mainGroup = DCC29DD114730AA9005E8FD4;
+			productRefGroup = DCC29DDD14730AA9005E8FD4 /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				DCC29DDB14730AA9005E8FD4 /* BenchmarkMac */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		DCC29DDA14730AA9005E8FD4 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				DCC29DEB14730AA9005E8FD4 /* InfoPlist.strings in Resources */,
+				DCC29DF114730AA9005E8FD4 /* Credits.rtf in Resources */,
+				DCC29DF714730AA9005E8FD4 /* MainMenu.xib in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		8506515FE7184EE6BF1F427F /* Copy Pods Resources */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "Copy Pods Resources";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-BM_osx/Pods-BM_osx-resources.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
+		CCC3BE78F0DF486A86ECB56A /* Check Pods Manifest.lock */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "Check Pods Manifest.lock";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n    cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n    exit 1\nfi\n";
+			showEnvVarsInLog = 0;
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		DCC29DD814730AA9005E8FD4 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				DCC29DED14730AA9005E8FD4 /* main.m in Sources */,
+				DCC29DF414730AA9005E8FD4 /* AppDelegate.m in Sources */,
+				DCC29E1F14730B05005E8FD4 /* BaseNSLogging.m in Sources */,
+				DCC29E2014730B05005E8FD4 /* DynamicLogging.m in Sources */,
+				DCC29E2114730B05005E8FD4 /* PerformanceTesting.m in Sources */,
+				DCC29E2214730B05005E8FD4 /* StaticLogging.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+		DCC29DE914730AA9005E8FD4 /* InfoPlist.strings */ = {
+			isa = PBXVariantGroup;
+			children = (
+				DCC29DEA14730AA9005E8FD4 /* en */,
+			);
+			name = InfoPlist.strings;
+			sourceTree = "<group>";
+		};
+		DCC29DEF14730AA9005E8FD4 /* Credits.rtf */ = {
+			isa = PBXVariantGroup;
+			children = (
+				DCC29DF014730AA9005E8FD4 /* en */,
+			);
+			name = Credits.rtf;
+			sourceTree = "<group>";
+		};
+		DCC29DF514730AA9005E8FD4 /* MainMenu.xib */ = {
+			isa = PBXVariantGroup;
+			children = (
+				DCC29DF614730AA9005E8FD4 /* en */,
+			);
+			name = MainMenu.xib;
+			sourceTree = "<group>";
+		};
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+		DCC29DF814730AA9005E8FD4 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				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_ENABLE_OBJC_EXCEPTIONS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.7;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = macosx;
+			};
+			name = Debug;
+		};
+		DCC29DF914730AA9005E8FD4 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = YES;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.7;
+				SDKROOT = macosx;
+			};
+			name = Release;
+		};
+		DCC29DFB14730AA9005E8FD4 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 5EE3DC55E808453403A4E009 /* Pods-BM_osx.debug.xcconfig */;
+			buildSettings = {
+				COMBINE_HIDPI_IMAGES = YES;
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = "BenchmarkMac/BenchmarkMac-Prefix.pch";
+				INFOPLIST_FILE = "BenchmarkMac/BenchmarkMac-Info.plist";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				WRAPPER_EXTENSION = app;
+			};
+			name = Debug;
+		};
+		DCC29DFC14730AA9005E8FD4 /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = A4CB8540E4C50155D1D220D9 /* Pods-BM_osx.release.xcconfig */;
+			buildSettings = {
+				COMBINE_HIDPI_IMAGES = YES;
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = "BenchmarkMac/BenchmarkMac-Prefix.pch";
+				INFOPLIST_FILE = "BenchmarkMac/BenchmarkMac-Info.plist";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				WRAPPER_EXTENSION = app;
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		DCC29DD614730AA9005E8FD4 /* Build configuration list for PBXProject "BenchmarkMac" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				DCC29DF814730AA9005E8FD4 /* Debug */,
+				DCC29DF914730AA9005E8FD4 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		DCC29DFA14730AA9005E8FD4 /* Build configuration list for PBXNativeTarget "BenchmarkMac" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				DCC29DFB14730AA9005E8FD4 /* Debug */,
+				DCC29DFC14730AA9005E8FD4 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = DCC29DD314730AA9005E8FD4 /* Project object */;
+}
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac.xcodeproj/xcshareddata/._xcschemes b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac.xcodeproj/xcshareddata/._xcschemes
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac.xcodeproj/xcshareddata/._xcschemes
Binary files differ
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac.xcodeproj/xcshareddata/xcschemes/._BenchmarkMac.xcscheme b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac.xcodeproj/xcshareddata/xcschemes/._BenchmarkMac.xcscheme
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac.xcodeproj/xcshareddata/xcschemes/._BenchmarkMac.xcscheme
Binary files differ
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac.xcodeproj/xcshareddata/xcschemes/BenchmarkMac.xcscheme b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac.xcodeproj/xcshareddata/xcschemes/BenchmarkMac.xcscheme
new file mode 100644
index 0000000..4aa3410
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac.xcodeproj/xcshareddata/xcschemes/BenchmarkMac.xcscheme
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0610"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "DCC29DDB14730AA9005E8FD4"
+               BuildableName = "BenchmarkMac.app"
+               BlueprintName = "BenchmarkMac"
+               ReferencedContainer = "container:BenchmarkMac.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      buildConfiguration = "Debug">
+      <Testables>
+      </Testables>
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "DCC29DDB14730AA9005E8FD4"
+            BuildableName = "BenchmarkMac.app"
+            BlueprintName = "BenchmarkMac"
+            ReferencedContainer = "container:BenchmarkMac.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+   </TestAction>
+   <LaunchAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Debug"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      allowLocationSimulation = "YES">
+      <BuildableProductRunnable>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "DCC29DDB14730AA9005E8FD4"
+            BuildableName = "BenchmarkMac.app"
+            BlueprintName = "BenchmarkMac"
+            ReferencedContainer = "container:BenchmarkMac.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Release"
+      debugDocumentVersioning = "YES">
+      <BuildableProductRunnable>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "DCC29DDB14730AA9005E8FD4"
+            BuildableName = "BenchmarkMac.app"
+            BlueprintName = "BenchmarkMac"
+            ReferencedContainer = "container:BenchmarkMac.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/._AppDelegate.h b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/._AppDelegate.h
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/._AppDelegate.h
Binary files differ
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/._AppDelegate.m b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/._AppDelegate.m
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/._AppDelegate.m
Binary files differ
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/._BenchmarkMac-Info.plist b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/._BenchmarkMac-Info.plist
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/._BenchmarkMac-Info.plist
Binary files differ
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/._BenchmarkMac-Prefix.pch b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/._BenchmarkMac-Prefix.pch
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/._BenchmarkMac-Prefix.pch
Binary files differ
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/._en.lproj b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/._en.lproj
new file mode 100755
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/._en.lproj
Binary files differ
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/._main.m b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/._main.m
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/._main.m
Binary files differ
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/AppDelegate.h b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/AppDelegate.h
new file mode 100644
index 0000000..c295a70
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/AppDelegate.h
@@ -0,0 +1,14 @@
+//
+//  AppDelegate.h
+//  BenchmarkMac
+//
+//  Created by Robbie Hanson on 11/15/11.
+//
+
+#import <Cocoa/Cocoa.h>
+
+@interface AppDelegate : NSObject <NSApplicationDelegate>
+
+@property (assign) IBOutlet NSWindow *window;
+
+@end
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/AppDelegate.m b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/AppDelegate.m
new file mode 100644
index 0000000..42842ea
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/AppDelegate.m
@@ -0,0 +1,14 @@
+#import "AppDelegate.h"
+#import "PerformanceTesting.h"
+
+
+@implementation AppDelegate
+
+@synthesize window = _window;
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
+{
+    [PerformanceTesting startPerformanceTests];
+}
+
+@end
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/BenchmarkMac-Info.plist b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/BenchmarkMac-Info.plist
new file mode 100644
index 0000000..6220f93
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/BenchmarkMac-Info.plist
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleExecutable</key>
+	<string>${EXECUTABLE_NAME}</string>
+	<key>CFBundleIconFile</key>
+	<string></string>
+	<key>CFBundleIdentifier</key>
+	<string>com.deusty.oss.${PRODUCT_NAME:rfc1034identifier}</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+	<key>LSMinimumSystemVersion</key>
+	<string>${MACOSX_DEPLOYMENT_TARGET}</string>
+	<key>NSMainNibFile</key>
+	<string>MainMenu</string>
+	<key>NSPrincipalClass</key>
+	<string>NSApplication</string>
+</dict>
+</plist>
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/BenchmarkMac-Prefix.pch b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/BenchmarkMac-Prefix.pch
new file mode 100644
index 0000000..4cbf974
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/BenchmarkMac-Prefix.pch
@@ -0,0 +1,7 @@
+//
+// Prefix header for all source files of the 'BenchmarkMac' target in the 'BenchmarkMac' project
+//
+
+#ifdef __OBJC__
+	#import <Cocoa/Cocoa.h>
+#endif
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/en.lproj/._Credits.rtf b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/en.lproj/._Credits.rtf
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/en.lproj/._Credits.rtf
Binary files differ
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/en.lproj/._InfoPlist.strings b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/en.lproj/._InfoPlist.strings
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/en.lproj/._InfoPlist.strings
Binary files differ
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/en.lproj/._MainMenu.xib b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/en.lproj/._MainMenu.xib
new file mode 100644
index 0000000..bc71f26
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/en.lproj/._MainMenu.xib
Binary files differ
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/en.lproj/Credits.rtf b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/en.lproj/Credits.rtf
new file mode 100644
index 0000000..46576ef
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/en.lproj/Credits.rtf
@@ -0,0 +1,29 @@
+{\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\paperw9840\paperh8400
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\b\fs24 \cf0 Engineering:
+\b0 \
+	Some people\
+\
+
+\b Human Interface Design:
+\b0 \
+	Some other people\
+\
+
+\b Testing:
+\b0 \
+	Hopefully not nobody\
+\
+
+\b Documentation:
+\b0 \
+	Whoever\
+\
+
+\b With special thanks to:
+\b0 \
+	Mom\
+}
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/en.lproj/InfoPlist.strings b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/en.lproj/InfoPlist.strings
new file mode 100644
index 0000000..477b28f
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/en.lproj/InfoPlist.strings
@@ -0,0 +1,2 @@
+/* Localized versions of Info.plist keys */
+
diff --git a/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/en.lproj/MainMenu.xib b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/en.lproj/MainMenu.xib
new file mode 100644
index 0000000..18f1a3e
--- /dev/null
+++ b/cocoalumberjack/Demos/Benchmark/Desktop/BenchmarkMac/en.lproj/MainMenu.xib
@@ -0,0 +1,4582 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="8.00">
+	<data>
+		<int key="IBDocument.SystemTarget">1070</int>
+		<string key="IBDocument.SystemVersion">11A511</string>
+		<string key="IBDocument.InterfaceBuilderVersion">1920</string>
+		<string key="IBDocument.AppKitVersion">1138</string>
+		<string key="IBDocument.HIToolboxVersion">566.00</string>
+		<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
+			<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
+			<string key="NS.object.0">1920</string>
+		</object>
+		<array key="IBDocument.IntegratedClassDependencies">
+			<string>NSWindowTemplate</string>
+			<string>NSView</string>
+			<string>NSMenu</string>
+			<string>NSMenuItem</string>
+			<string>NSCustomObject</string>
+		</array>
+		<array key="IBDocument.PluginDependencies">
+			<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+		</array>
+		<object class="NSMutableDictionary" key="IBDocument.Metadata">
+			<string key="NS.key.0">PluginDependencyRecalculationVersion</string>
+			<integer value="1" key="NS.object.0"/>
+		</object>
+		<array class="NSMutableArray" key="IBDocument.RootObjects" id="1048">
+			<object class="NSCustomObject" id="1021">
+				<string key="NSClassName">NSApplication</string>
+			</object>
+			<object class="NSCustomObject" id="1014">
+				<string key="NSClassName">FirstResponder</string>
+			</object>
+			<object class="NSCustomObject" id="1050">
+				<string key="NSClassName">NSApplication</string>
+			</object>
+			<object class="NSMenu" id="649796088">
+				<string key="NSTitle">AMainMenu</string>
+				<array class="NSMutableArray" key="NSMenuItems">
+					<object class="NSMenuItem" id="694149608">
+						<reference key="NSMenu" ref="649796088"/>
+						<string key="NSTitle">BenchmarkMac</string>
+						<string key="NSKeyEquiv"/>
+						<int key="NSKeyEquivModMask">1048576</int>
+						<int key="NSMnemonicLoc">2147483647</int>
+						<object class="NSCustomResource" key="NSOnImage" id="35465992">
+							<string key="NSClassName">NSImage</string>
+							<string key="NSResourceName">NSMenuCheckmark</string>
+						</object>
+						<object class="NSCustomResource" key="NSMixedImage" id="502551668">
+							<string key="NSClassName">NSImage</string>
+							<string key="NSResourceName">NSMenuMixedState</string>
+						</object>
+						<string key="NSAction">submenuAction:</string>
+						<object class="NSMenu" key="NSSubmenu" id="110575045">
+							<string key="NSTitle">BenchmarkMac</string>
+							<array class="NSMutableArray" key="NSMenuItems">
+								<object class="NSMenuItem" id="238522557">
+									<reference key="NSMenu" ref="110575045"/>
+									<string key="NSTitle">About BenchmarkMac</string>
+									<string key="NSKeyEquiv"/>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="304266470">
+									<reference key="NSMenu" ref="110575045"/>
+									<bool key="NSIsDisabled">YES</bool>
+									<bool key="NSIsSeparator">YES</bool>
+									<string key="NSTitle"/>
+									<string key="NSKeyEquiv"/>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="609285721">
+									<reference key="NSMenu" ref="110575045"/>
+									<string key="NSTitle">Preferences…</string>
+									<string key="NSKeyEquiv">,</string>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="481834944">
+									<reference key="NSMenu" ref="110575045"/>
+									<bool key="NSIsDisabled">YES</bool>
+									<bool key="NSIsSeparator">YES</bool>
+									<string key="NSTitle"/>
+									<string key="NSKeyEquiv"/>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="1046388886">
+									<reference key="NSMenu" ref="110575045"/>
+									<string key="NSTitle">Services</string>
+									<string key="NSKeyEquiv"/>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+									<string key="NSAction">submenuAction:</string>
+									<object class="NSMenu" key="NSSubmenu" id="752062318">
+										<string key="NSTitle">Services</string>
+										<array class="NSMutableArray" key="NSMenuItems"/>
+										<string key="NSName">_NSServicesMenu</string>
+									</object>
+								</object>
+								<object class="NSMenuItem" id="646227648">
+									<reference key="NSMenu" ref="110575045"/>
+									<bool key="NSIsDisabled">YES</bool>
+									<bool key="NSIsSeparator">YES</bool>
+									<string key="NSTitle"/>
+									<string key="NSKeyEquiv"/>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="755159360">
+									<reference key="NSMenu" ref="110575045"/>
+									<string key="NSTitle">Hide BenchmarkMac</string>
+									<string key="NSKeyEquiv">h</string>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="342932134">
+									<reference key="NSMenu" ref="110575045"/>
+									<string key="NSTitle">Hide Others</string>
+									<string key="NSKeyEquiv">h</string>
+									<int key="NSKeyEquivModMask">1572864</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="908899353">
+									<reference key="NSMenu" ref="110575045"/>
+									<string key="NSTitle">Show All</string>
+									<string key="NSKeyEquiv"/>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="1056857174">
+									<reference key="NSMenu" ref="110575045"/>
+									<bool key="NSIsDisabled">YES</bool>
+									<bool key="NSIsSeparator">YES</bool>
+									<string key="NSTitle"/>
+									<string key="NSKeyEquiv"/>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="632727374">
+									<reference key="NSMenu" ref="110575045"/>
+									<string key="NSTitle">Quit BenchmarkMac</string>
+									<string key="NSKeyEquiv">q</string>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+							</array>
+							<string key="NSName">_NSAppleMenu</string>
+						</object>
+					</object>
+					<object class="NSMenuItem" id="379814623">
+						<reference key="NSMenu" ref="649796088"/>
+						<string key="NSTitle">File</string>
+						<string key="NSKeyEquiv"/>
+						<int key="NSKeyEquivModMask">1048576</int>
+						<int key="NSMnemonicLoc">2147483647</int>
+						<reference key="NSOnImage" ref="35465992"/>
+						<reference key="NSMixedImage" ref="502551668"/>
+						<string key="NSAction">submenuAction:</string>
+						<object class="NSMenu" key="NSSubmenu" id="720053764">
+							<string key="NSTitle">File</string>
+							<array class="NSMutableArray" key="NSMenuItems">
+								<object class="NSMenuItem" id="705341025">
+									<reference key="NSMenu" ref="720053764"/>
+									<string key="NSTitle">New</string>
+									<string key="NSKeyEquiv">n</string>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="722745758">
+									<reference key="NSMenu" ref="720053764"/>
+									<string key="NSTitle">Open…</string>
+									<string key="NSKeyEquiv">o</string>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="1025936716">
+									<reference key="NSMenu" ref="720053764"/>
+									<string key="NSTitle">Open Recent</string>
+									<string key="NSKeyEquiv"/>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+									<string key="NSAction">submenuAction:</string>
+									<object class="NSMenu" key="NSSubmenu" id="1065607017">
+										<string key="NSTitle">Open Recent</string>
+										<array class="NSMutableArray" key="NSMenuItems">
+											<object class="NSMenuItem" id="759406840">
+												<reference key="NSMenu" ref="1065607017"/>
+												<string key="NSTitle">Clear Menu</string>
+												<string key="NSKeyEquiv"/>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+										</array>
+										<string key="NSName">_NSRecentDocumentsMenu</string>
+									</object>
+								</object>
+								<object class="NSMenuItem" id="425164168">
+									<reference key="NSMenu" ref="720053764"/>
+									<bool key="NSIsDisabled">YES</bool>
+									<bool key="NSIsSeparator">YES</bool>
+									<string key="NSTitle"/>
+									<string key="NSKeyEquiv"/>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="776162233">
+									<reference key="NSMenu" ref="720053764"/>
+									<string key="NSTitle">Close</string>
+									<string key="NSKeyEquiv">w</string>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="1023925487">
+									<reference key="NSMenu" ref="720053764"/>
+									<string key="NSTitle">Save…</string>
+									<string key="NSKeyEquiv">s</string>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="579971712">
+									<reference key="NSMenu" ref="720053764"/>
+									<string key="NSTitle">Revert to Saved</string>
+									<string key="NSKeyEquiv"/>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="1010469920">
+									<reference key="NSMenu" ref="720053764"/>
+									<bool key="NSIsDisabled">YES</bool>
+									<bool key="NSIsSeparator">YES</bool>
+									<string key="NSTitle"/>
+									<string key="NSKeyEquiv"/>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="294629803">
+									<reference key="NSMenu" ref="720053764"/>
+									<string key="NSTitle">Page Setup...</string>
+									<string key="NSKeyEquiv">P</string>
+									<int key="NSKeyEquivModMask">1179648</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+									<string key="NSToolTip"/>
+								</object>
+								<object class="NSMenuItem" id="49223823">
+									<reference key="NSMenu" ref="720053764"/>
+									<string key="NSTitle">Print…</string>
+									<string key="NSKeyEquiv">p</string>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+							</array>
+						</object>
+					</object>
+					<object class="NSMenuItem" id="952259628">
+						<reference key="NSMenu" ref="649796088"/>
+						<string key="NSTitle">Edit</string>
+						<string key="NSKeyEquiv"/>
+						<int key="NSKeyEquivModMask">1048576</int>
+						<int key="NSMnemonicLoc">2147483647</int>
+						<reference key="NSOnImage" ref="35465992"/>
+						<reference key="NSMixedImage" ref="502551668"/>
+						<string key="NSAction">submenuAction:</string>
+						<object class="NSMenu" key="NSSubmenu" id="789758025">
+							<string key="NSTitle">Edit</string>
+							<array class="NSMutableArray" key="NSMenuItems">
+								<object class="NSMenuItem" id="1058277027">
+									<reference key="NSMenu" ref="789758025"/>
+									<string key="NSTitle">Undo</string>
+									<string key="NSKeyEquiv">z</string>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="790794224">
+									<reference key="NSMenu" ref="789758025"/>
+									<string key="NSTitle">Redo</string>
+									<string key="NSKeyEquiv">Z</string>
+									<int key="NSKeyEquivModMask">1179648</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="1040322652">
+									<reference key="NSMenu" ref="789758025"/>
+									<bool key="NSIsDisabled">YES</bool>
+									<bool key="NSIsSeparator">YES</bool>
+									<string key="NSTitle"/>
+									<string key="NSKeyEquiv"/>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="296257095">
+									<reference key="NSMenu" ref="789758025"/>
+									<string key="NSTitle">Cut</string>
+									<string key="NSKeyEquiv">x</string>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="860595796">
+									<reference key="NSMenu" ref="789758025"/>
+									<string key="NSTitle">Copy</string>
+									<string key="NSKeyEquiv">c</string>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="29853731">
+									<reference key="NSMenu" ref="789758025"/>
+									<string key="NSTitle">Paste</string>
+									<string key="NSKeyEquiv">v</string>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="82994268">
+									<reference key="NSMenu" ref="789758025"/>
+									<string key="NSTitle">Paste and Match Style</string>
+									<string key="NSKeyEquiv">V</string>
+									<int key="NSKeyEquivModMask">1572864</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="437104165">
+									<reference key="NSMenu" ref="789758025"/>
+									<string key="NSTitle">Delete</string>
+									<string key="NSKeyEquiv"/>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="583158037">
+									<reference key="NSMenu" ref="789758025"/>
+									<string key="NSTitle">Select All</string>
+									<string key="NSKeyEquiv">a</string>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="212016141">
+									<reference key="NSMenu" ref="789758025"/>
+									<bool key="NSIsDisabled">YES</bool>
+									<bool key="NSIsSeparator">YES</bool>
+									<string key="NSTitle"/>
+									<string key="NSKeyEquiv"/>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="892235320">
+									<reference key="NSMenu" ref="789758025"/>
+									<string key="NSTitle">Find</string>
+									<string key="NSKeyEquiv"/>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+									<string key="NSAction">submenuAction:</string>
+									<object class="NSMenu" key="NSSubmenu" id="963351320">
+										<string key="NSTitle">Find</string>
+										<array class="NSMutableArray" key="NSMenuItems">
+											<object class="NSMenuItem" id="447796847">
+												<reference key="NSMenu" ref="963351320"/>
+												<string key="NSTitle">Find…</string>
+												<string key="NSKeyEquiv">f</string>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+												<int key="NSTag">1</int>
+											</object>
+											<object class="NSMenuItem" id="738670835">
+												<reference key="NSMenu" ref="963351320"/>
+												<string key="NSTitle">Find and Replace…</string>
+												<string key="NSKeyEquiv">f</string>
+												<int key="NSKeyEquivModMask">1572864</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+												<int key="NSTag">12</int>
+											</object>
+											<object class="NSMenuItem" id="326711663">
+												<reference key="NSMenu" ref="963351320"/>
+												<string key="NSTitle">Find Next</string>
+												<string key="NSKeyEquiv">g</string>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+												<int key="NSTag">2</int>
+											</object>
+											<object class="NSMenuItem" id="270902937">
+												<reference key="NSMenu" ref="963351320"/>
+												<string key="NSTitle">Find Previous</string>
+												<string key="NSKeyEquiv">G</string>
+												<int key="NSKeyEquivModMask">1179648</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+												<int key="NSTag">3</int>
+											</object>
+											<object class="NSMenuItem" id="159080638">
+												<reference key="NSMenu" ref="963351320"/>
+												<string key="NSTitle">Use Selection for Find</string>
+												<string key="NSKeyEquiv">e</string>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+												<int key="NSTag">7</int>
+											</object>
+											<object class="NSMenuItem" id="88285865">
+												<reference key="NSMenu" ref="963351320"/>
+												<string key="NSTitle">Jump to Selection</string>
+												<string key="NSKeyEquiv">j</string>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+										</array>
+									</object>
+								</object>
+								<object class="NSMenuItem" id="972420730">
+									<reference key="NSMenu" ref="789758025"/>
+									<string key="NSTitle">Spelling and Grammar</string>
+									<string key="NSKeyEquiv"/>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+									<string key="NSAction">submenuAction:</string>
+									<object class="NSMenu" key="NSSubmenu" id="769623530">
+										<string key="NSTitle">Spelling and Grammar</string>
+										<array class="NSMutableArray" key="NSMenuItems">
+											<object class="NSMenuItem" id="679648819">
+												<reference key="NSMenu" ref="769623530"/>
+												<string key="NSTitle">Show Spelling and Grammar</string>
+												<string key="NSKeyEquiv">:</string>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="96193923">
+												<reference key="NSMenu" ref="769623530"/>
+												<string key="NSTitle">Check Document Now</string>
+												<string key="NSKeyEquiv">;</string>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="859480356">
+												<reference key="NSMenu" ref="769623530"/>
+												<bool key="NSIsDisabled">YES</bool>
+												<bool key="NSIsSeparator">YES</bool>
+												<string key="NSTitle"/>
+												<string key="NSKeyEquiv"/>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="948374510">
+												<reference key="NSMenu" ref="769623530"/>
+												<string key="NSTitle">Check Spelling While Typing</string>
+												<string key="NSKeyEquiv"/>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="967646866">
+												<reference key="NSMenu" ref="769623530"/>
+												<string key="NSTitle">Check Grammar With Spelling</string>
+												<string key="NSKeyEquiv"/>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="795346622">
+												<reference key="NSMenu" ref="769623530"/>
+												<string key="NSTitle">Correct Spelling Automatically</string>
+												<string key="NSKeyEquiv"/>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+										</array>
+									</object>
+								</object>
+								<object class="NSMenuItem" id="507821607">
+									<reference key="NSMenu" ref="789758025"/>
+									<string key="NSTitle">Substitutions</string>
+									<string key="NSKeyEquiv"/>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+									<string key="NSAction">submenuAction:</string>
+									<object class="NSMenu" key="NSSubmenu" id="698887838">
+										<string key="NSTitle">Substitutions</string>
+										<array class="NSMutableArray" key="NSMenuItems">
+											<object class="NSMenuItem" id="65139061">
+												<reference key="NSMenu" ref="698887838"/>
+												<string key="NSTitle">Show Substitutions</string>
+												<string key="NSKeyEquiv"/>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="19036812">
+												<reference key="NSMenu" ref="698887838"/>
+												<bool key="NSIsDisabled">YES</bool>
+												<bool key="NSIsSeparator">YES</bool>
+												<string key="NSTitle"/>
+												<string key="NSKeyEquiv"/>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="605118523">
+												<reference key="NSMenu" ref="698887838"/>
+												<string key="NSTitle">Smart Copy/Paste</string>
+												<string key="NSKeyEquiv">f</string>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+												<int key="NSTag">1</int>
+											</object>
+											<object class="NSMenuItem" id="197661976">
+												<reference key="NSMenu" ref="698887838"/>
+												<string key="NSTitle">Smart Quotes</string>
+												<string key="NSKeyEquiv">g</string>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+												<int key="NSTag">2</int>
+											</object>
+											<object class="NSMenuItem" id="672708820">
+												<reference key="NSMenu" ref="698887838"/>
+												<string key="NSTitle">Smart Dashes</string>
+												<string key="NSKeyEquiv"/>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="708854459">
+												<reference key="NSMenu" ref="698887838"/>
+												<string key="NSTitle">Smart Links</string>
+												<string key="NSKeyEquiv">G</string>
+												<int key="NSKeyEquivModMask">1179648</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+												<int key="NSTag">3</int>
+											</object>
+											<object class="NSMenuItem" id="537092702">
+												<reference key="NSMenu" ref="698887838"/>
+												<string key="NSTitle">Text Replacement</string>
+												<string key="NSKeyEquiv"/>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+										</array>
+									</object>
+								</object>
+								<object class="NSMenuItem" id="288088188">
+									<reference key="NSMenu" ref="789758025"/>
+									<string key="NSTitle">Transformations</string>
+									<string key="NSKeyEquiv"/>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+									<string key="NSAction">submenuAction:</string>
+									<object class="NSMenu" key="NSSubmenu" id="579392910">
+										<string key="NSTitle">Transformations</string>
+										<array class="NSMutableArray" key="NSMenuItems">
+											<object class="NSMenuItem" id="1060694897">
+												<reference key="NSMenu" ref="579392910"/>
+												<string key="NSTitle">Make Upper Case</string>
+												<string key="NSKeyEquiv"/>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="879586729">
+												<reference key="NSMenu" ref="579392910"/>
+												<string key="NSTitle">Make Lower Case</string>
+												<string key="NSKeyEquiv"/>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="56570060">
+												<reference key="NSMenu" ref="579392910"/>
+												<string key="NSTitle">Capitalize</string>
+												<string key="NSKeyEquiv"/>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+										</array>
+									</object>
+								</object>
+								<object class="NSMenuItem" id="676164635">
+									<reference key="NSMenu" ref="789758025"/>
+									<string key="NSTitle">Speech</string>
+									<string key="NSKeyEquiv"/>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+									<string key="NSAction">submenuAction:</string>
+									<object class="NSMenu" key="NSSubmenu" id="785027613">
+										<string key="NSTitle">Speech</string>
+										<array class="NSMutableArray" key="NSMenuItems">
+											<object class="NSMenuItem" id="731782645">
+												<reference key="NSMenu" ref="785027613"/>
+												<string key="NSTitle">Start Speaking</string>
+												<string key="NSKeyEquiv"/>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="680220178">
+												<reference key="NSMenu" ref="785027613"/>
+												<string key="NSTitle">Stop Speaking</string>
+												<string key="NSKeyEquiv"/>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+										</array>
+									</object>
+								</object>
+							</array>
+						</object>
+					</object>
+					<object class="NSMenuItem" id="302598603">
+						<reference key="NSMenu" ref="649796088"/>
+						<string key="NSTitle">Format</string>
+						<string key="NSKeyEquiv"/>
+						<int key="NSMnemonicLoc">2147483647</int>
+						<reference key="NSOnImage" ref="35465992"/>
+						<reference key="NSMixedImage" ref="502551668"/>
+						<string key="NSAction">submenuAction:</string>
+						<object class="NSMenu" key="NSSubmenu" id="941447902">
+							<string key="NSTitle">Format</string>
+							<array class="NSMutableArray" key="NSMenuItems">
+								<object class="NSMenuItem" id="792887677">
+									<reference key="NSMenu" ref="941447902"/>
+									<string key="NSTitle">Font</string>
+									<string key="NSKeyEquiv"/>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+									<string key="NSAction">submenuAction:</string>
+									<object class="NSMenu" key="NSSubmenu" id="786677654">
+										<string key="NSTitle">Font</string>
+										<array class="NSMutableArray" key="NSMenuItems">
+											<object class="NSMenuItem" id="159677712">
+												<reference key="NSMenu" ref="786677654"/>
+												<string key="NSTitle">Show Fonts</string>
+												<string key="NSKeyEquiv">t</string>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="305399458">
+												<reference key="NSMenu" ref="786677654"/>
+												<string key="NSTitle">Bold</string>
+												<string key="NSKeyEquiv">b</string>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+												<int key="NSTag">2</int>
+											</object>
+											<object class="NSMenuItem" id="814362025">
+												<reference key="NSMenu" ref="786677654"/>
+												<string key="NSTitle">Italic</string>
+												<string key="NSKeyEquiv">i</string>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+												<int key="NSTag">1</int>
+											</object>
+											<object class="NSMenuItem" id="330926929">
+												<reference key="NSMenu" ref="786677654"/>
+												<string key="NSTitle">Underline</string>
+												<string key="NSKeyEquiv">u</string>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="533507878">
+												<reference key="NSMenu" ref="786677654"/>
+												<bool key="NSIsDisabled">YES</bool>
+												<bool key="NSIsSeparator">YES</bool>
+												<string key="NSTitle"/>
+												<string key="NSKeyEquiv"/>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="158063935">
+												<reference key="NSMenu" ref="786677654"/>
+												<string key="NSTitle">Bigger</string>
+												<string key="NSKeyEquiv">+</string>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+												<int key="NSTag">3</int>
+											</object>
+											<object class="NSMenuItem" id="885547335">
+												<reference key="NSMenu" ref="786677654"/>
+												<string key="NSTitle">Smaller</string>
+												<string key="NSKeyEquiv">-</string>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+												<int key="NSTag">4</int>
+											</object>
+											<object class="NSMenuItem" id="901062459">
+												<reference key="NSMenu" ref="786677654"/>
+												<bool key="NSIsDisabled">YES</bool>
+												<bool key="NSIsSeparator">YES</bool>
+												<string key="NSTitle"/>
+												<string key="NSKeyEquiv"/>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="767671776">
+												<reference key="NSMenu" ref="786677654"/>
+												<string key="NSTitle">Kern</string>
+												<string key="NSKeyEquiv"/>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+												<string key="NSAction">submenuAction:</string>
+												<object class="NSMenu" key="NSSubmenu" id="175441468">
+													<string key="NSTitle">Kern</string>
+													<array class="NSMutableArray" key="NSMenuItems">
+														<object class="NSMenuItem" id="252969304">
+															<reference key="NSMenu" ref="175441468"/>
+															<string key="NSTitle">Use Default</string>
+															<string key="NSKeyEquiv"/>
+															<int key="NSMnemonicLoc">2147483647</int>
+															<reference key="NSOnImage" ref="35465992"/>
+															<reference key="NSMixedImage" ref="502551668"/>
+														</object>
+														<object class="NSMenuItem" id="766922938">
+															<reference key="NSMenu" ref="175441468"/>
+															<string key="NSTitle">Use None</string>
+															<string key="NSKeyEquiv"/>
+															<int key="NSMnemonicLoc">2147483647</int>
+															<reference key="NSOnImage" ref="35465992"/>
+															<reference key="NSMixedImage" ref="502551668"/>
+														</object>
+														<object class="NSMenuItem" id="677519740">
+															<reference key="NSMenu" ref="175441468"/>
+															<string key="NSTitle">Tighten</string>
+															<string key="NSKeyEquiv"/>
+															<int key="NSMnemonicLoc">2147483647</int>
+															<reference key="NSOnImage" ref="35465992"/>
+															<reference key="NSMixedImage" ref="502551668"/>
+														</object>
+														<object class="NSMenuItem" id="238351151">
+															<reference key="NSMenu" ref="175441468"/>
+															<string key="NSTitle">Loosen</string>
+															<string key="NSKeyEquiv"/>
+															<int key="NSMnemonicLoc">2147483647</int>
+															<reference key="NSOnImage" ref="35465992"/>
+															<reference key="NSMixedImage" ref="502551668"/>
+														</object>
+													</array>
+												</object>
+											</object>
+											<object class="NSMenuItem" id="691570813">
+												<reference key="NSMenu" ref="786677654"/>
+												<string key="NSTitle">Ligature</string>
+												<string key="NSKeyEquiv"/>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+												<string key="NSAction">submenuAction:</string>
+												<object class="NSMenu" key="NSSubmenu" id="1058217995">
+													<string key="NSTitle">Ligature</string>
+													<array class="NSMutableArray" key="NSMenuItems">
+														<object class="NSMenuItem" id="706297211">
+															<reference key="NSMenu" ref="1058217995"/>
+															<string key="NSTitle">Use Default</string>
+															<string key="NSKeyEquiv"/>
+															<int key="NSMnemonicLoc">2147483647</int>
+															<reference key="NSOnImage" ref="35465992"/>
+															<reference key="NSMixedImage" ref="502551668"/>
+														</object>
+														<object class="NSMenuItem" id="568384683">
+															<reference key="NSMenu" ref="1058217995"/>
+															<string key="NSTitle">Use None</string>
+															<string key="NSKeyEquiv"/>
+															<int key="NSMnemonicLoc">2147483647</int>
+															<reference key="NSOnImage" ref="35465992"/>
+															<reference key="NSMixedImage" ref="502551668"/>
+														</object>
+														<object class="NSMenuItem" id="663508465">
+															<reference key="NSMenu" ref="1058217995"/>
+															<string key="NSTitle">Use All</string>
+															<string key="NSKeyEquiv"/>
+															<int key="NSMnemonicLoc">2147483647</int>
+															<reference key="NSOnImage" ref="35465992"/>
+															<reference key="NSMixedImage" ref="502551668"/>
+														</object>
+													</array>
+												</object>
+											</object>
+											<object class="NSMenuItem" id="769124883">
+												<reference key="NSMenu" ref="786677654"/>
+												<string key="NSTitle">Baseline</string>
+												<string key="NSKeyEquiv"/>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+												<string key="NSAction">submenuAction:</string>
+												<object class="NSMenu" key="NSSubmenu" id="18263474">
+													<string key="NSTitle">Baseline</string>
+													<array class="NSMutableArray" key="NSMenuItems">
+														<object class="NSMenuItem" id="257962622">
+															<reference key="NSMenu" ref="18263474"/>
+															<string key="NSTitle">Use Default</string>
+															<string key="NSKeyEquiv"/>
+															<int key="NSMnemonicLoc">2147483647</int>
+															<reference key="NSOnImage" ref="35465992"/>
+															<reference key="NSMixedImage" ref="502551668"/>
+														</object>
+														<object class="NSMenuItem" id="644725453">
+															<reference key="NSMenu" ref="18263474"/>
+															<string key="NSTitle">Superscript</string>
+															<string key="NSKeyEquiv"/>
+															<int key="NSMnemonicLoc">2147483647</int>
+															<reference key="NSOnImage" ref="35465992"/>
+															<reference key="NSMixedImage" ref="502551668"/>
+														</object>
+														<object class="NSMenuItem" id="1037576581">
+															<reference key="NSMenu" ref="18263474"/>
+															<string key="NSTitle">Subscript</string>
+															<string key="NSKeyEquiv"/>
+															<int key="NSMnemonicLoc">2147483647</int>
+															<reference key="NSOnImage" ref="35465992"/>
+															<reference key="NSMixedImage" ref="502551668"/>
+														</object>
+														<object class="NSMenuItem" id="941806246">
+															<reference key="NSMenu" ref="18263474"/>
+															<string key="NSTitle">Raise</string>
+															<string key="NSKeyEquiv"/>
+															<int key="NSMnemonicLoc">2147483647</int>
+															<reference key="NSOnImage" ref="35465992"/>
+															<reference key="NSMixedImage" ref="502551668"/>
+														</object>
+														<object class="NSMenuItem" id="1045724900">
+															<reference key="NSMenu" ref="18263474"/>
+															<string key="NSTitle">Lower</string>
+															<string key="NSKeyEquiv"/>
+															<int key="NSMnemonicLoc">2147483647</int>
+															<reference key="NSOnImage" ref="35465992"/>
+															<reference key="NSMixedImage" ref="502551668"/>
+														</object>
+													</array>
+												</object>
+											</object>
+											<object class="NSMenuItem" id="739652853">
+												<reference key="NSMenu" ref="786677654"/>
+												<bool key="NSIsDisabled">YES</bool>
+												<bool key="NSIsSeparator">YES</bool>
+												<string key="NSTitle"/>
+												<string key="NSKeyEquiv"/>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="1012600125">
+												<reference key="NSMenu" ref="786677654"/>
+												<string key="NSTitle">Show Colors</string>
+												<string key="NSKeyEquiv">C</string>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="214559597">
+												<reference key="NSMenu" ref="786677654"/>
+												<bool key="NSIsDisabled">YES</bool>
+												<bool key="NSIsSeparator">YES</bool>
+												<string key="NSTitle"/>
+												<string key="NSKeyEquiv"/>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="596732606">
+												<reference key="NSMenu" ref="786677654"/>
+												<string key="NSTitle">Copy Style</string>
+												<string key="NSKeyEquiv">c</string>
+												<int key="NSKeyEquivModMask">1572864</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="393423671">
+												<reference key="NSMenu" ref="786677654"/>
+												<string key="NSTitle">Paste Style</string>
+												<string key="NSKeyEquiv">v</string>
+												<int key="NSKeyEquivModMask">1572864</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+										</array>
+										<string key="NSName">_NSFontMenu</string>
+									</object>
+								</object>
+								<object class="NSMenuItem" id="215659978">
+									<reference key="NSMenu" ref="941447902"/>
+									<string key="NSTitle">Text</string>
+									<string key="NSKeyEquiv"/>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+									<string key="NSAction">submenuAction:</string>
+									<object class="NSMenu" key="NSSubmenu" id="446991534">
+										<string key="NSTitle">Text</string>
+										<array class="NSMutableArray" key="NSMenuItems">
+											<object class="NSMenuItem" id="875092757">
+												<reference key="NSMenu" ref="446991534"/>
+												<string key="NSTitle">Align Left</string>
+												<string key="NSKeyEquiv">{</string>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="630155264">
+												<reference key="NSMenu" ref="446991534"/>
+												<string key="NSTitle">Center</string>
+												<string key="NSKeyEquiv">|</string>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="945678886">
+												<reference key="NSMenu" ref="446991534"/>
+												<string key="NSTitle">Justify</string>
+												<string key="NSKeyEquiv"/>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="512868991">
+												<reference key="NSMenu" ref="446991534"/>
+												<string key="NSTitle">Align Right</string>
+												<string key="NSKeyEquiv">}</string>
+												<int key="NSKeyEquivModMask">1048576</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="163117631">
+												<reference key="NSMenu" ref="446991534"/>
+												<bool key="NSIsDisabled">YES</bool>
+												<bool key="NSIsSeparator">YES</bool>
+												<string key="NSTitle"/>
+												<string key="NSKeyEquiv"/>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="31516759">
+												<reference key="NSMenu" ref="446991534"/>
+												<string key="NSTitle">Writing Direction</string>
+												<string key="NSKeyEquiv"/>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+												<string key="NSAction">submenuAction:</string>
+												<object class="NSMenu" key="NSSubmenu" id="956096989">
+													<string key="NSTitle">Writing Direction</string>
+													<array class="NSMutableArray" key="NSMenuItems">
+														<object class="NSMenuItem" id="257099033">
+															<reference key="NSMenu" ref="956096989"/>
+															<bool key="NSIsDisabled">YES</bool>
+															<string key="NSTitle">Paragraph</string>
+															<string key="NSKeyEquiv"/>
+															<int key="NSMnemonicLoc">2147483647</int>
+															<reference key="NSOnImage" ref="35465992"/>
+															<reference key="NSMixedImage" ref="502551668"/>
+														</object>
+														<object class="NSMenuItem" id="551969625">
+															<reference key="NSMenu" ref="956096989"/>
+															<string type="base64-UTF8" key="NSTitle">CURlZmF1bHQ</string>
+															<string key="NSKeyEquiv"/>
+															<int key="NSMnemonicLoc">2147483647</int>
+															<reference key="NSOnImage" ref="35465992"/>
+															<reference key="NSMixedImage" ref="502551668"/>
+														</object>
+														<object class="NSMenuItem" id="249532473">
+															<reference key="NSMenu" ref="956096989"/>
+															<string type="base64-UTF8" key="NSTitle">CUxlZnQgdG8gUmlnaHQ</string>
+															<string key="NSKeyEquiv"/>
+															<int key="NSMnemonicLoc">2147483647</int>
+															<reference key="NSOnImage" ref="35465992"/>
+															<reference key="NSMixedImage" ref="502551668"/>
+														</object>
+														<object class="NSMenuItem" id="607364498">
+															<reference key="NSMenu" ref="956096989"/>
+															<string type="base64-UTF8" key="NSTitle">CVJpZ2h0IHRvIExlZnQ</string>
+															<string key="NSKeyEquiv"/>
+															<int key="NSMnemonicLoc">2147483647</int>
+															<reference key="NSOnImage" ref="35465992"/>
+															<reference key="NSMixedImage" ref="502551668"/>
+														</object>
+														<object class="NSMenuItem" id="508151438">
+															<reference key="NSMenu" ref="956096989"/>
+															<bool key="NSIsDisabled">YES</bool>
+															<bool key="NSIsSeparator">YES</bool>
+															<string key="NSTitle"/>
+															<string key="NSKeyEquiv"/>
+															<int key="NSMnemonicLoc">2147483647</int>
+															<reference key="NSOnImage" ref="35465992"/>
+															<reference key="NSMixedImage" ref="502551668"/>
+														</object>
+														<object class="NSMenuItem" id="981751889">
+															<reference key="NSMenu" ref="956096989"/>
+															<bool key="NSIsDisabled">YES</bool>
+															<string key="NSTitle">Selection</string>
+															<string key="NSKeyEquiv"/>
+															<int key="NSMnemonicLoc">2147483647</int>
+															<reference key="NSOnImage" ref="35465992"/>
+															<reference key="NSMixedImage" ref="502551668"/>
+														</object>
+														<object class="NSMenuItem" id="380031999">
+															<reference key="NSMenu" ref="956096989"/>
+															<string type="base64-UTF8" key="NSTitle">CURlZmF1bHQ</string>
+															<string key="NSKeyEquiv"/>
+															<int key="NSMnemonicLoc">2147483647</int>
+															<reference key="NSOnImage" ref="35465992"/>
+															<reference key="NSMixedImage" ref="502551668"/>
+														</object>
+														<object class="NSMenuItem" id="825984362">
+															<reference key="NSMenu" ref="956096989"/>
+															<string type="base64-UTF8" key="NSTitle">CUxlZnQgdG8gUmlnaHQ</string>
+															<string key="NSKeyEquiv"/>
+															<int key="NSMnemonicLoc">2147483647</int>
+															<reference key="NSOnImage" ref="35465992"/>
+															<reference key="NSMixedImage" ref="502551668"/>
+														</object>
+														<object class="NSMenuItem" id="560145579">
+															<reference key="NSMenu" ref="956096989"/>
+															<string type="base64-UTF8" key="NSTitle">CVJpZ2h0IHRvIExlZnQ</string>
+															<string key="NSKeyEquiv"/>
+															<int key="NSMnemonicLoc">2147483647</int>
+															<reference key="NSOnImage" ref="35465992"/>
+															<reference key="NSMixedImage" ref="502551668"/>
+														</object>
+													</array>
+												</object>
+											</object>
+											<object class="NSMenuItem" id="908105787">
+												<reference key="NSMenu" ref="446991534"/>
+												<bool key="NSIsDisabled">YES</bool>
+												<bool key="NSIsSeparator">YES</bool>
+												<string key="NSTitle"/>
+												<string key="NSKeyEquiv"/>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="644046920">
+												<reference key="NSMenu" ref="446991534"/>
+												<string key="NSTitle">Show Ruler</string>
+												<string key="NSKeyEquiv"/>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="231811626">
+												<reference key="NSMenu" ref="446991534"/>
+												<string key="NSTitle">Copy Ruler</string>
+												<string key="NSKeyEquiv">c</string>
+												<int key="NSKeyEquivModMask">1310720</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+											<object class="NSMenuItem" id="883618387">
+												<reference key="NSMenu" ref="446991534"/>
+												<string key="NSTitle">Paste Ruler</string>
+												<string key="NSKeyEquiv">v</string>
+												<int key="NSKeyEquivModMask">1310720</int>
+												<int key="NSMnemonicLoc">2147483647</int>
+												<reference key="NSOnImage" ref="35465992"/>
+												<reference key="NSMixedImage" ref="502551668"/>
+											</object>
+										</array>
+									</object>
+								</object>
+							</array>
+						</object>
+					</object>
+					<object class="NSMenuItem" id="586577488">
+						<reference key="NSMenu" ref="649796088"/>
+						<string key="NSTitle">View</string>
+						<string key="NSKeyEquiv"/>
+						<int key="NSKeyEquivModMask">1048576</int>
+						<int key="NSMnemonicLoc">2147483647</int>
+						<reference key="NSOnImage" ref="35465992"/>
+						<reference key="NSMixedImage" ref="502551668"/>
+						<string key="NSAction">submenuAction:</string>
+						<object class="NSMenu" key="NSSubmenu" id="466310130">
+							<string key="NSTitle">View</string>
+							<array class="NSMutableArray" key="NSMenuItems">
+								<object class="NSMenuItem" id="102151532">
+									<reference key="NSMenu" ref="466310130"/>
+									<string key="NSTitle">Show Toolbar</string>
+									<string key="NSKeyEquiv">t</string>
+									<int key="NSKeyEquivModMask">1572864</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="237841660">
+									<reference key="NSMenu" ref="466310130"/>
+									<string key="NSTitle">Customize Toolbar…</string>
+									<string key="NSKeyEquiv"/>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+							</array>
+						</object>
+					</object>
+					<object class="NSMenuItem" id="713487014">
+						<reference key="NSMenu" ref="649796088"/>
+						<string key="NSTitle">Window</string>
+						<string key="NSKeyEquiv"/>
+						<int key="NSKeyEquivModMask">1048576</int>
+						<int key="NSMnemonicLoc">2147483647</int>
+						<reference key="NSOnImage" ref="35465992"/>
+						<reference key="NSMixedImage" ref="502551668"/>
+						<string key="NSAction">submenuAction:</string>
+						<object class="NSMenu" key="NSSubmenu" id="835318025">
+							<string key="NSTitle">Window</string>
+							<array class="NSMutableArray" key="NSMenuItems">
+								<object class="NSMenuItem" id="1011231497">
+									<reference key="NSMenu" ref="835318025"/>
+									<string key="NSTitle">Minimize</string>
+									<string key="NSKeyEquiv">m</string>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="575023229">
+									<reference key="NSMenu" ref="835318025"/>
+									<string key="NSTitle">Zoom</string>
+									<string key="NSKeyEquiv"/>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="299356726">
+									<reference key="NSMenu" ref="835318025"/>
+									<bool key="NSIsDisabled">YES</bool>
+									<bool key="NSIsSeparator">YES</bool>
+									<string key="NSTitle"/>
+									<string key="NSKeyEquiv"/>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+								<object class="NSMenuItem" id="625202149">
+									<reference key="NSMenu" ref="835318025"/>
+									<string key="NSTitle">Bring All to Front</string>
+									<string key="NSKeyEquiv"/>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+							</array>
+							<string key="NSName">_NSWindowsMenu</string>
+						</object>
+					</object>
+					<object class="NSMenuItem" id="448692316">
+						<reference key="NSMenu" ref="649796088"/>
+						<string key="NSTitle">Help</string>
+						<string key="NSKeyEquiv"/>
+						<int key="NSMnemonicLoc">2147483647</int>
+						<reference key="NSOnImage" ref="35465992"/>
+						<reference key="NSMixedImage" ref="502551668"/>
+						<string key="NSAction">submenuAction:</string>
+						<object class="NSMenu" key="NSSubmenu" id="992780483">
+							<string key="NSTitle">Help</string>
+							<array class="NSMutableArray" key="NSMenuItems">
+								<object class="NSMenuItem" id="105068016">
+									<reference key="NSMenu" ref="992780483"/>
+									<string key="NSTitle">BenchmarkMac Help</string>
+									<string key="NSKeyEquiv">?</string>
+									<int key="NSKeyEquivModMask">1048576</int>
+									<int key="NSMnemonicLoc">2147483647</int>
+									<reference key="NSOnImage" ref="35465992"/>
+									<reference key="NSMixedImage" ref="502551668"/>
+								</object>
+							</array>
+							<string key="NSName">_NSHelpMenu</string>
+						</object>
+					</object>
+				</array>
+				<string key="NSName">_NSMainMenu</string>
+			</object>
+			<object class="NSWindowTemplate" id="972006081">
+				<int key="NSWindowStyleMask">15</int>
+				<int key="NSWindowBacking">2</int>
+				<string key="NSWindowRect">{{335, 390}, {480, 360}}</string>
+				<int key="NSWTFlags">1954021376</int>
+				<string key="NSWindowTitle">BenchmarkMac</string>
+				<string key="NSWindowClass">NSWindow</string>
+				<nil key="NSViewClass"/>
+				<nil key="NSUserInterfaceItemIdentifier"/>
+				<object class="NSView" key="NSWindowView" id="439893737">
+					<nil key="NSNextResponder"/>
+					<int key="NSvFlags">256</int>
+					<string key="NSFrameSize">{480, 360}</string>
+				</object>
+				<string key="NSScreenRect">{{0, 0}, {1920, 1178}}</string>
+				<string key="NSMaxSize">{10000000000000, 10000000000000}</string>
+				<bool key="NSWindowIsRestorable">YES</bool>
+			</object>
+			<object class="NSCustomObject" id="976324537">
+				<string key="NSClassName">AppDelegate</string>
+			</object>
+			<object class="NSCustomObject" id="755631768">
+				<string key="NSClassName">NSFontManager</string>
+			</object>
+		</array>
+		<object class="IBObjectContainer" key="IBDocument.Objects">
+			<array class="NSMutableArray" key="connectionRecords">
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">terminate:</string>
+						<reference key="source" ref="1050"/>
+						<reference key="destination" ref="632727374"/>
+					</object>
+					<int key="connectionID">449</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">orderFrontStandardAboutPanel:</string>
+						<reference key="source" ref="1021"/>
+						<reference key="destination" ref="238522557"/>
+					</object>
+					<int key="connectionID">142</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBOutletConnection" key="connection">
+						<string key="label">delegate</string>
+						<reference key="source" ref="1021"/>
+						<reference key="destination" ref="976324537"/>
+					</object>
+					<int key="connectionID">495</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">performMiniaturize:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="1011231497"/>
+					</object>
+					<int key="connectionID">37</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">arrangeInFront:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="625202149"/>
+					</object>
+					<int key="connectionID">39</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">print:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="49223823"/>
+					</object>
+					<int key="connectionID">86</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">runPageLayout:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="294629803"/>
+					</object>
+					<int key="connectionID">87</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">clearRecentDocuments:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="759406840"/>
+					</object>
+					<int key="connectionID">127</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">performClose:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="776162233"/>
+					</object>
+					<int key="connectionID">193</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">toggleContinuousSpellChecking:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="948374510"/>
+					</object>
+					<int key="connectionID">222</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">undo:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="1058277027"/>
+					</object>
+					<int key="connectionID">223</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">copy:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="860595796"/>
+					</object>
+					<int key="connectionID">224</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">checkSpelling:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="96193923"/>
+					</object>
+					<int key="connectionID">225</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">paste:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="29853731"/>
+					</object>
+					<int key="connectionID">226</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">stopSpeaking:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="680220178"/>
+					</object>
+					<int key="connectionID">227</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">cut:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="296257095"/>
+					</object>
+					<int key="connectionID">228</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">showGuessPanel:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="679648819"/>
+					</object>
+					<int key="connectionID">230</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">redo:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="790794224"/>
+					</object>
+					<int key="connectionID">231</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">selectAll:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="583158037"/>
+					</object>
+					<int key="connectionID">232</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">startSpeaking:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="731782645"/>
+					</object>
+					<int key="connectionID">233</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">delete:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="437104165"/>
+					</object>
+					<int key="connectionID">235</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">performZoom:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="575023229"/>
+					</object>
+					<int key="connectionID">240</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">performFindPanelAction:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="447796847"/>
+					</object>
+					<int key="connectionID">241</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">centerSelectionInVisibleArea:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="88285865"/>
+					</object>
+					<int key="connectionID">245</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">toggleGrammarChecking:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="967646866"/>
+					</object>
+					<int key="connectionID">347</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">toggleSmartInsertDelete:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="605118523"/>
+					</object>
+					<int key="connectionID">355</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">toggleAutomaticQuoteSubstitution:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="197661976"/>
+					</object>
+					<int key="connectionID">356</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">toggleAutomaticLinkDetection:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="708854459"/>
+					</object>
+					<int key="connectionID">357</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">saveDocument:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="1023925487"/>
+					</object>
+					<int key="connectionID">362</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">revertDocumentToSaved:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="579971712"/>
+					</object>
+					<int key="connectionID">364</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">runToolbarCustomizationPalette:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="237841660"/>
+					</object>
+					<int key="connectionID">365</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">toggleToolbarShown:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="102151532"/>
+					</object>
+					<int key="connectionID">366</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">hide:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="755159360"/>
+					</object>
+					<int key="connectionID">367</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">hideOtherApplications:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="342932134"/>
+					</object>
+					<int key="connectionID">368</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">unhideAllApplications:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="908899353"/>
+					</object>
+					<int key="connectionID">370</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">newDocument:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="705341025"/>
+					</object>
+					<int key="connectionID">373</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">openDocument:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="722745758"/>
+					</object>
+					<int key="connectionID">374</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">raiseBaseline:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="941806246"/>
+					</object>
+					<int key="connectionID">426</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">lowerBaseline:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="1045724900"/>
+					</object>
+					<int key="connectionID">427</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">copyFont:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="596732606"/>
+					</object>
+					<int key="connectionID">428</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">subscript:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="1037576581"/>
+					</object>
+					<int key="connectionID">429</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">superscript:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="644725453"/>
+					</object>
+					<int key="connectionID">430</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">tightenKerning:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="677519740"/>
+					</object>
+					<int key="connectionID">431</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">underline:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="330926929"/>
+					</object>
+					<int key="connectionID">432</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">orderFrontColorPanel:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="1012600125"/>
+					</object>
+					<int key="connectionID">433</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">useAllLigatures:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="663508465"/>
+					</object>
+					<int key="connectionID">434</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">loosenKerning:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="238351151"/>
+					</object>
+					<int key="connectionID">435</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">pasteFont:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="393423671"/>
+					</object>
+					<int key="connectionID">436</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">unscript:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="257962622"/>
+					</object>
+					<int key="connectionID">437</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">useStandardKerning:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="252969304"/>
+					</object>
+					<int key="connectionID">438</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">useStandardLigatures:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="706297211"/>
+					</object>
+					<int key="connectionID">439</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">turnOffLigatures:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="568384683"/>
+					</object>
+					<int key="connectionID">440</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">turnOffKerning:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="766922938"/>
+					</object>
+					<int key="connectionID">441</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">toggleAutomaticSpellingCorrection:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="795346622"/>
+					</object>
+					<int key="connectionID">456</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">orderFrontSubstitutionsPanel:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="65139061"/>
+					</object>
+					<int key="connectionID">458</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">toggleAutomaticDashSubstitution:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="672708820"/>
+					</object>
+					<int key="connectionID">461</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">toggleAutomaticTextReplacement:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="537092702"/>
+					</object>
+					<int key="connectionID">463</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">uppercaseWord:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="1060694897"/>
+					</object>
+					<int key="connectionID">464</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">capitalizeWord:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="56570060"/>
+					</object>
+					<int key="connectionID">467</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">lowercaseWord:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="879586729"/>
+					</object>
+					<int key="connectionID">468</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">pasteAsPlainText:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="82994268"/>
+					</object>
+					<int key="connectionID">486</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">performFindPanelAction:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="326711663"/>
+					</object>
+					<int key="connectionID">487</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">performFindPanelAction:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="270902937"/>
+					</object>
+					<int key="connectionID">488</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">performFindPanelAction:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="159080638"/>
+					</object>
+					<int key="connectionID">489</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">showHelp:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="105068016"/>
+					</object>
+					<int key="connectionID">493</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">alignCenter:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="630155264"/>
+					</object>
+					<int key="connectionID">518</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">pasteRuler:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="883618387"/>
+					</object>
+					<int key="connectionID">519</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">toggleRuler:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="644046920"/>
+					</object>
+					<int key="connectionID">520</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">alignRight:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="512868991"/>
+					</object>
+					<int key="connectionID">521</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">copyRuler:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="231811626"/>
+					</object>
+					<int key="connectionID">522</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">alignJustified:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="945678886"/>
+					</object>
+					<int key="connectionID">523</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">alignLeft:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="875092757"/>
+					</object>
+					<int key="connectionID">524</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">makeBaseWritingDirectionNatural:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="551969625"/>
+					</object>
+					<int key="connectionID">525</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">makeBaseWritingDirectionLeftToRight:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="249532473"/>
+					</object>
+					<int key="connectionID">526</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">makeBaseWritingDirectionRightToLeft:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="607364498"/>
+					</object>
+					<int key="connectionID">527</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">makeTextWritingDirectionNatural:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="380031999"/>
+					</object>
+					<int key="connectionID">528</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">makeTextWritingDirectionLeftToRight:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="825984362"/>
+					</object>
+					<int key="connectionID">529</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">makeTextWritingDirectionRightToLeft:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="560145579"/>
+					</object>
+					<int key="connectionID">530</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">performFindPanelAction:</string>
+						<reference key="source" ref="1014"/>
+						<reference key="destination" ref="738670835"/>
+					</object>
+					<int key="connectionID">535</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">addFontTrait:</string>
+						<reference key="source" ref="755631768"/>
+						<reference key="destination" ref="305399458"/>
+					</object>
+					<int key="connectionID">421</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">addFontTrait:</string>
+						<reference key="source" ref="755631768"/>
+						<reference key="destination" ref="814362025"/>
+					</object>
+					<int key="connectionID">422</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">modifyFont:</string>
+						<reference key="source" ref="755631768"/>
+						<reference key="destination" ref="885547335"/>
+					</object>
+					<int key="connectionID">423</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">orderFrontFontPanel:</string>
+						<reference key="source" ref="755631768"/>
+						<reference key="destination" ref="159677712"/>
+					</object>
+					<int key="connectionID">424</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">modifyFont:</string>
+						<reference key="source" ref="755631768"/>
+						<reference key="destination" ref="158063935"/>
+					</object>
+					<int key="connectionID">425</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBOutletConnection" key="connection">
+						<string key="label">window</string>
+						<reference key="source" ref="976324537"/>
+						<reference key="destination" ref="972006081"/>
+					</object>
+					<int key="connectionID">532</int>
+				</object>
+			</array>
+			<object class="IBMutableOrderedSet" key="objectRecords">
+				<array key="orderedObjects">
+					<object class="IBObjectRecord">
+						<int key="objectID">0</int>
+						<array key="object" id="0"/>
+						<reference key="children" ref="1048"/>
+						<nil key="parent"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">-2</int>
+						<reference key="object" ref="1021"/>
+						<reference key="parent" ref="0"/>
+						<string key="objectName">File's Owner</string>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">-1</int>
+						<reference key="object" ref="1014"/>
+						<reference key="parent" ref="0"/>
+						<string key="objectName">First Responder</string>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">-3</int>
+						<reference key="object" ref="1050"/>
+						<reference key="parent" ref="0"/>
+						<string key="objectName">Application</string>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">29</int>
+						<reference key="object" ref="649796088"/>
+						<array class="NSMutableArray" key="children">
+							<reference ref="713487014"/>
+							<reference ref="694149608"/>
+							<reference ref="952259628"/>
+							<reference ref="379814623"/>
+							<reference ref="586577488"/>
+							<reference ref="302598603"/>
+							<reference ref="448692316"/>
+						</array>
+						<reference key="parent" ref="0"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">19</int>
+						<reference key="object" ref="713487014"/>
+						<array class="NSMutableArray" key="children">
+							<reference ref="835318025"/>
+						</array>
+						<reference key="parent" ref="649796088"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">56</int>
+						<reference key="object" ref="694149608"/>
+						<array class="NSMutableArray" key="children">
+							<reference ref="110575045"/>
+						</array>
+						<reference key="parent" ref="649796088"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">217</int>
+						<reference key="object" ref="952259628"/>
+						<array class="NSMutableArray" key="children">
+							<reference ref="789758025"/>
+						</array>
+						<reference key="parent" ref="649796088"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">83</int>
+						<reference key="object" ref="379814623"/>
+						<array class="NSMutableArray" key="children">
+							<reference ref="720053764"/>
+						</array>
+						<reference key="parent" ref="649796088"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">81</int>
+						<reference key="object" ref="720053764"/>
+						<array class="NSMutableArray" key="children">
+							<reference ref="1023925487"/>
+							<reference ref="49223823"/>
+							<reference ref="722745758"/>
+							<reference ref="705341025"/>
+							<reference ref="1025936716"/>
+							<reference ref="294629803"/>
+							<reference ref="776162233"/>
+							<reference ref="425164168"/>
+							<reference ref="579971712"/>
+							<reference ref="1010469920"/>
+						</array>
+						<reference key="parent" ref="379814623"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">75</int>
+						<reference key="object" ref="1023925487"/>
+						<reference key="parent" ref="720053764"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">78</int>
+						<reference key="object" ref="49223823"/>
+						<reference key="parent" ref="720053764"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">72</int>
+						<reference key="object" ref="722745758"/>
+						<reference key="parent" ref="720053764"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">82</int>
+						<reference key="object" ref="705341025"/>
+						<reference key="parent" ref="720053764"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">124</int>
+						<reference key="object" ref="1025936716"/>
+						<array class="NSMutableArray" key="children">
+							<reference ref="1065607017"/>
+						</array>
+						<reference key="parent" ref="720053764"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">77</int>
+						<reference key="object" ref="294629803"/>
+						<reference key="parent" ref="720053764"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">73</int>
+						<reference key="object" ref="776162233"/>
+						<reference key="parent" ref="720053764"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">79</int>
+						<reference key="object" ref="425164168"/>
+						<reference key="parent" ref="720053764"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">112</int>
+						<reference key="object" ref="579971712"/>
+						<reference key="parent" ref="720053764"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">74</int>
+						<reference key="object" ref="1010469920"/>
+						<reference key="parent" ref="720053764"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">125</int>
+						<reference key="object" ref="1065607017"/>
+						<array class="NSMutableArray" key="children">
+							<reference ref="759406840"/>
+						</array>
+						<reference key="parent" ref="1025936716"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">126</int>
+						<reference key="object" ref="759406840"/>
+						<reference key="parent" ref="1065607017"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">205</int>
+						<reference key="object" ref="789758025"/>
+						<array class="NSMutableArray" key="children">
+							<reference ref="437104165"/>
+							<reference ref="583158037"/>
+							<reference ref="1058277027"/>
+							<reference ref="212016141"/>
+							<reference ref="296257095"/>
+							<reference ref="29853731"/>
+							<reference ref="860595796"/>
+							<reference ref="1040322652"/>
+							<reference ref="790794224"/>
+							<reference ref="892235320"/>
+							<reference ref="972420730"/>
+							<reference ref="676164635"/>
+							<reference ref="507821607"/>
+							<reference ref="288088188"/>
+							<reference ref="82994268"/>
+						</array>
+						<reference key="parent" ref="952259628"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">202</int>
+						<reference key="object" ref="437104165"/>
+						<reference key="parent" ref="789758025"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">198</int>
+						<reference key="object" ref="583158037"/>
+						<reference key="parent" ref="789758025"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">207</int>
+						<reference key="object" ref="1058277027"/>
+						<reference key="parent" ref="789758025"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">214</int>
+						<reference key="object" ref="212016141"/>
+						<reference key="parent" ref="789758025"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">199</int>
+						<reference key="object" ref="296257095"/>
+						<reference key="parent" ref="789758025"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">203</int>
+						<reference key="object" ref="29853731"/>
+						<reference key="parent" ref="789758025"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">197</int>
+						<reference key="object" ref="860595796"/>
+						<reference key="parent" ref="789758025"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">206</int>
+						<reference key="object" ref="1040322652"/>
+						<reference key="parent" ref="789758025"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">215</int>
+						<reference key="object" ref="790794224"/>
+						<reference key="parent" ref="789758025"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">218</int>
+						<reference key="object" ref="892235320"/>
+						<array class="NSMutableArray" key="children">
+							<reference ref="963351320"/>
+						</array>
+						<reference key="parent" ref="789758025"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">216</int>
+						<reference key="object" ref="972420730"/>
+						<array class="NSMutableArray" key="children">
+							<reference ref="769623530"/>
+						</array>
+						<reference key="parent" ref="789758025"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">200</int>
+						<reference key="object" ref="769623530"/>
+						<array class="NSMutableArray" key="children">
+							<reference ref="948374510"/>
+							<reference ref="96193923"/>
+							<reference ref="679648819"/>
+							<reference ref="967646866"/>
+							<reference ref="859480356"/>
+							<reference ref="795346622"/>
+						</array>
+						<reference key="parent" ref="972420730"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">219</int>
+						<reference key="object" ref="948374510"/>
+						<reference key="parent" ref="769623530"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">201</int>
+						<reference key="object" ref="96193923"/>
+						<reference key="parent" ref="769623530"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">204</int>
+						<reference key="object" ref="679648819"/>
+						<reference key="parent" ref="769623530"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">220</int>
+						<reference key="object" ref="963351320"/>
+						<array class="NSMutableArray" key="children">
+							<reference ref="270902937"/>
+							<reference ref="88285865"/>
+							<reference ref="159080638"/>
+							<reference ref="326711663"/>
+							<reference ref="447796847"/>
+							<reference ref="738670835"/>
+						</array>
+						<reference key="parent" ref="892235320"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">213</int>
+						<reference key="object" ref="270902937"/>
+						<reference key="parent" ref="963351320"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">210</int>
+						<reference key="object" ref="88285865"/>
+						<reference key="parent" ref="963351320"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">221</int>
+						<reference key="object" ref="159080638"/>
+						<reference key="parent" ref="963351320"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">208</int>
+						<reference key="object" ref="326711663"/>
+						<reference key="parent" ref="963351320"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">209</int>
+						<reference key="object" ref="447796847"/>
+						<reference key="parent" ref="963351320"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">57</int>
+						<reference key="object" ref="110575045"/>
+						<array class="NSMutableArray" key="children">
+							<reference ref="238522557"/>
+							<reference ref="755159360"/>
+							<reference ref="908899353"/>
+							<reference ref="632727374"/>
+							<reference ref="646227648"/>
+							<reference ref="609285721"/>
+							<reference ref="481834944"/>
+							<reference ref="304266470"/>
+							<reference ref="1046388886"/>
+							<reference ref="1056857174"/>
+							<reference ref="342932134"/>
+						</array>
+						<reference key="parent" ref="694149608"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">58</int>
+						<reference key="object" ref="238522557"/>
+						<reference key="parent" ref="110575045"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">134</int>
+						<reference key="object" ref="755159360"/>
+						<reference key="parent" ref="110575045"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">150</int>
+						<reference key="object" ref="908899353"/>
+						<reference key="parent" ref="110575045"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">136</int>
+						<reference key="object" ref="632727374"/>
+						<reference key="parent" ref="110575045"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">144</int>
+						<reference key="object" ref="646227648"/>
+						<reference key="parent" ref="110575045"/>
<