Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Traffic plugin #9

Merged
merged 44 commits into from
Sep 19, 2017
Merged

[WIP] Traffic plugin #9

merged 44 commits into from
Sep 19, 2017

Conversation

jmkiley
Copy link
Contributor

@jmkiley jmkiley commented Aug 31, 2017

To Do:

  • Add method to add traffic layer above another layer.
  • Cleanup code.
    - [ ] Carthage.
  • Read me/instructions for how to use.
  • Have others test out installation.

@friedbunny
Copy link

Initial notes as I tried out the demo app in the repo:

  • Need to carthage bootstrap.
  • Need to create mapbox_access_token.
  • mapbox-plugins-ios/Funhouse/Info.plist': The file “Info.plist” couldn’t be opened because there is no such file.
  • There is no scheme with the same name as the Funhouse target — it appears to be called MapboxPlugins.
  • The test app effectively has three names — TestApp, Funhouse, and MapboxPlugins.
  • If the traffic layer isn’t available until ~z10, we should make a note of that (otherwise folks will load the thing and think it’s not working).

@jmkiley
Copy link
Contributor Author

jmkiley commented Aug 31, 2017

TY! I missed a few things when I was renaming from Funhouse -> TestApp. Working on catching everything now.

@jmkiley jmkiley self-assigned this Aug 31, 2017
.gitignore Outdated
@@ -5,6 +5,6 @@ xcuserdata
*.moved-aside
*.xcuserstate
*.xcscmblueprint
mapbox_access_token

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hrm, I think mapbox_access_token still needs to be ignored, it’s just that creating the file is a necessary step towards getting the demo app working.

@jmkiley
Copy link
Contributor Author

jmkiley commented Aug 31, 2017

@friedbunny found an issue where the Mapbox framework isn't visible when you install through CocoaPods. I am working on fixing that now.

@jmkiley
Copy link
Contributor Author

jmkiley commented Aug 31, 2017

I think I resolved the Module not found issue in 5302a40. I changed @import Mapbox; to #import <Mapbox-iOS-SDK/Mapbox/Mapbox.h>. 🤞


