{"action":"created","comment":{"url":"https://api.github.com/repos/dropwizard/dropwizard/pulls/comments/211034167","pull_request_review_id":147383140,"id":211034167,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIxMTAzNDE2Nw==","diff_hunk":"@@ -0,0 +1,236 @@\n+package io.dropwizard.logging;\n+\n+import static org.assertj.core.api.Assertions.assertThat;\n+import static org.assertj.core.api.Assertions.assertThatThrownBy;\n+\n+import java.io.ByteArrayOutputStream;\n+import java.io.File;\n+import java.io.PrintStream;\n+import java.io.UnsupportedEncodingException;\n+import java.net.URISyntaxException;\n+import java.nio.charset.StandardCharsets;\n+import java.util.Arrays;\n+import java.util.Collections;\n+import java.util.HashMap;\n+import java.util.concurrent.CountDownLatch;\n+import java.util.concurrent.TimeUnit;\n+\n+import javax.annotation.Nullable;\n+\n+import org.apache.commons.text.StrSubstitutor;\n+import org.assertj.core.api.Condition;\n+import org.junit.After;\n+import org.junit.Before;\n+import org.junit.Test;\n+import org.slf4j.Logger;\n+import org.slf4j.LoggerFactory;\n+\n+import com.codahale.metrics.MetricRegistry;\n+import com.google.common.util.concurrent.RateLimiter;\n+\n+import ch.qos.logback.classic.spi.ILoggingEvent;\n+import io.dropwizard.configuration.ConfigurationValidationException;\n+import io.dropwizard.configuration.FileConfigurationSourceProvider;\n+import io.dropwizard.configuration.SubstitutingSourceProvider;\n+import io.dropwizard.configuration.YamlConfigurationFactory;\n+import io.dropwizard.jackson.Jackson;\n+import io.dropwizard.util.Duration;\n+import io.dropwizard.validation.BaseValidator;\n+\n+public class ThrottlingAppenderWrapperTest {\n+\n+    // Test Constants:\n+    private static final String LINE_SEPERATOR = System.getProperty(\"line.separator\");\n+    private static final double NANOS_PER_SECOND = TimeUnit.SECONDS.toNanos(1L);\n+\n+    // Test defaults:\n+    private static final int WRITE_LINES = 100;\n+    private static final Duration RUN_WINDOW = Duration.seconds(1);\n+\n+    // Test helpers:\n+    private static final String APP_LOG_PREFIX = \"Application log\";\n+    private static final Condition<String> APP_LOG_CONDITION = new Condition<>(o -> o.contains(APP_LOG_PREFIX), \"contains application log\");\n+\n+    // Asynchronous timeouts\n+    private static final Duration LOG_WAIT = Duration.seconds(90);\n+\n+    @SuppressWarnings(\"rawtypes\")\n+    private final YamlConfigurationFactory<ConsoleAppenderFactory> factory;\n+    private final ByteArrayOutputStream bos;\n+\n+    @Nullable\n+    private PrintStream oldSysOut;\n+\n+    @Nullable\n+    private PrintStream newSysOut;\n+\n+    public ThrottlingAppenderWrapperTest() {\n+        super();\n+        this.oldSysOut = null;\n+        this.bos = new ByteArrayOutputStream();\n+\n+        this.factory = new YamlConfigurationFactory<>(\n+            ConsoleAppenderFactory.class,\n+            BaseValidator.newValidator(),\n+            Jackson.newObjectMapper(),\n+            \"dw\");\n+    }\n+\n+    @Before\n+    public void setup() throws UnsupportedEncodingException {\n+        this.oldSysOut = System.out;\n+        // This forces auto-flush, which should help with buffering issues\n+        this.newSysOut = new PrintStream(this.bos, true, StandardCharsets.UTF_8.name());\n+        System.setOut(this.newSysOut);\n+    }\n+\n+    @After\n+    public void teardown() {\n+        if (this.oldSysOut != null) {\n+            System.setOut(this.oldSysOut);\n+        }\n+\n+        if (this.newSysOut != null) {\n+            this.newSysOut.close();\n+        }\n+\n+        this.bos.reset();\n+    }\n+\n+    @Test\n+    public void appenderWithZeroMessageRate() {\n+        assertThatThrownBy(() -> this.factory.build(this.findResource(\"/yaml/appender_with_zero_message_rate.yml\")))\n+            .isInstanceOf(ConfigurationValidationException.class)\n+            .hasMessageContaining(\"messageRate must be greater than 0 SECONDS\");\n+    }\n+\n+    @Test\n+    public void appenderWithInvalidMessageRate() {\n+        assertThatThrownBy(() -> this.factory.build(this.findResource(\"/yaml/appender_with_invalid_message_rate.yml\")))\n+            .isInstanceOf(ConfigurationValidationException.class)\n+            .hasMessageContaining(\"messageRate must be less than or equal to 1 MINUTES\");\n+    }\n+\n+    @Test\n+    public void overThrottlingLimit() throws Exception {\n+        this.runLineTest(Duration.milliseconds(100), WRITE_LINES, RUN_WINDOW);\n+    }\n+\n+    @Test\n+    public void belowThrottlingLimit() throws Exception {\n+        this.runLineTest(Duration.microseconds(1), WRITE_LINES, RUN_WINDOW);\n+    }\n+\n+    private void runLineTest(final Duration messageRate, final int lineCount, final Duration runWindow) throws Exception {\n+        final HashMap<String, Object> variables = new HashMap<>();\n+        variables.put(\"messageRate\", messageRate);\n+\n+        @SuppressWarnings(\"unchecked\")\n+        final ConsoleAppenderFactory<ILoggingEvent> config = this.factory.build(\n+            new SubstitutingSourceProvider(new FileConfigurationSourceProvider(), new StrSubstitutor(variables)),\n+            this.findResource(\"/yaml/logging-message-rate.yml\").getPath());\n+\n+        final DefaultLoggingFactory defaultLoggingFactory = new DefaultLoggingFactory();\n+        defaultLoggingFactory.setAppenders(Collections.singletonList(config));\n+        defaultLoggingFactory.configure(new MetricRegistry(), \"test-logger\");\n+\n+        final Logger logger = LoggerFactory.getLogger(\"com.example.app\");\n+\n+        final long start = System.nanoTime();\n+\n+        final long rwNanos = runWindow.toNanoseconds();\n+        final double seconds = rwNanos / NANOS_PER_SECOND;\n+\n+        // We need to subtract 1 as we automatically get one at time zero; how\n+        // long should the remaining take?\n+        final double limit = (lineCount - 1) / seconds;\n+\n+        final RateLimiter rateLimiter = RateLimiter.create(limit);\n+        for (int i = 0; i < lineCount; i++) {\n+            rateLimiter.acquire();\n+            logger.info(\"{} {}\", APP_LOG_PREFIX, i);\n+        }\n+\n+        final long elapsed = System.nanoTime() - start;\n+\n+        // We need to sleep for at least message duration to ensure our line\n+        // will be written and thus invoke the countdown on the latch.\n+        Thread.sleep(messageRate.toMilliseconds() + 1L);\n+\n+        final LogWait lwait = new LogWait(1);\n+        logger.info(\"Log termination {}\", lwait);\n+        assertThat(lwait.block(LOG_WAIT.toNanoseconds(), TimeUnit.NANOSECONDS)).isTrue();\n+\n+        // Force logger to flush\n+        defaultLoggingFactory.stop();\n+\n+        // Force streams to flush. NullAway doesn't understand that if we made\n+        // it here, these can't be null. C'est la vie.\n+        if (this.newSysOut != null) {\n+            this.newSysOut.flush();\n+        }\n+\n+        final byte[] rawBuffer = this.bos.toByteArray();\n+\n+        final String strBuffer = new String(rawBuffer, StandardCharsets.UTF_8);\n+        final String[] logArray = strBuffer.split(LINE_SEPERATOR);\n+\n+        final long mrNanos = messageRate.toNanoseconds();\n+\n+        // Note that when we write slower than our threshold, more intervals\n+        // will elapse than we have lines, thus we need a Math.min guard rail so\n+        // our tests function.\n+        final double messagesPerWindow = (double) rwNanos / (double) mrNanos;\n+\n+        // We add 1 as we get an automatic message at time zero\n+        final int low = Math.min((int) messagesPerWindow, lineCount);\n+\n+        // How many durations did we cover (i.e how many log lines do we expect\n+        // worst case host performance)\n+        final double intervals = (double) elapsed / (double) mrNanos;\n+\n+        // If we had a fractional interval, round up instead of down. We have to\n+        // add one regardless as at full speed, we end up with 1 + executed\n+        // intervals as an event fires at time zero.\n+        int high = (int) intervals;\n+        if ((intervals - high > 0d)) {","path":"dropwizard-logging/src/test/java/io/dropwizard/logging/ThrottlingAppenderWrapperTest.java","position":196,"original_position":196,"commit_id":"2466a393bd63c1e45ef9eb4d1f2de4fb29280737","original_commit_id":"2466a393bd63c1e45ef9eb4d1f2de4fb29280737","user":{"login":"nickbabcock","id":2106129,"node_id":"MDQ6VXNlcjIxMDYxMjk=","avatar_url":"https://avatars1.githubusercontent.com/u/2106129?v=4","gravatar_id":"","url":"https://api.github.com/users/nickbabcock","html_url":"https://github.com/nickbabcock","followers_url":"https://api.github.com/users/nickbabcock/followers","following_url":"https://api.github.com/users/nickbabcock/following{/other_user}","gists_url":"https://api.github.com/users/nickbabcock/gists{/gist_id}","starred_url":"https://api.github.com/users/nickbabcock/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nickbabcock/subscriptions","organizations_url":"https://api.github.com/users/nickbabcock/orgs","repos_url":"https://api.github.com/users/nickbabcock/repos","events_url":"https://api.github.com/users/nickbabcock/events{/privacy}","received_events_url":"https://api.github.com/users/nickbabcock/received_events","type":"User","site_admin":false},"body":"Can this be written more straightforward with something like `Math.ceil`? a la\r\n\r\n```java\r\nint high = (int)Math.ceil(intervals) + 1\r\n```\r\n","created_at":"2018-08-17T21:14:14Z","updated_at":"2018-08-17T21:14:14Z","html_url":"https://github.com/dropwizard/dropwizard/pull/2458#discussion_r211034167","pull_request_url":"https://api.github.com/repos/dropwizard/dropwizard/pulls/2458","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/dropwizard/dropwizard/pulls/comments/211034167"},"html":{"href":"https://github.com/dropwizard/dropwizard/pull/2458#discussion_r211034167"},"pull_request":{"href":"https://api.github.com/repos/dropwizard/dropwizard/pulls/2458"}}},"pull_request":{"url":"https://api.github.com/repos/dropwizard/dropwizard/pulls/2458","id":209232928,"node_id":"MDExOlB1bGxSZXF1ZXN0MjA5MjMyOTI4","html_url":"https://github.com/dropwizard/dropwizard/pull/2458","diff_url":"https://github.com/dropwizard/dropwizard/pull/2458.diff","patch_url":"https://github.com/dropwizard/dropwizard/pull/2458.patch","issue_url":"https://api.github.com/repos/dropwizard/dropwizard/issues/2458","number":2458,"state":"open","locked":false,"title":"Rewrite of throttling logging appender testing","user":{"login":"isaki-x","id":10616227,"node_id":"MDQ6VXNlcjEwNjE2MjI3","avatar_url":"https://avatars2.githubusercontent.com/u/10616227?v=4","gravatar_id":"","url":"https://api.github.com/users/isaki-x","html_url":"https://github.com/isaki-x","followers_url":"https://api.github.com/users/isaki-x/followers","following_url":"https://api.github.com/users/isaki-x/following{/other_user}","gists_url":"https://api.github.com/users/isaki-x/gists{/gist_id}","starred_url":"https://api.github.com/users/isaki-x/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/isaki-x/subscriptions","organizations_url":"https://api.github.com/users/isaki-x/orgs","repos_url":"https://api.github.com/users/isaki-x/repos","events_url":"https://api.github.com/users/isaki-x/events{/privacy}","received_events_url":"https://api.github.com/users/isaki-x/received_events","type":"User","site_admin":false},"body":"- Renamed test class to match the class it is testing\r\n(ThrottlingAppenderWrapper).\r\n- Rewrote class to play nicer with slower processing and to improve long\r\nterm supportability.\r\n- Relied on system property for line seperation instead of hardcoded\r\nregex.\r\n- Removed unused imports (and in the class being tested as well).\r\n\r\n###### Problem:\r\nThe current unit test relies on wall clock timings which can cause issues during CI builds on slow machines.\r\n\r\n###### Solution:\r\nI've done my best to eliminate wall clock where possible and added calculations where that wasn't possible to dynamically calculate the expected result for slow machines.\r\n\r\n###### Result:\r\nThe tests should be far more reliable.","created_at":"2018-08-17T19:06:30Z","updated_at":"2018-08-17T21:14:14Z","closed_at":null,"merged_at":null,"merge_commit_sha":"3f50da3b0416f9b147161ff6428c4292c64aba98","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":656449,"node_id":"MDU6TGFiZWw2NTY0NDk=","url":"https://api.github.com/repos/dropwizard/dropwizard/labels/improvement","name":"improvement","color":"0b02e1","default":false}],"milestone":{"url":"https://api.github.com/repos/dropwizard/dropwizard/milestones/18","html_url":"https://github.com/dropwizard/dropwizard/milestone/18","labels_url":"https://api.github.com/repos/dropwizard/dropwizard/milestones/18/labels","id":1958804,"node_id":"MDk6TWlsZXN0b25lMTk1ODgwNA==","number":18,"title":"2.0.0","description":null,"creator":{"login":"evnm","id":110020,"node_id":"MDQ6VXNlcjExMDAyMA==","avatar_url":"https://avatars1.githubusercontent.com/u/110020?v=4","gravatar_id":"","url":"https://api.github.com/users/evnm","html_url":"https://github.com/evnm","followers_url":"https://api.github.com/users/evnm/followers","following_url":"https://api.github.com/users/evnm/following{/other_user}","gists_url":"https://api.github.com/users/evnm/gists{/gist_id}","starred_url":"https://api.github.com/users/evnm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/evnm/subscriptions","organizations_url":"https://api.github.com/users/evnm/orgs","repos_url":"https://api.github.com/users/evnm/repos","events_url":"https://api.github.com/users/evnm/events{/privacy}","received_events_url":"https://api.github.com/users/evnm/received_events","type":"User","site_admin":false},"open_issues":9,"closed_issues":63,"state":"open","created_at":"2016-08-23T19:10:05Z","updated_at":"2018-08-17T19:25:12Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/dropwizard/dropwizard/pulls/2458/commits","review_comments_url":"https://api.github.com/repos/dropwizard/dropwizard/pulls/2458/comments","review_comment_url":"https://api.github.com/repos/dropwizard/dropwizard/pulls/comments{/number}","comments_url":"https://api.github.com/repos/dropwizard/dropwizard/issues/2458/comments","statuses_url":"https://api.github.com/repos/dropwizard/dropwizard/statuses/2466a393bd63c1e45ef9eb4d1f2de4fb29280737","head":{"label":"isaki-x:throttle_test_refactor","ref":"throttle_test_refactor","sha":"2466a393bd63c1e45ef9eb4d1f2de4fb29280737","user":{"login":"isaki-x","id":10616227,"node_id":"MDQ6VXNlcjEwNjE2MjI3","avatar_url":"https://avatars2.githubusercontent.com/u/10616227?v=4","gravatar_id":"","url":"https://api.github.com/users/isaki-x","html_url":"https://github.com/isaki-x","followers_url":"https://api.github.com/users/isaki-x/followers","following_url":"https://api.github.com/users/isaki-x/following{/other_user}","gists_url":"https://api.github.com/users/isaki-x/gists{/gist_id}","starred_url":"https://api.github.com/users/isaki-x/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/isaki-x/subscriptions","organizations_url":"https://api.github.com/users/isaki-x/orgs","repos_url":"https://api.github.com/users/isaki-x/repos","events_url":"https://api.github.com/users/isaki-x/events{/privacy}","received_events_url":"https://api.github.com/users/isaki-x/received_events","type":"User","site_admin":false},"repo":{"id":93063277,"node_id":"MDEwOlJlcG9zaXRvcnk5MzA2MzI3Nw==","name":"dropwizard","full_name":"isaki-x/dropwizard","owner":{"login":"isaki-x","id":10616227,"node_id":"MDQ6VXNlcjEwNjE2MjI3","avatar_url":"https://avatars2.githubusercontent.com/u/10616227?v=4","gravatar_id":"","url":"https://api.github.com/users/isaki-x","html_url":"https://github.com/isaki-x","followers_url":"https://api.github.com/users/isaki-x/followers","following_url":"https://api.github.com/users/isaki-x/following{/other_user}","gists_url":"https://api.github.com/users/isaki-x/gists{/gist_id}","starred_url":"https://api.github.com/users/isaki-x/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/isaki-x/subscriptions","organizations_url":"https://api.github.com/users/isaki-x/orgs","repos_url":"https://api.github.com/users/isaki-x/repos","events_url":"https://api.github.com/users/isaki-x/events{/privacy}","received_events_url":"https://api.github.com/users/isaki-x/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/isaki-x/dropwizard","description":"A damn simple library for building production-ready RESTful web services.","fork":true,"url":"https://api.github.com/repos/isaki-x/dropwizard","forks_url":"https://api.github.com/repos/isaki-x/dropwizard/forks","keys_url":"https://api.github.com/repos/isaki-x/dropwizard/keys{/key_id}","collaborators_url":"https://api.github.com/repos/isaki-x/dropwizard/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/isaki-x/dropwizard/teams","hooks_url":"https://api.github.com/repos/isaki-x/dropwizard/hooks","issue_events_url":"https://api.github.com/repos/isaki-x/dropwizard/issues/events{/number}","events_url":"https://api.github.com/repos/isaki-x/dropwizard/events","assignees_url":"https://api.github.com/repos/isaki-x/dropwizard/assignees{/user}","branches_url":"https://api.github.com/repos/isaki-x/dropwizard/branches{/branch}","tags_url":"https://api.github.com/repos/isaki-x/dropwizard/tags","blobs_url":"https://api.github.com/repos/isaki-x/dropwizard/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/isaki-x/dropwizard/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/isaki-x/dropwizard/git/refs{/sha}","trees_url":"https://api.github.com/repos/isaki-x/dropwizard/git/trees{/sha}","statuses_url":"https://api.github.com/repos/isaki-x/dropwizard/statuses/{sha}","languages_url":"https://api.github.com/repos/isaki-x/dropwizard/languages","stargazers_url":"https://api.github.com/repos/isaki-x/dropwizard/stargazers","contributors_url":"https://api.github.com/repos/isaki-x/dropwizard/contributors","subscribers_url":"https://api.github.com/repos/isaki-x/dropwizard/subscribers","subscription_url":"https://api.github.com/repos/isaki-x/dropwizard/subscription","commits_url":"https://api.github.com/repos/isaki-x/dropwizard/commits{/sha}","git_commits_url":"https://api.github.com/repos/isaki-x/dropwizard/git/commits{/sha}","comments_url":"https://api.github.com/repos/isaki-x/dropwizard/comments{/number}","issue_comment_url":"https://api.github.com/repos/isaki-x/dropwizard/issues/comments{/number}","contents_url":"https://api.github.com/repos/isaki-x/dropwizard/contents/{+path}","compare_url":"https://api.github.com/repos/isaki-x/dropwizard/compare/{base}...{head}","merges_url":"https://api.github.com/repos/isaki-x/dropwizard/merges","archive_url":"https://api.github.com/repos/isaki-x/dropwizard/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/isaki-x/dropwizard/downloads","issues_url":"https://api.github.com/repos/isaki-x/dropwizard/issues{/number}","pulls_url":"https://api.github.com/repos/isaki-x/dropwizard/pulls{/number}","milestones_url":"https://api.github.com/repos/isaki-x/dropwizard/milestones{/number}","notifications_url":"https://api.github.com/repos/isaki-x/dropwizard/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/isaki-x/dropwizard/labels{/name}","releases_url":"https://api.github.com/repos/isaki-x/dropwizard/releases{/id}","deployments_url":"https://api.github.com/repos/isaki-x/dropwizard/deployments","created_at":"2017-06-01T14:00:01Z","updated_at":"2018-08-17T19:17:58Z","pushed_at":"2018-08-17T19:32:21Z","git_url":"git://github.com/isaki-x/dropwizard.git","ssh_url":"git@github.com:isaki-x/dropwizard.git","clone_url":"https://github.com/isaki-x/dropwizard.git","svn_url":"https://github.com/isaki-x/dropwizard","homepage":"http://www.dropwizard.io","size":49851,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"dropwizard:master","ref":"master","sha":"bd8363076b8ba485c52d7f6ad0e094da0d90c03a","user":{"login":"dropwizard","id":5478557,"node_id":"MDEyOk9yZ2FuaXphdGlvbjU0Nzg1NTc=","avatar_url":"https://avatars3.githubusercontent.com/u/5478557?v=4","gravatar_id":"","url":"https://api.github.com/users/dropwizard","html_url":"https://github.com/dropwizard","followers_url":"https://api.github.com/users/dropwizard/followers","following_url":"https://api.github.com/users/dropwizard/following{/other_user}","gists_url":"https://api.github.com/users/dropwizard/gists{/gist_id}","starred_url":"https://api.github.com/users/dropwizard/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dropwizard/subscriptions","organizations_url":"https://api.github.com/users/dropwizard/orgs","repos_url":"https://api.github.com/users/dropwizard/repos","events_url":"https://api.github.com/users/dropwizard/events{/privacy}","received_events_url":"https://api.github.com/users/dropwizard/received_events","type":"Organization","site_admin":false},"repo":{"id":1272129,"node_id":"MDEwOlJlcG9zaXRvcnkxMjcyMTI5","name":"dropwizard","full_name":"dropwizard/dropwizard","owner":{"login":"dropwizard","id":5478557,"node_id":"MDEyOk9yZ2FuaXphdGlvbjU0Nzg1NTc=","avatar_url":"https://avatars3.githubusercontent.com/u/5478557?v=4","gravatar_id":"","url":"https://api.github.com/users/dropwizard","html_url":"https://github.com/dropwizard","followers_url":"https://api.github.com/users/dropwizard/followers","following_url":"https://api.github.com/users/dropwizard/following{/other_user}","gists_url":"https://api.github.com/users/dropwizard/gists{/gist_id}","starred_url":"https://api.github.com/users/dropwizard/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dropwizard/subscriptions","organizations_url":"https://api.github.com/users/dropwizard/orgs","repos_url":"https://api.github.com/users/dropwizard/repos","events_url":"https://api.github.com/users/dropwizard/events{/privacy}","received_events_url":"https://api.github.com/users/dropwizard/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/dropwizard/dropwizard","description":"A damn simple library for building production-ready RESTful web services.","fork":false,"url":"https://api.github.com/repos/dropwizard/dropwizard","forks_url":"https://api.github.com/repos/dropwizard/dropwizard/forks","keys_url":"https://api.github.com/repos/dropwizard/dropwizard/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dropwizard/dropwizard/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dropwizard/dropwizard/teams","hooks_url":"https://api.github.com/repos/dropwizard/dropwizard/hooks","issue_events_url":"https://api.github.com/repos/dropwizard/dropwizard/issues/events{/number}","events_url":"https://api.github.com/repos/dropwizard/dropwizard/events","assignees_url":"https://api.github.com/repos/dropwizard/dropwizard/assignees{/user}","branches_url":"https://api.github.com/repos/dropwizard/dropwizard/branches{/branch}","tags_url":"https://api.github.com/repos/dropwizard/dropwizard/tags","blobs_url":"https://api.github.com/repos/dropwizard/dropwizard/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dropwizard/dropwizard/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dropwizard/dropwizard/git/refs{/sha}","trees_url":"https://api.github.com/repos/dropwizard/dropwizard/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dropwizard/dropwizard/statuses/{sha}","languages_url":"https://api.github.com/repos/dropwizard/dropwizard/languages","stargazers_url":"https://api.github.com/repos/dropwizard/dropwizard/stargazers","contributors_url":"https://api.github.com/repos/dropwizard/dropwizard/contributors","subscribers_url":"https://api.github.com/repos/dropwizard/dropwizard/subscribers","subscription_url":"https://api.github.com/repos/dropwizard/dropwizard/subscription","commits_url":"https://api.github.com/repos/dropwizard/dropwizard/commits{/sha}","git_commits_url":"https://api.github.com/repos/dropwizard/dropwizard/git/commits{/sha}","comments_url":"https://api.github.com/repos/dropwizard/dropwizard/comments{/number}","issue_comment_url":"https://api.github.com/repos/dropwizard/dropwizard/issues/comments{/number}","contents_url":"https://api.github.com/repos/dropwizard/dropwizard/contents/{+path}","compare_url":"https://api.github.com/repos/dropwizard/dropwizard/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dropwizard/dropwizard/merges","archive_url":"https://api.github.com/repos/dropwizard/dropwizard/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dropwizard/dropwizard/downloads","issues_url":"https://api.github.com/repos/dropwizard/dropwizard/issues{/number}","pulls_url":"https://api.github.com/repos/dropwizard/dropwizard/pulls{/number}","milestones_url":"https://api.github.com/repos/dropwizard/dropwizard/milestones{/number}","notifications_url":"https://api.github.com/repos/dropwizard/dropwizard/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dropwizard/dropwizard/labels{/name}","releases_url":"https://api.github.com/repos/dropwizard/dropwizard/releases{/id}","deployments_url":"https://api.github.com/repos/dropwizard/dropwizard/deployments","created_at":"2011-01-19T19:52:29Z","updated_at":"2018-08-17T13:33:56Z","pushed_at":"2018-08-17T19:25:35Z","git_url":"git://github.com/dropwizard/dropwizard.git","ssh_url":"git@github.com:dropwizard/dropwizard.git","clone_url":"https://github.com/dropwizard/dropwizard.git","svn_url":"https://github.com/dropwizard/dropwizard","homepage":"https://www.dropwizard.io","size":72975,"stargazers_count":6778,"watchers_count":6778,"language":"Java","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":2898,"mirror_url":null,"archived":false,"open_issues_count":101,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":2898,"open_issues":101,"watchers":6778,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/dropwizard/dropwizard/pulls/2458"},"html":{"href":"https://github.com/dropwizard/dropwizard/pull/2458"},"issue":{"href":"https://api.github.com/repos/dropwizard/dropwizard/issues/2458"},"comments":{"href":"https://api.github.com/repos/dropwizard/dropwizard/issues/2458/comments"},"review_comments":{"href":"https://api.github.com/repos/dropwizard/dropwizard/pulls/2458/comments"},"review_comment":{"href":"https://api.github.com/repos/dropwizard/dropwizard/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/dropwizard/dropwizard/pulls/2458/commits"},"statuses":{"href":"https://api.github.com/repos/dropwizard/dropwizard/statuses/2466a393bd63c1e45ef9eb4d1f2de4fb29280737"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"nickbabcock"}}