Giter Site home page Giter Site logo

urlnavigator's Introduction

URLNavigator

Swift CocoaPods Build Status CodeCov

⛵️ URLNavigator provides an elegant way to navigate through view controllers by URLs. URL patterns can be mapped by using URLNavigator.register(_:_:) function.

URLNavigator can be used for mapping URL patterns with 2 kind of types: URLNavigable and URLOpenHandler. URLNavigable is a type which defines an custom initializer and URLOpenHandler is a closure which can be executed. Both an initializer and a closure receive an URL and placeholder values.

Getting Started

1. Understanding URL Patterns

URL patterns can contain placeholders. Placeholders will be replaced with matching values from URLs. Use < and > to make placeholders. Placeholders can have types: string(default), int, float, and path.

For example, myapp://user/<int:id> matches with:

  • myapp://user/123
  • myapp://user/87

But it doesn't match with:

  • myapp://user/devxoul (expected int)
  • myapp://user/123/posts (different url structure)
  • /user/devxoul (missing scheme)

2. Mapping View Controllers and URL Open Handlers

URLNavigator allows to map view controllers and URL open handlers with URL patterns. Here's an example of mapping URL patterns with view controllers and a closure. Each closures has three parameters: url, values and context.

  • url is an URL that is passed from push() and present().
  • values is a dictionary that contains URL placeholder keys and values.
  • context is a dictionary which contains extra values passed from push(), present() or open().
let navigator = Navigator()

// register view controllers
navigator.register("myapp://user/<int:id>") { url, values, context in
  guard let userID = values["id"] as? Int else { return nil }
  return UserViewController(userID: userID)
}
navigator.register("myapp://post/<title>") { url, values, context in
  return storyboard.instantiateViewController(withIdentifier: "PostViewController")
}

// register url open handlers
navigator.handle("myapp://alert") { url, values, context in
  let title = url.queryParameters["title"]
  let message = url.queryParameters["message"]
  presentAlertController(title: title, message: message)
  return true
}

3. Pushing, Presenting and Opening URLs

URLNavigator can push and present view controllers and execute closures with URLs.

Provide the from parameter to push() to specify the navigation controller which the new view controller will be pushed. Similarly, provide the from parameter to present() to specify the view controller which the new view controller will be presented. If the nil is passed, which is a default value, current application's top most view controller will be used to push or present view controllers.

present() takes an extra parameter: wrap. If a UINavigationController class is specified, the new view controller will be wrapped with the class. Default value is nil.

Navigator.push("myapp://user/123")
Navigator.present("myapp://post/54321", wrap: UINavigationController.self)

Navigator.open("myapp://alert?title=Hello&message=World")

Installation

URLNavigator officially supports CocoaPods only.

Podfile

pod 'URLNavigator'

Example

You can find an example app here.

  1. Build and install the example app.
  2. Open Safari app
  3. Enter navigator://user/devxoul in the URL bar.
  4. The example app will be launched.

Tips and Tricks

Where to initialize a Navigator instance

  1. Define as a global constant:

    let navigator = Navigator()
    
    class AppDelegate: UIResponder, UIApplicationDelegate {
      // ...
    }
  2. Register to an IoC container:

    container.register(NavigatorProtocol.self) { _ in Navigator() } // Swinject
    let navigator = container.resolve(NavigatorProtocol.self)!
  3. Inject dependency from a composition root.

Where to Map URLs

I'd prefer using separated URL map file.

struct URLNavigationMap {
  static func initialize(navigator: NavigatorProtocol) {
    navigator.register("myapp://user/<int:id>") { ... }
    navigator.register("myapp://post/<title>") { ... }
    navigator.handle("myapp://alert") { ... }
  }
}

Then call initialize() at AppDelegate's application:didFinishLaunchingWithOptions:.

@UIApplicationMain
final class AppDelegate: UIResponder, UIApplicationDelegate {
  func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
  ) -> Bool {
    // Navigator
    URLNavigationMap.initialize(navigator: navigator)
    
    // Do something else...
  }
}

Implementing AppDelegate Launch Option URL

It's available to open your app with URLs if custom schemes are registered. In order to navigate to view controllers with URLs, you'll have to implement application:didFinishLaunchingWithOptions: method.

func application(
  _ application: UIApplication,
  didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
) -> Bool {
  // ...
  if let url = launchOptions?[.url] as? URL {
    if let opened = navigator.open(url)
    if !opened {
      navigator.present(url)
    }
  }
  return true
}

