diff --git a/.cocoadocs.yml b/.cocoadocs.yml
new file mode 100644
index 000000000..28cdd7148
--- /dev/null
+++ b/.cocoadocs.yml
@@ -0,0 +1 @@
+explicit-references: true
diff --git a/.travis.yml b/.travis.yml
index f0d61bf7e..9cbc69cd4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,12 +1,24 @@
language: objective-c
+env:
+ global:
+ LC_CTYPE="en_US.UTF-8"
+ matrix:
+ - CONFIGURATION="Code Coverage" SCHEME="XCDYouTubeKit iOS Static Library" DESTINATION="platform=iOS Simulator,name=iPhone 5s" OBJROOT="build"
+ - CONFIGURATION="Release" SCHEME="XCDYouTubeKit iOS Static Library" DESTINATION="platform=iOS Simulator,name=iPhone 5s,OS=7.1"
+ - CONFIGURATION="Release" SCHEME="XCDYouTubeKit iOS Static Library" DESTINATION="platform=iOS Simulator,name=iPhone 5s,OS=8.1"
+ - CONFIGURATION="Release" SCHEME="XCDYouTubeKit iOS Static Library" DESTINATION="platform=iOS Simulator,name=iPhone 4s" RUN_CLANG_STATIC_ANALYZER="YES"
+ - CONFIGURATION="Release" SCHEME="XCDYouTubeKit iOS Static Library" DESTINATION="platform=iOS Simulator,name=iPhone 5s" RUN_CLANG_STATIC_ANALYZER="YES"
+ - CONFIGURATION="Release" SCHEME="XCDYouTubeKit iOS Framework" DESTINATION="platform=iOS Simulator,name=iPhone 4s" RUN_CLANG_STATIC_ANALYZER="YES"
+ - CONFIGURATION="Release" SCHEME="XCDYouTubeKit iOS Framework" DESTINATION="platform=iOS Simulator,name=iPhone 5s" RUN_CLANG_STATIC_ANALYZER="YES"
+ - CONFIGURATION="Release" SCHEME="XCDYouTubeKit OS X" DESTINATION="platform=OS X" RUN_CLANG_STATIC_ANALYZER="YES"
+before_install:
+ - xcrun simctl list
install:
- - gem install xcpretty --no-rdoc --no-ri --no-document --quiet
- - sudo easy_install cpp-coveralls
+ - gem install xcpretty --no-rdoc --no-ri --no-document --quiet
+ - sudo easy_install cpp-coveralls
script:
- - export LC_CTYPE=en_US.UTF-8
- - set -o pipefail
- - xcodebuild test -project XCDYouTubeKit.xcodeproj -scheme 'XCDYouTubeKit iOS Static Library' -destination 'platform=iOS Simulator,name=iPhone Retina (4-inch)' | xcpretty -c
- - xcodebuild test -project XCDYouTubeKit.xcodeproj -scheme 'XCDYouTubeKit iOS Static Library' -destination 'platform=iOS Simulator,name=iPhone Retina (4-inch 64-bit)' OBJROOT=build | xcpretty -c
- - xcodebuild test -project XCDYouTubeKit.xcodeproj -scheme 'XCDYouTubeKit OS X' | xcpretty -c
+ - ./Scripts/run-tests.sh
after_success:
- - coveralls --include XCDYouTubeKit
+ - if [ "$CONFIGURATION" == "Code Coverage" ]; then
+ coveralls --include XCDYouTubeKit;
+ fi
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5b4d33596..8fc51ede0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+#### Version 2.2.0
+
+* Networking and parsing code is executed on a background thread for better performance. The `XCDYouTubeVideoOperation` class has changed from an asynchronous to a synchronous operation and must not be started on the main thread. (#147)
+* Logging support, see the [README](README.md#logging) for documentation.
+* Improved documentation.
+
#### Version 2.1.3
* Adaptation to YouTube API change. (#144)
diff --git a/LICENSE b/LICENSE
index 3ecf7d365..37026f305 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2013-2014 Cédric Luthi
+Copyright (c) 2013-2015 Cédric Luthi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index e8a1a5c54..7c2a8ecf7 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
[![Build Status](https://img.shields.io/travis/0xced/XCDYouTubeKit/master.svg?style=flat)](https://travis-ci.org/0xced/XCDYouTubeKit)
[![Coverage Status](https://img.shields.io/coveralls/0xced/XCDYouTubeKit/master.svg?style=flat)](https://coveralls.io/r/0xced/XCDYouTubeKit?branch=master)
[![Platform](https://img.shields.io/cocoapods/p/XCDYouTubeKit.svg?style=flat)](http://cocoadocs.org/docsets/XCDYouTubeKit/)
-[![Pod Version](https://img.shields.io/cocoapods/v/XCDYouTubeKit.svg?style=flat)](http://cocoadocs.org/docsets/XCDYouTubeKit/)
+[![Pod Version](https://img.shields.io/cocoapods/v/XCDYouTubeKit.svg?style=flat)](https://cocoapods.org/pods/XCDYouTubeKit)
[![Carthage Compatibility](https://img.shields.io/badge/carthage-✓-f2a77e.svg?style=flat)](https://github.com/Carthage/Carthage/)
[![License](https://img.shields.io/cocoapods/l/XCDYouTubeKit.svg?style=flat)](LICENSE)
@@ -30,12 +30,12 @@ XCDYouTubeKit is available through CocoaPods and Carthage.
CocoaPods:
```ruby
-pod "XCDYouTubeKit", "~> 2.1.3"
+pod "XCDYouTubeKit", "~> 2.2.0"
```
Carthage:
```objc
-github "0xced/XCDYouTubeKit" ~> 2.1.3
+github "0xced/XCDYouTubeKit" ~> 2.2.0
```
Alternatively, you can manually use the provided static library on iOS or dynamic framework on OS X. In order to use the iOS static library, you must:
@@ -97,6 +97,31 @@ XCDYouTubeVideoPlayerViewController *videoPlayerViewController = [[XCDYouTubeVid
See the demo project for more sample code.
+## Logging
+
+Since version 2.2.0, XCDYouTubeKit produces logs. XCDYouTubeKit supports [CocoaLumberjack](https://github.com/CocoaLumberjack/CocoaLumberjack) but does not require it. If your project includes CocoaLumberjack, all logs will be routed through CocoaLumberjack, else logs will be emitted with `NSLog`.
+
+The context for identifying all XCDYouTubeKit logs in CocoaLumberjack is the number `(NSInteger)0xced70676`. Beware, CocoaLumberjack contexts are NSIntegers, don’t forget the cast.
+
+### Controlling log levels
+
+If you are using CocoaLumberjack, you are responsible for controlling the log levels with the CocoaLumberjack APIs.
+
+If you are not using CocoaLumberjack, you can control the log levels with the `XCDYouTubeKitLogLevel` environment variable. The log levels are the same as CocoaLumberjack, with the addition of the *trace* level.
+
+Level | Value
+--------|------
+Error | 0x01
+Warning | 0x02
+Info | 0x04
+Debug | 0x08
+Verbose | 0x10
+Trace | 0x20
+
+The levels are bitmasks, so you can combine them. For example, if you want to log *error*, *warning* and *info* levels, set the `XCDYouTubeKitLogLevel` environment variable to `0x7`.
+
+If you do not set the `XCDYouTubeKitLogLevel` environment variable, only warning and error levels are logged.
+
## Credits
The URL extraction algorithms in *XCDYouTubeKit* are inspired by the [YouTube extractor](https://github.com/rg3/youtube-dl/blob/master/youtube_dl/extractor/youtube.py) module of the *youtube-dl* project.
diff --git a/Scripts/analyzer.py b/Scripts/analyzer.py
new file mode 100755
index 000000000..920d6fff4
--- /dev/null
+++ b/Scripts/analyzer.py
@@ -0,0 +1,23 @@
+#!/usr/bin/python
+
+import os, plistlib, sys
+
+run_clang_static_analyzer = os.environ.get('RUN_CLANG_STATIC_ANALYZER', '0').strip(' ')
+if not run_clang_static_analyzer[:1] in 'YyTt123456789':
+ sys.exit(0)
+
+analyzer_results_dir = os.path.join(os.environ['TARGET_TEMP_DIR'], 'StaticAnalyzer', os.environ['PROJECT_NAME'], os.environ['TARGET_NAME'], os.environ['CURRENT_VARIANT'], os.environ['CURRENT_ARCH'])
+if not os.path.exists(analyzer_results_dir):
+ sys.exit("error: Static Anaylzer results not found, expected in %s" % analyzer_results_dir)
+
+exit_code = 0
+for result in os.listdir(analyzer_results_dir):
+ with open(os.path.join(analyzer_results_dir, result)) as f:
+ plist = plistlib.readPlist(f)
+ for diagnostic in plist['diagnostics']:
+ location = diagnostic['location']
+ path = plist['files'][location['file']]
+ print "%s:%s:%s: error: Static Anaylzer Issue: %s" % (path, location['line'], location['col'], diagnostic['description'])
+ exit_code = 1
+
+sys.exit(exit_code)
diff --git a/Scripts/run-tests.sh b/Scripts/run-tests.sh
new file mode 100755
index 000000000..9ac4c0335
--- /dev/null
+++ b/Scripts/run-tests.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+set -o pipefail
+
+: ${SCHEME:="XCDYouTubeKit iOS Static Library"}
+: ${CONFIGURATION:="Release"}
+: ${DESTINATION:="platform=iOS Simulator,name=iPhone 5s"}
+
+COMMAND="xcodebuild clean test -project XCDYouTubeKit.xcodeproj -scheme '${SCHEME}' -configuration '${CONFIGURATION}' -destination '${DESTINATION}'"
+
+for BUILD_SETTING in OBJROOT RUN_CLANG_STATIC_ANALYZER; do
+ VALUE=`eval echo \\$"${BUILD_SETTING}"`
+ if [ ! -z "${VALUE}" ]; then
+ COMMAND+=" ${BUILD_SETTING}='${VALUE}'"
+ unset ${BUILD_SETTING}
+ fi
+done
+
+xcpretty --version > /dev/null && COMMAND+=" | xcpretty -c"
+
+set -x
+eval "${COMMAND}"
diff --git a/XCDYouTubeKit Demo.xcworkspace/contents.xcworkspacedata b/XCDYouTubeKit Demo.xcworkspace/contents.xcworkspacedata
index f9441e700..2441abb2c 100644
--- a/XCDYouTubeKit Demo.xcworkspace/contents.xcworkspacedata
+++ b/XCDYouTubeKit Demo.xcworkspace/contents.xcworkspacedata
@@ -7,4 +7,7 @@
+
+
diff --git a/XCDYouTubeKit Demo/OS X Demo/AppDelegate.h b/XCDYouTubeKit Demo/OS X Demo/AppDelegate.h
index 6f778fb9e..6776810ee 100644
--- a/XCDYouTubeKit Demo/OS X Demo/AppDelegate.h
+++ b/XCDYouTubeKit Demo/OS X Demo/AppDelegate.h
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2014 Cédric Luthi. All rights reserved.
+// Copyright (c) 2013-2015 Cédric Luthi. All rights reserved.
//
@interface AppDelegate : NSObject
diff --git a/XCDYouTubeKit Demo/OS X Demo/AppDelegate.m b/XCDYouTubeKit Demo/OS X Demo/AppDelegate.m
index 37d0e87b2..5d2c22d80 100644
--- a/XCDYouTubeKit Demo/OS X Demo/AppDelegate.m
+++ b/XCDYouTubeKit Demo/OS X Demo/AppDelegate.m
@@ -1,14 +1,18 @@
//
-// Copyright (c) 2014 Cédric Luthi. All rights reserved.
+// Copyright (c) 2013-2015 Cédric Luthi. All rights reserved.
//
#import "AppDelegate.h"
+#import
+
@implementation AppDelegate
- (void) applicationDidFinishLaunching:(NSNotification *)aNotification
{
[[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"VideoIdentifier": @"EdeVaT-zZt4" }];
+
+ [DDLog addLogger:[DDASLLogger sharedInstance]];
}
- (IBAction) playVideo:(id)sender
diff --git a/XCDYouTubeKit Demo/OS X Demo/Supporting Files/XCDYouTubeKit OS X Demo-Info.plist b/XCDYouTubeKit Demo/OS X Demo/Supporting Files/XCDYouTubeKit OS X Demo-Info.plist
index ef94c180a..91cc91846 100644
--- a/XCDYouTubeKit Demo/OS X Demo/Supporting Files/XCDYouTubeKit OS X Demo-Info.plist
+++ b/XCDYouTubeKit Demo/OS X Demo/Supporting Files/XCDYouTubeKit OS X Demo-Info.plist
@@ -25,7 +25,7 @@
LSMinimumSystemVersion
${MACOSX_DEPLOYMENT_TARGET}
NSHumanReadableCopyright
- Copyright © 2014 Cédric Luthi. All rights reserved.
+ Copyright © 2013-2015 Cédric Luthi. All rights reserved.
NSMainNibFile
MainMenu
NSPrincipalClass
diff --git a/XCDYouTubeKit Demo/OS X Demo/Supporting Files/main.m b/XCDYouTubeKit Demo/OS X Demo/Supporting Files/main.m
index 569579aa6..33bb6da79 100644
--- a/XCDYouTubeKit Demo/OS X Demo/Supporting Files/main.m
+++ b/XCDYouTubeKit Demo/OS X Demo/Supporting Files/main.m
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2014 Cédric Luthi. All rights reserved.
+// Copyright (c) 2013-2015 Cédric Luthi. All rights reserved.
//
int main(int argc, const char * argv[])
diff --git a/XCDYouTubeKit Demo/Podfile b/XCDYouTubeKit Demo/Podfile
new file mode 100644
index 000000000..1ad7f67e2
--- /dev/null
+++ b/XCDYouTubeKit Demo/Podfile
@@ -0,0 +1,16 @@
+xcodeproj 'XCDYouTubeKit Demo.xcodeproj'
+workspace '../XCDYouTubeKit Demo.xcworkspace'
+
+def import_pods
+ pod 'XCDLumberjackNSLogger', '~> 1.0.0'
+end
+
+target 'XCDYouTubeKit iOS Demo' do
+ platform :ios, '5.0'
+ import_pods
+end
+
+target 'XCDYouTubeKit OS X Demo' do
+ platform :osx, '10.9'
+ import_pods
+end
diff --git a/XCDYouTubeKit Demo/Podfile.lock b/XCDYouTubeKit Demo/Podfile.lock
new file mode 100644
index 000000000..b07710929
--- /dev/null
+++ b/XCDYouTubeKit Demo/Podfile.lock
@@ -0,0 +1,25 @@
+PODS:
+ - CocoaLumberjack (2.0.0):
+ - CocoaLumberjack/Default (= 2.0.0)
+ - CocoaLumberjack/Extensions (= 2.0.0)
+ - CocoaLumberjack/Core (2.0.0)
+ - CocoaLumberjack/Default (2.0.0):
+ - CocoaLumberjack/Core
+ - CocoaLumberjack/Extensions (2.0.0):
+ - CocoaLumberjack/Default
+ - NSLogger (1.5.1):
+ - NSLogger/Standard (= 1.5.1)
+ - NSLogger/Standard (1.5.1)
+ - XCDLumberjackNSLogger (1.0.0):
+ - CocoaLumberjack (~> 2.0.0)
+ - NSLogger (~> 1.5.1)
+
+DEPENDENCIES:
+ - XCDLumberjackNSLogger (~> 1.0.0)
+
+SPEC CHECKSUMS:
+ CocoaLumberjack: a6f77d987d65dc7ba86b0f84db7d0b9084f77bcb
+ NSLogger: 5ed223a2436df96244e033be750656dacdeec034
+ XCDLumberjackNSLogger: 499dd507ac73e41b63b600b3280b9920e35f53c6
+
+COCOAPODS: 0.37.2
diff --git a/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/CocoaLumberjack.h b/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/CocoaLumberjack.h
new file mode 100644
index 000000000..0b568fb09
--- /dev/null
+++ b/XCDYouTubeKit Demo/Pods/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
+ *
+ * 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
+
+// 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/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/CocoaLumberjack.swift b/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/CocoaLumberjack.swift
new file mode 100644
index 000000000..3c59e4094
--- /dev/null
+++ b/XCDYouTubeKit Demo/Pods/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
+import CocoaLumberjack
+
+extension DDLogFlag {
+ public static func fromLogLevel(logLevel: DDLogLevel) -> DDLogFlag {
+ return DDLogFlag(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 = self
+ if logFlag & .Verbose == .Verbose {
+ return .Error
+ } else if logFlag & .Debug == .Debug {
+ return .Debug
+ } else if logFlag & .Info == .Info {
+ return .Info
+ } else if logFlag & .Warning == .Warning {
+ return .Warning
+ } else if logFlag & .Error == .Error {
+ return .Verbose
+ } else {
+ return .Off
+ }
+ }
+ }
+}
+
+extension DDMultiFormatter {
+ public var formatterArray: [DDLogFormatter] {
+ return self.formatters as [DDLogFormatter]
+ }
+}
+
+public var defaultDebugLevel = DDLogLevel.Warning
+
+public func resetDefaultDebugLevel() {
+ defaultDebugLevel = DDLogLevel.Warning
+}
+
+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, #string: @autoclosure () -> 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(logText: @autoclosure () -> String, level: DDLogLevel = defaultDebugLevel, file: StaticString = __FILE__, function: StaticString = __FUNCTION__, line: UWord = __LINE__, asynchronous async: Bool = true) {
+ SwiftLogMacro(async, level, flag: .Debug, file: file, function: function, line: line, string: logText)
+}
+
+public func DDLogInfo(logText: @autoclosure () -> String, level: DDLogLevel = defaultDebugLevel, file: StaticString = __FILE__, function: StaticString = __FUNCTION__, line: UWord = __LINE__, asynchronous async: Bool = true) {
+ SwiftLogMacro(async, level, flag: .Info, file: file, function: function, line: line, string: logText)
+}
+
+public func DDLogWarn(logText: @autoclosure () -> String, level: DDLogLevel = defaultDebugLevel, file: StaticString = __FILE__, function: StaticString = __FUNCTION__, line: UWord = __LINE__, asynchronous async: Bool = true) {
+ SwiftLogMacro(async, level, flag: .Warning, file: file, function: function, line: line, string: logText)
+}
+
+public func DDLogVerbose(logText: @autoclosure () -> String, level: DDLogLevel = defaultDebugLevel, file: StaticString = __FILE__, function: StaticString = __FUNCTION__, line: UWord = __LINE__, asynchronous async: Bool = true) {
+ SwiftLogMacro(async, level, flag: .Verbose, file: file, function: function, line: line, string: logText)
+}
+
+public func DDLogError(logText: @autoclosure () -> String, level: DDLogLevel = defaultDebugLevel, file: StaticString = __FILE__, function: StaticString = __FUNCTION__, line: UWord = __LINE__, asynchronous async: Bool = false) {
+ SwiftLogMacro(async, level, flag: .Error, file: file, function: function, line: line, 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
+ return "\(fileName)".lastPathComponent.stringByDeletingPathExtension
+}
diff --git a/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDASLLogCapture.h b/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDASLLogCapture.h
new file mode 100644
index 000000000..c87d0b1ac
--- /dev/null
+++ b/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDASLLogCapture.h
@@ -0,0 +1,32 @@
+// 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
+
++ (void)start;
++ (void)stop;
+
+// Default log level: DDLogLevelVerbose (i.e. capture all ASL messages).
++ (DDLogLevel)captureLevel;
++ (void)setCaptureLevel:(DDLogLevel)level;
+
+@end
diff --git a/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDASLLogCapture.m b/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDASLLogCapture.m
new file mode 100644
index 000000000..87601a34c
--- /dev/null
+++ b/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDASLLogCapture.m
@@ -0,0 +1,227 @@
+// 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
+#include
+#include
+#include
+
+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) {
+ [DDASLLogCapture 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);
+
+#if !TARGET_OS_IPHONE || TARGET_IPHONE_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)aslMessageRecieved:(aslmsg)msg {
+ const char* messageCString = asl_get( msg, ASL_KEY_MSG );
+ if ( messageCString == NULL )
+ return;
+
+ // NSString * sender = [NSString stringWithCString:asl_get(msg, ASL_KEY_SENDER) encoding:NSUTF8StringEncoding];
+ NSString *message = @(messageCString);
+ NSString *level = @(asl_get(msg, ASL_KEY_LEVEL));
+ NSString *secondsStr = @(asl_get(msg, ASL_KEY_TIME));
+ NSString *nanoStr = @(asl_get(msg, ASL_KEY_TIME_NSEC));
+
+ NSTimeInterval seconds = [secondsStr doubleValue];
+ NSTimeInterval nanoSeconds = [nanoStr doubleValue];
+ NSTimeInterval totalSeconds = seconds + (nanoSeconds / 1e9);
+
+ NSDate *timeStamp = [NSDate dateWithTimeIntervalSince1970:totalSeconds];
+
+ int flag;
+ BOOL async;
+
+ switch ([level intValue]) {
+ // 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;
+ }
+
+ 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, ¬ifyToken, 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);
+ }
+
+ [DDASLLogCapture configureAslQuery:query];
+
+ // Iterate over new messages.
+ aslmsg msg;
+ aslresponse response = asl_search(NULL, query);
+
+ while ((msg = dd_asl_next(response)))
+ {
+ [DDASLLogCapture aslMessageRecieved:msg];
+
+ // Keep track of which messages we've seen.
+ lastSeenID = atoll(asl_get(msg, ASL_KEY_MSG_ID));
+ }
+ dd_asl_release(response);
+
+ if (_cancel) {
+ notify_cancel(notifyToken);
+ return;
+ }
+
+ free(query);
+ }
+ });
+ }
+}
+
+@end
diff --git a/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDASLLogger.h b/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDASLLogger.h
new file mode 100755
index 000000000..5ca6785b6
--- /dev/null
+++ b/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDASLLogger.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
+
+// Disable legacy macros
+#ifndef DD_LEGACY_MACROS
+ #define DD_LEGACY_MACROS 0
+#endif
+
+#import "DDLog.h"
+
+/**
+ * This class provides a logger for the Apple System Log facility.
+ *
+ * As described in the "Getting Started" page,
+ * the traditional NSLog() function directs it's 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
+
++ (instancetype)sharedInstance;
+
+// Inherited from DDAbstractLogger
+
+// - (id )logFormatter;
+// - (void)setLogFormatter:(id )formatter;
+
+@end
diff --git a/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDASLLogger.m b/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDASLLogger.m
new file mode 100644
index 000000000..c3a2c185c
--- /dev/null
+++ b/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDASLLogger.m
@@ -0,0 +1,116 @@
+// 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
+
+#if !__has_feature(objc_arc)
+#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
+#endif
+
+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 (logMessage) {
+ 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_send(_client, m);
+ }
+ asl_free(m);
+ }
+ //TODO handle asl_* failures non-silently?
+ }
+}
+
+- (NSString *)loggerName {
+ return @"cocoa.lumberjack.aslLogger";
+}
+
+@end
diff --git a/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDAbstractDatabaseLogger.h b/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDAbstractDatabaseLogger.h
new file mode 100644
index 000000000..745a91b0f
--- /dev/null
+++ b/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDAbstractDatabaseLogger.h
@@ -0,0 +1,112 @@
+// 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;
+@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;
+@property (assign, readwrite) NSTimeInterval deleteInterval;
+@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/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDAbstractDatabaseLogger.m b/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDAbstractDatabaseLogger.m
new file mode 100644
index 000000000..c8782de48
--- /dev/null
+++ b/XCDYouTubeKit Demo/Pods/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
+
+
+#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/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDAssertMacros.h b/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDAssertMacros.h
new file mode 100644
index 000000000..870d31f5d
--- /dev/null
+++ b/XCDYouTubeKit Demo/Pods/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/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDFileLogger.h b/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDFileLogger.h
new file mode 100644
index 000000000..d2f9ebb5d
--- /dev/null
+++ b/XCDYouTubeKit Demo/Pods/CocoaLumberjack/Classes/DDFileLogger.h
@@ -0,0 +1,391 @@
+// 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
+@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
+
+- (NSString *)logsDirectory;
+
+- (NSArray *)unsortedLogFilePaths;
+- (NSArray *)unsortedLogFileNames;
+- (NSArray *)unsortedLogFileInfos;
+
+- (NSArray *)sortedLogFilePaths;
+- (NSArray *)sortedLogFileNames;
+- (NSArray *)sortedLogFileInfos;
+
+// Private methods (only to be used by DDFileLogger)
+
+- (NSString *)createNewLogFile;
+
+@optional
+
+// Notifications from DDFileLogger
+
+- (void)didArchiveLogFile:(NSString *)logFilePath;
+- (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/.
+ * On iPhone, this is in ~/Library/Caches/Logs.
+ *
+ * Log files are named "