// Default method to add traffic layers
- (void)addToMapView:(MGLMapView *)mapView {
MGLSymbolStyleLayer *symbolLayer = [mapView.style layerWithIdentifier:@"poi-scalerank3"];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noticing a warning from here in an application project that uses this branch. The result of the call to layerWithIdentifier needs to be cast to a MGLSymbolStyleLayer (if it safely can be) to avoid the warning.

@jmkiley
Copy link
Contributor Author

jmkiley commented Aug 31, 2017

Currently running into issues with using the Traffic Plugin in the TestApp, but it seems to be working via CocoaPods. Going to work on Carthage integration, then on fixing TestApp.

@jmkiley
Copy link
Contributor Author

jmkiley commented Sep 11, 2017

I think I've addressed most, if not all, of @friedbunny and @1ec5's feedback!

@jmkiley
Copy link
Contributor Author

jmkiley commented Sep 13, 2017

I think this is ready for re-review 😬

@friedbunny
Copy link

If you re-record trafficplugin.gif using v3.7.0 or master, the map styles will smoothly transition (instead of flashing and completely redrawing).

Copy link

@friedbunny friedbunny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that we’ve git-ignored mapbox_access_token and the build folder and its products, but the files themselves should also be removed from this PR.

@@ -0,0 +1,5 @@
extern const unsigned char TrafficPluginVersionString[];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

De-commit the build folder.

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete build products, such as the framework and its dSYM.

.gitignore Outdated
@@ -1,10 +1,12 @@
.DS_Store

TrafficPlugin.framework
TrafficPlugin.build

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps make these more generic, so that future plugins can benefit.

# the deployment target. You can optionally include the target after the platform.
#

s.platform = :ios, "10.0"
Copy link

@friedbunny friedbunny Sep 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless there’s an insurmountable technical limitation, this project should support the same platforms as the maps SDK itself (which works back to iOS 8).

Copy link

@friedbunny friedbunny Sep 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deployment target for this project is also currently set to iOS 10.

README.md Outdated

Test out Mapbox Plugins in the TestApp.

1. Run `carthage bootstrap` to install the Mapbox iOS SDK.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the current flow to use the test app? This PR checks in a Podfile and Podfile.lock, which should be deleted if we’re recommending Carthage for this purpose.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Carthage is the current flow, there should be a Cartfile.resolved.

README.md Outdated

Test out Mapbox Plugins in the TestApp.

1. Run `carthage bootstrap` to install the Mapbox iOS SDK.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we’re using CocoaPods for the test app, this is what happens:

$ pod install
Analyzing dependencies
Downloading dependencies
Using Mapbox-iOS-SDK (3.6.2)
Generating Pods project
Integrating client project
Sending stats
Pod installation complete! There is 1 dependency from the Podfile and 1 total pod installed.

[!] Automatically assigning platform ios with version 10.0 on target PluginKit because no platform was specified. Please specify a platform for this target in your Podfile. See `https://guides.cocoapods.org/syntax/podfile.html#platform`.

[!] Automatically assigning platform ios with version 10.0 on target TestApp because no platform was specified. Please specify a platform for this target in your Podfile. See `https://guides.cocoapods.org/syntax/podfile.html#platform`.

[!] Automatically assigning platform ios with version 10.0 on target TrafficPlugin because no platform was specified. Please specify a platform for this target in your Podfile. See `https://guides.cocoapods.org/syntax/podfile.html#platform`.

[!] The Podfile contains framework or static library targets, for which the Podfile does not contain host targets (targets which embed the framework).
If this project is for doing framework development, you can ignore this message. Otherwise, add a target to the Podfile that embeds these frameworks to make this message go away (e.g. a test target).

[!] The `PluginKit [Debug]` target overrides the `OTHER_LDFLAGS` build setting defined in `Pods/Target Support Files/Pods-PluginKit/Pods-PluginKit.debug.xcconfig'. This can lead to problems with the CocoaPods installation
    - Use the `$(inherited)` flag, or
    - Remove the build settings from the target.

[!] The `PluginKit [Release]` target overrides the `OTHER_LDFLAGS` build setting defined in `Pods/Target Support Files/Pods-PluginKit/Pods-PluginKit.release.xcconfig'. This can lead to problems with the CocoaPods installation
    - Use the `$(inherited)` flag, or
    - Remove the build settings from the target.

[!] The `TrafficPlugin [Debug]` target overrides the `FRAMEWORK_SEARCH_PATHS` build setting defined in `Pods/Target Support Files/Pods-TrafficPlugin/Pods-TrafficPlugin.debug.xcconfig'. This can lead to problems with the CocoaPods installation
    - Use the `$(inherited)` flag, or
    - Remove the build settings from the target.

[!] The `TrafficPlugin [Release]` target overrides the `FRAMEWORK_SEARCH_PATHS` build setting defined in `Pods/Target Support Files/Pods-TrafficPlugin/Pods-TrafficPlugin.release.xcconfig'. This can lead to problems with the CocoaPods installation
    - Use the `$(inherited)` flag, or
    - Remove the build settings from the target.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And then TestApp doesn’t compile:

screen shot 2017-09-14 at 1 37 15 pm

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Think I fixed this 🙇‍♀️ Working on cleaning up the other files now.

s.description = "Add plugins to your Mapbox basemaps. Mapbox Plugins allow you to add a traffic layer to your maps."

s.homepage = "https://github.com/mapbox/mapbox-plugins-ios/"
# s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use trafficplugin.gif here for now.

# * Try to keep it short, snappy and to the point.
# * Write the description between the DESC delimiters below.
# * Finally, don't worry about the indent, CocoaPods strips it!
s.description = "Add plugins to your Mapbox basemaps. Mapbox Plugins allow you to add a traffic layer to your maps."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add plugins to your Mapbox basemaps. Each plugin is packaged as a subspec. At the moment, the following plugin is available:

* “Traffic” adds traffic congestion layers to a map view.

# the deployment target. You can optionally include the target after the platform.
#

s.platform = :ios, "8.0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Believe it or not, I think the code in PluginKit and Traffic would also compile just fine on macOS with the Mapbox-macOS-SDK pod. Not sure if there’s a way to specify different dependencies based on the platform, though.

// Default method to add traffic layers
- (void)addToMapView:(MGLMapView *)mapView {
for (MGLStyleLayer *layer in mapView.style.layers.reverseObjectEnumerator) {
if (![layer isKindOfClass:[MGLSymbolStyleLayer class]]) {
Copy link
Contributor

@1ec5 1ec5 Sep 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the algorithm outlined in #9 (comment) would be more robust. Among the things that would go under the traffic lines with this implementation are route lines and other shape sources. Traffic lines are so closely associated with roads that we should try to keep them as close as possible to the road layers in the layer stack.

blue:0
alpha:1]]
};
_trafficColor = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeCategorical sourceStops:stopsDictionary attributeName:@"congestion" options:@{MGLStyleFunctionOptionDefaultValue : [MGLStyleValue valueWithRawValue:[UIColor greenColor]]}];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dispatch_once block ensures that this line only executes once. But _trafficColor is an ivar, so if the developer creates multiple instances of MBXTrafficPlugin for some reason, those subsequent instances will be nonfunctional. Since all the instances of MBXTrafficPlugin should have the same color value, _trafficColor should be a global variable.

}