Implementing AppDelegate Open URL Method

You'll might want to implement custom URL open handler. Here's an example of using URLNavigator with other URL open handlers.

func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
  // If you're using Facebook SDK
  let fb = FBSDKApplicationDelegate.sharedInstance()
  if fb.application(application, open: url, sourceApplication: sourceApplication, annotation: annotation) {
    return true
  }

  // URLNavigator Handler
  if navigator.open(url) {
    return true
  }

  // URLNavigator View Controller
  if navigator.present(url, wrap: UINavigationController.self) != nil {
    return true
  }

  return false
}

Passing Extra Values when Pushing, Presenting and Opening

let context: [AnyHashable: Any] = [
  "fromViewController": self
]
Navigator.push("myapp://user/10", context: context)
Navigator.present("myapp://user/10", context: context)
Navigator.open("myapp://alert?title=Hi", context: context)

Defining custom URL Value Converters

You can define custom URL Value Converters for URL placeholders.

For example, the placeholder <region> is only allowed for the strings ["us-west-1", "ap-northeast-2", "eu-west-3"]. If it doesn't contain any of these, the URL pattern should not match.

Add a custom value converter to the [String: URLValueConverter] dictionary on your instance of Navigator.

navigator.matcher.valueConverters["region"] = { pathComponents, index in
  let allowedRegions = ["us-west-1", "ap-northeast-2", "eu-west-3"]
  if allowedRegions.contains(pathComponents[index]) {
    return pathComponents[index]
  } else {
    return nil
  }
}

With the code above, for example, myapp://region/<region:_> matches with:

  • myapp://region/us-west-1
  • myapp://region/ap-northeast-2
  • myapp://region/eu-west-3

But it doesn't match with:

  • myapp://region/ca-central-1

For additional information, see the implementation of default URL Value Converters.

License

URLNavigator is under MIT license. See the LICENSE file for more info.

urlnavigator's People

Contributors

aemoe avatar alihen avatar devxoul avatar fuyoufang avatar hjazz avatar ishawnwang avatar jeffaburt avatar jrmsklar avatar ohkanghoon avatar rolandasrazma avatar ruby109 avatar taimur avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

urlnavigator's Issues

Navigator.scheme removed ?

Hello,

I just try to update to your new 2.0 URLNavigator version and I can't find a way to set automatically my URL scheme in the Navigator like with Navigator.scheme in 1.0 version
I need to do this because I create two apps from the same base code but with different scheme.
And I have a lot of Navigator.map("my/url/path/without/scheme") so duplicate all of these with each scheme version isn't a good solution.

Did I missed something?

Thank!

Can't transition to the newest version of URLNavigator

Hello @devxoul. First of all thanks for making this Navigator it's so helpful. I have a hard time to transition to the new version of the Navigator because of some issues. I know that .map has been deprecated but I have a hard time to find with what to replace it. Here's the errors that I keep getting:

If I can understand what I need to change etc I would be more than happy to make a migrate doc with more explanation in the docs about how and why things need to change for the 2nd version.

Thanks for the help in advance @devxoul!

33952674-3b87e44e-e03b-11e7-8cd8-7b606e049c12
screen shot 2017-12-13 at 19 13 02
screen shot 2017-12-13 at 19 13 16

Dependency Injection

I think it should be possible to map URL to some closure that returns UIViewController instead of just Navigatable.

I am using Swinject in project and I am unable to use URLNavigator DI container as it requires type only and I cannot return an instance in any way.

Simple example:

Navigator.map("//list/<approvalRequestType>") { navigation in 
  return ListViewController(foo: navigation.values["approvalRequestType"] as! Int) 
}

error when install by carthage

Hello,
A problem occurs in release 2.0.0 when using Carthage, it will install success,but error when compiles:

Module file's minimum deployment target is ios11.0 v11.0: /Users/.../Carthage/Build/iOS/URLNavigator.framework/Modules/URLNavigator.swiftmodule/x86_64.swiftmodule

but when I use 1.3.0 , carthage install fail, error:
"Incompatible Swift version - framework was built with 4.0 (swiftlang-900.0.65 clang-900.0.37) and the local version is 4.0 (swiftlang-900.0.65.2 clang-900.0.37)."

My local Xcode version is 9.0.1 (9A1004), could you help me

tvOS support

Hi @devxoul

What about a tvOS support ?

I think it is easy because of the same architecture on tvOS about windows & co. We use UIKit and Foundation and non-specific iOS APIs.

Are you agree ?
I think add a demo project for tvOS and change the podspec and it will be ok :)

Prevent push to the same ViewController

Hi,

First, thanks for building URLNavigator. It turns really easy to implement a deep linking strategy throughout the app.
Second, my question, is there any way to prevent opening the same view controller or the same "path" already built in into URLNavigator?

If not, I'm willing to implement some strategy, I'm just not seeing how you'll do it, right now.

Thanks once again, great job!

Francisco

Protocol Implementation Issues in Demo project

I downloaded the sample project and I faced this issue.

Type 'UserViewController' does not conform to protocol 'URLNavigable'. Here is the screen shot.
http://imgur.com/DDQxSjD

I researched and I found there is only 1 function in the Protocol URLNavigable

init?(navigation: Navigation)

and there is not function with this signature

convenience init?(url: URLConvertible, values: [String: Any], userInfo: [AnyHashable: Any]?)

Using autocorrect this is what compiler added and with little modifications I am able to compile and run the project but its not navigating properly. Can someone help / assist to fix it.
Thanks a lot !

extension UserViewController: URLNavigable {
  convenience init?(navigation: Navigation) {
    guard let id = navigation.values["id"] as? Int else {
               return nil
        }
    self.init(navigation:navigation)
    
  }

  convenience init?(url: URLConvertible, values: [String: Any], userInfo: [AnyHashable: Any]?) {
    guard let username = values["username"] as? String else { return nil }
    self.init(username: username)
  }

}

Hey, some questions.

VC name A want push VC name B. If A want get some informations from B, B will contain a block property that A set it, B call it. How to do this with URLNavigator ?

Carthage cannot build

*** Downloading URLNavigator.framework binary at "2.0.2"
*** Skipped installing URLNavigator.framework binary due to the error:
        "Incompatible Swift version - framework was built with 4.0 (swiftlang-900.0.65 clang-900.0.37) and the local version is 4.0.2 (swiftlang-900.0.69.2 clang-900.0.38)."
*** Checking out URLNavigator at "2.0.2"
*** xcodebuild output can be found in /var/folders/vz/3fwzpk4n73sd5qmp95675c600000gp/T/carthage-xcodebuild.CaYb0E.log
*** Skipped building URLNavigator due to the error:
Dependency "URLNavigator" has no shared framework schemes

If you believe this to be an error, please file an issue with the maintainers at https://github.com/devxoul/URLNavigator/issues/new

If you provide a shared scheme to build then Carthage will build a new binary with our version of swift. This will allow us to get around swift's version issues since it doesn't have a stable ABI.

Release 2.0.0 Carthage issue

Hello,
A problem occurs in release 2.0.0 when using Carthage:
After Carthage update, I can not find URLNavigator.framework file in Carthage/Build/... directory.
However, release 1.3.0 is OK.

Request: Remove a route from the map

It would be nice to remove a route handler from the map :)

Maybe?

// In URLNavigator.swift
open func remove(_ urlPattern: URLConvertible) {
    let URLString = URLMatcher.default.normalized(urlPattern, scheme: self.scheme).urlStringValue
    if self.urlMap.removeValue(forKey: URLString) == nil {
        self.urlOpenHandlers.removeValue(forKey: URLString)
    }
}

open func removeAllURLPatterns() {
    self.urlMap.removeAll()
    self.urlOpenHandlers.removeAll()
}

Nested pushes

Hi! I was wondering if it would be able to implement nested view controller navigation. Take the example:

A chat app has:

  • Tab_Chats > Chat_List > Chat_View
  • Tab_Settings > Settings_View

As of today we can have

  • "/chats" open the list view
  • "/chat/<id>" open a specific chat view

But would it be possible to allow for "/chats/chat<id>", where both are URLNavigable separately and the combined url is interpreted automatically, showing the chat view animated but, afterwards, setting the list as the previous view controller in the stack. In this way we could enter the chat, but don't have it in the middle of nowhere, but in the same place as ever, where "back" takes the user back to the list view (even if it was not the prior view controller).

This would make the navigator much more useful, not having to implement each url like "/chats/chat/<id>" and implementing the logic by hand.

[Improvement] Override UIKit for handling navigation

Hi @devxoul,

I find your framework really interesnting, and lately, I've been playing around with Redux architecture in iOS. Summary: You keep a stack with the status, and each time something change you have a new status.
https://github.com/ReSwift/ReSwift

One thing that's still missing is handling navigation inside a state because it may be difficult to override a tabBar, or make a UINavigationViewController fire an action when dismissing the controller, etc.

This could play nicely if you knew how to do it or you may be interested in Redux.
Here is an attempt of doing that:
https://github.com/ReSwift/ReSwift-Router

Keep the good work up and thanks for making this framework available!

Navigation push function returns nil

Whenever I push a VC through push method of Navigator it goes to nil statement at the guard

Here is how I am doing it. I have NavigationMap file with these lines

static func initialize() {
let URL = "navigator://propertyDPV"
Navigator.present(URL)
}

In URLNavigator.swift class the function return nil

@discardableResult
  open func push(
    _ url: URLConvertible,
    context: NavigationContext? = nil,
    from: UINavigationController? = nil,
    animated: Bool = true
  ) -> UIViewController? {
    guard let viewController = self.viewController(for: url, context: context) else {
      return nil
    }
    return self.push(viewController, from: from, animated: animated)
  }

Understanding why "+" is removed from queryParameter

In URLConvertible.swift, there is this function:

public var queryParameters: [String: String] {
    var parameters = [String: String]()
    self.urlValue?.query?.components(separatedBy: "&").forEach {
      let keyAndValue = $0.components(separatedBy: "=")
      if keyAndValue.count == 2 {
        let key = keyAndValue[0]
        let value = keyAndValue[1].replacingOccurrences(of: "+", with: " ").removingPercentEncoding
          ?? keyAndValue[1]
        parameters[key] = value
      }
    }
    return parameters
  }

It strips the "+" into spaces.

So having this route: myapp://access/[email protected], the queryParam email becomes me [email protected].

In which case do we need to remove the "+"?
My guess is that Google converts any query with a space into a URL with a "+". But this is specific to Google.
If we still need it, we probably need to add another similar compiled var like queryParametersRaw: [String: String] without the query manipulation

Tab bars?

Does this support tab bars? Lets say I want to route to a page in one of the tab, will it work?
But to mention this is a cool project, thanks.

Error in Release note 2.0.0 (Must remove Context object)

There is a release note error for v2

In the code example for

Mapping view controllers: Use register() to map view controllers. It takes a view controller factory instead of URLNavigable so that you can inject dependency to the view controller or create a view controller from Storyboard. Also, URLNavigable is removed.

The object Context? should be replaced by Any? in the navigator.register function

Must call designated initializer of the superclass

I've implemented the protocol URLNavigable in a BaseClass of mine which is inherited by all my ViewControllers. However when compiling the project it throws me the error Must call designated initializer of the superclass BaseViewController.
I don't really get whats the designated it wants me to implement. Do you know what I am missing?

Thanks.

Present with custom navigation controller

First off thank you for making such a useful library. It has saved me and my team a lot of time.

Our application uses a custom subclass of UINavigationController. I wanted to see if there are any plans to be able to specify the navigation controller to use for wrapping when calling present.

Our current work around is to use open similar to the storyboard work around, however we lose the ability to use the Navigable protocol.

Remove `scheme` requirement

My app supports routing with multiple schemes (eg. myapp://, othertarget:// & https://), and I would like for the same URLOpenHandler to be called, no matter the scheme. I'm trying to migrate from JLRoutes (which can handle this), and coming up against the roadblock of the "Either matcher or URL should have scheme: '\(url)'" assertion in URLMatcher.

The way I would have assumed, and hoped, it would work is that if no scheme is provided when building the map, it is assumed to be a universal route and is matched no-matter the input URL's scheme (but if a scheme is provided in the map pattern, or the scheme property is set on URLNavigator, it is only matched when that scheme is input).

I understand that this would change expected behaviour for people already using the framework, but think it'd be a great addition to the project.

In the meantime, or if you dont feel it fits the goals of your work, do you have any suggestions as to how best to solve this problem otherwise? I guess mutating the input-URL's scheme to always be a primary scheme just before it is passed to the open(url:) method might work, but seems rather hacky.

Thanks!

Global fallback router

  • I want a fallback router such as 'shceme://*', and when all the others can't match, this handler be called
  • so that i can present a viewcontroller to show something like Comming Soon ~ and do analytics, any build in support for this ?

:D

instantiate viewcontroller from storyboard rather than init?

I'm pretty new to swift and ios development.

here is my scenario:

in the Home controller, user clicks a post and goes to Post controller.

Navigator.pushURL(postUrl) is triggerd in Home Controller.

I have a connected outlet UIWebView in Post view controller.

the outlet is nil according to xcode debug console once pushed to Post controller.

from SO http://stackoverflow.com/questions/25379616/uiviewcontroller-alloc-and-init-vs-instantiate

it should instantiate the Post controller from storyboard so that the outlet will be configured automatically.

Is there any workaround to achieve this?

Using URLNavigator with ObjC files

Can anyone please confirm if we can use the library with files / classes written in ObjectiveC. I have used the URLNavigator library and it works perfect with Swift files but I couldn't make it work with ObjectiveC files. if convenient can anyone mention the code ( a screenshot would work ) of the class in which protocol of URLNavigator is implemented and the VC is pushed or presented using URLNavigator. Thanks a lot !

Facing memory leaks while using URLOpenHandler

I think we are using a singleton inside a closure which results in a memory leak. In addition to that there are other leaks as well.

Navigator.map("http://first") { [unowned self] _ in
            let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "first") as! FirstViewController
            Navigator.push(vc)
            return true
        }

image

Construct navigation stack

When opening the app from a deeplink that references a viewcontroller that is 2, 3.. views deep in a UINavigationController stack, how do you build up the stack? In the included repo example if you do a cold start from safari using navigator://user/devxoul url, the user can never get back to the user list.

can't worked if use navigationdrawercontroller

    let leftViewController = SecondViewController()
    let appBottomNavigationController = AppBottomNavigationController(viewControllers: [navHome,navTeachingResearch,navSignUp,navStudio,navMicroClass])
    window!.rootViewController = AppBottomNavigationController(viewControllers: [navHome,navTeachingResearch,navSignUp,navStudio,navMicroClass])    //success
    //window!.rootViewController = AppNavigationDrawerController(rootViewController: appBottomNavigationController, leftViewController: leftViewController)     //can't worked,push
    window!.makeKeyAndVisible()
    URLNavigationMap.initialize()

Type does not conform to Protocol 'URLConvertible'

When I imported the Library along with the file exactly as implemented in the Example project - I got these errors in URLConvertible.swift file. Can anyone please look into. Try google-ing a lot but couldn't find any solution.

Type 'String' does not conform to protocol 'URLConvertible'

Type 'URL' does not conform to protocol 'URLConvertible'

Can't Ingegration with carthage of the swift4.0.3 version.

I integration with carthage.
The cart Cartfile is below:

github "devxoul/URLNavigator"

And run:

carthage update --platform ios

It has error below:

*** Skipped installing URLNavigator.framework binary due to the error:
"Incompatible Swift version - framework was built with 4.0 (swiftlang-900.0.65 clang-900.0.37) and the local version is 4.0.3 (swiftlang-900.0.74.1 clang-900.0.39.2)."

And I download the newest release framework, it has the same tips.

A few questions

  1. Is it possible to support multiple Navigation map?
  2. How to pass object when map the storyboard?
  3. Is it possible for customized animation in push, present, open?

Thanks.

Add Swift 3 Compatibility

With the upcoming release of Swift 3 (and the newly introduced incompatibility to Swift 2.2 and older in Xcode 8) it would be great to have a separate branch with Swift 3 compatibility.

Please consider also adding a Swift 2.3 branch for people who can’t migrate to Swift 3, because of other dependencies.

Needs an example project

Hi,

Please consider adding a sample project showcasing at least the basic usage of the library. It will be really helpful.

Thanks!

Crashed

iOS 11,iPhone 8 Plus

  1. create project

  2. Main.storyboard
    image

  3. button clicked

@IBAction func push(sender: UIButton) {
    let vc = UIViewController()
    navigator.push(vc)
}

The third time clicked button,100% crashed!!!

2.0.1 has this issue,2.0.0 no

Request: Check if route is valid/mapped

It would be nice to test a route "foo://bar" so we know it is has been mapped:

Maybe?

// In URLNavigator.swift
// Return true if route is found
open func map(_ urlPattern: URLConvertible) -> Bool {
    let URLString = URLMatcher.default.normalized(urlPattern, scheme: self.scheme).urlStringValue
    return self.urlMap[URLString] != nil ? true : (self.urlOpenHandlers[URLString] != nil ? true : false)
}

Protocol Conform issue

When I implemented protocol in my ViewController I got this error. can someone please assist. I have checked the demo projects and the initializers are mentioned directly inside the class.

  • 'required' initializer must be declared directly in class 'MotorViewController' (not in an extension)

  • 'Initializer requirement 'init(navigation:)' can only be satisfied by a required initializer in the definition of non-final class 'MotorViewController'

http://imgur.com/4u51uuw

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.