// MARK: Add three traffic layers
// Adds motorway, motorway-link, and trunk layer.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: motorway_link.


// MARK: Add three traffic layers
// Adds motorway, motorway-link, and trunk layer.
- (void)addMotorwayLayerTo:(MGLMapView *)mapView below:(BOOL)below style:(MGLStyleLayer *)layer {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While it’s good form in Swift to end an argument label with a preposition, the standard style in Objective-C to end each selector piece with a noun describing the parameter: -addMotorwayLayerToMapView:below:styleLayer: (or, ideally, -addMotorwayLayerToMapView:positioned:relativeToStyleLayer:, with positioned being an above/below enumeration).

// MARK: Traffic Layer Removal
- (void)removeFromMapView:(MGLMapView *)mapView {

for (MGLStyleLayer *layer in mapView.style.layers) if ([layer isKindOfClass:[MGLLineStyleLayer class]] && [((MGLLineStyleLayer *)layer).sourceIdentifier isEqualToString:@"traffic-source"]) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put the if on a separate line and use curly braces.

// MARK: Traffic Layer Removal
- (void)removeFromMapView:(MGLMapView *)mapView {

for (MGLStyleLayer *layer in mapView.style.layers) if ([layer isKindOfClass:[MGLLineStyleLayer class]] && [((MGLLineStyleLayer *)layer).sourceIdentifier isEqualToString:@"traffic-source"]) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, it’s a bit fast-and-loose, but a trick I employ to make Objective-C casts more readable relies on weak typing:

for (MGLLineStyleLayer *layer in mapView.style.layers) {
    if ([layer isKindOfClass:[MGLLineStyleLayer class]] && [layer.sourceIdentifier isEqualToString:…]) {
        …
    }
}

To be clear, there’s nothing wrong with the way you used a C cast on layer. Just thought I’d throw this tip out there.

// Add traffic source to map style.
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_source = [[MGLVectorSource alloc] initWithIdentifier:@"traffic-source" configurationURL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-traffic-v1"]];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It’s conceivable that the developer may’ve already added a traffic source to the map with the identifier traffic-source. Adding another source with that same identifier could lead to undefined behavior. Consider prefixing the layer identifiers with this plugin framework’s bundle identifier, which you can either hard-code or determine programmatically.


extern MGLStyleValue *trafficColor;

@interface MBXTrafficPlugin : NSObject <MBXPlugin>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class needs a documentation comment.

#import <Foundation/Foundation.h>
#import <Mapbox/Mapbox.h>

extern MGLStyleValue *trafficColor;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to expose this value publicly in the header. Instead, move this declaration to the source file. In the source file, you won’t need extern, but consider using static.


s.subspec 'PluginKit' do |core|
core.source_files = 'PluginKit/*.h'
core.dependency 'Mapbox-iOS-SDK'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should specify a minimum version of any dependency. v3.6 is a reasonable minimum, given that the traffic plugin uses the camera and style function syntaxes introduced in that version.

- (void) setupPropertiesFor:(MGLMapView *)mapView {
// Add traffic source to map style.
if (_source == nil) {
_sourceIdentifier = [NSString stringWithFormat:@"%@-traffic-source", [[NSBundle mainBundle] bundleIdentifier]];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+[NSBundle mainBundle] returns the main bundle, so when this code runs as part of an application, the bundle identifier will be that application’s bundle identifier, like com.example.MyApp. In the iOS SDK, we use a canary class to get the right bundle – in this case, that class can be MBXTrafficPlugin. (No need to include the rest of that iOS SDK method, which is specific to static libraries.)

// Adds motorway, motorway_link, and trunk layer.
- (void)addMotorwayLayerTo:(MGLMapView *)mapView below:(BOOL)below style:(MGLStyleLayer *)layer {

MGLLineStyleLayer *motorwayLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"mbx-traffic-motorway-layer" source:_source];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency, consider prefixing with the framework’s bundle identifier, as with the source identifier above.

# This description is used to generate tags and improve search results.
s.description = "Add plugins to your Mapbox basemaps. Each plugin is packaged as a subspec. At the moment, the following plugin is available:
* “Traffic” adds traffic congestion layers to a map view."
s.homepage = "https://github.com/mapbox/mapbox-plugins-ios/"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can specify trafficplugin.gif as s.screenshots, unless there’s a better screenshot to use here. s.screenshots requires a URL to an image that exists on a server. So we can use the raw URL to the image on GitHub, but make sure to use a permalink, ideally with the tag in the URL (example).

@friedbunny friedbunny dismissed their stale review September 15, 2017 21:25

:thumbs-up:

@jmkiley
Copy link
Contributor Author

jmkiley commented Sep 16, 2017

Addressed the feedback @1ec5! Thank you so much.

Copy link
Contributor

@1ec5 1ec5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting close! In addition to the unresolved feedback in #9 (review), here are a few more comments.

s.homepage = "https://github.com/mapbox/mapbox-plugins-ios/"

s.screenshot = 'https://github.com/mapbox/mapbox-plugins-ios/blob/master/TrafficPlugin/trafficplugin.gif'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will need to be a URL to a raw image, not its HTML description page. I think it’ll be:

https://raw.githubusercontent.com/mapbox/mapbox-plugins-ios/master/TrafficPlugin/trafficplugin.gif

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, missed the previous feedback. Thanks!

- (void)addToMapView:(MGLMapView *)mapView above:(MGLStyleLayer *)layer {
[self setupPropertiesFor:mapView];

// Consolidate to one layer once lineWidth supports DDS.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turn this into a TODO so we can more easily find it once we start requiring iOS SDK v3.7.0-alpha.1 and above. Might be worth opening a ticket too.

[self setupPropertiesFor:mapView];

// Consolidate to one layer once lineWidth supports DDS.
[self addMotorwayLayerTo:mapView positioned:NO relativeTo:layer];
Copy link
Contributor

@1ec5 1ec5 Sep 16, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

positioned:YES and positioned:NO sound a bit awkward. I previously suggested making an enumeration consisting of the cases Above and Below, but on second thought, we can remove the complexity around these methods by extracting out the actual insertion. Rename -addMotorwayLayerTo:positioned:relativeTo: to just -motorwayLayer and remove the calls to -insertLayer:{above,below}Layer:. Instead, have the method return the MGLStyleLayer and call the method like this:

[mapView.style insertLayer:self.primaryLayer above:layer];

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. Implemented it and it does look cleaner, thanks!


@property (nonatomic, retain) MGLVectorSource *source;
@property (nonatomic, retain) MGLStyleValue *trafficColor;
@property (nonatomic, retain) NSString *bundleIdentifier;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

retain is a bit archaic; strong is more consistent with ARC. strong is the default, anyhow, so there doesn’t need to be a second qualifier for any of these properties.

@jmkiley
Copy link
Contributor Author

jmkiley commented Sep 18, 2017

I think I addressed the latest suggestions, @1ec5. Thank you so much for your suggestions 🙇‍♀️

* “Traffic” adds traffic congestion layers to a map view.
Mapbox Plugins require version 3.6 of the Mapbox iOS SDK or higher."
s.homepage = "https://github.com/mapbox/mapbox-plugins-ios/"
s.screenshot = 'https://raw.githubusercontent.com/mapbox/mapbox-plugins-ios/master/TrafficPlugin/trafficplugin.gif'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To keep this URL from going 404 if we ever change the path, let’s replace master with a tag name. Supposing we tag v0.0.1 as v0.0.1, the URL would be https://raw.githubusercontent.com/mapbox/mapbox-plugins-ios/v0.0.1/TrafficPlugin/trafficplugin.gif. We can automate that by interpolating a variable:

s.screenshot = "https://raw.githubusercontent.com/mapbox/mapbox-plugins-ios/v#{s.version}/TrafficPlugin/trafficplugin.gif"



/**
MBXTrafficPlugin adds a traffic congestion layer to Mapbox basemaps. For more information about Mapbox Traffic vector tile source, see https://www.mapbox.com/vector-tiles/mapbox-traffic-v1/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Objective-C, use HTML or Markdown syntax for links in documentation comments:

For more information about the data powering this layer, see [the Mapbox Traffic source documentation](https://www.mapbox.com/vector-tiles/mapbox-traffic-v1/).

@interface MBXTrafficPlugin : NSObject <MBXPlugin>

/**
Add traffic to a MGLMapView. This method inserts the traffic layer above the road layer. See the Mapbox Vector Tile Source layer reference (https://www.mapbox.com/vector-tiles/mapbox-streets-v7/#layer-reference) for more information about vector tile layers.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The linked documentation pertains to the Mapbox Streets source specifically, not the Mapbox Vector Tile format generally:

This method inserts the traffic layer immediately above the road layers if the style is based on the Mapbox Streets source. For more fine-grained control over the position of the traffic layers, use the -addToMapView:belowLayer: or -addToMapView:aboveLayer: method.

@param mapView The map view that traffic will be displayed on.
@param layer The style layer that traffic will be inserted below. Use the `layers` property on a style to verify layer identifiers.
*/
- (void)addToMapView:(MGLMapView *)mapView below:(MGLStyleLayer *)layer;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad, I should’ve written -addToMapView:belowLayer:.

@param mapView The map view that traffic will be displayed on.
@param layer The style layer that traffic will be inserted below. Use the `layers` property on a style to verify layer identifiers.
*/
- (void)addToMapView:(MGLMapView *)mapView above:(MGLStyleLayer *)layer;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise, -addToMapView:aboveLayer:.


@implementation MBXTrafficPlugin

static MGLStyleValue *_trafficColor;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A static global variable isn’t part of a class, so move this declaration to the top of the file, right under the import statement. Also, remove the _ and prefix it with the class name, since it’s no longer an internal variable but is still meant for use with that class: MBXTrafficPluginColorStyleValue.

@interface MBXTrafficPlugin ()

@property (nonatomic) MGLVectorSource *source;
@property (nonatomic) MGLStyleValue *trafficColor;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This property is no longer used.

return motorwayLayer;
}

// Styless primary, secondary, and tertiary road layer.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: “Styles the”. Wouldn’t hurt to make this a documentation comment, even if it’s a private method, since Quick Help can still read these comments when you’re working on this file.

@jmkiley jmkiley merged commit 0c60b57 into 1ec5-project Sep 19, 2017
@jmkiley jmkiley deleted the traffic-plugin branch September 19, 2017 18:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants