{"action":"created","comment":{"url":"https://api.github.com/repos/cityzendata/warp10-platform/pulls/comments/212455958","pull_request_review_id":149095965,"id":212455958,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIxMjQ1NTk1OA==","diff_hunk":"@@ -39,265 +68,232 @@\n import java.util.concurrent.ExecutorService;\n import java.util.concurrent.LinkedBlockingQueue;\n import java.util.concurrent.RejectedExecutionException;\n+import java.util.concurrent.ThreadFactory;\n import java.util.concurrent.ThreadPoolExecutor;\n import java.util.concurrent.TimeUnit;\n+import java.util.concurrent.atomic.AtomicLong;\n import java.util.concurrent.locks.LockSupport;\n import java.util.zip.GZIPOutputStream;\n \n-import org.apache.thrift.TException;\n-import org.apache.thrift.TSerializer;\n-import org.apache.thrift.protocol.TCompactProtocol;\n-\n-import com.geoxp.oss.CryptoHelper;\n-import com.google.common.base.Charsets;\n-import com.google.common.base.Preconditions;\n-import com.google.common.primitives.Longs;\n-import com.netflix.curator.framework.CuratorFramework;\n-import com.netflix.curator.framework.CuratorFrameworkFactory;\n-import com.netflix.curator.framework.recipes.leader.LeaderLatch;\n-import com.netflix.curator.retry.RetryNTimes;\n-\n-import io.warp10.continuum.Configuration;\n-import io.warp10.continuum.KafkaProducerPool;\n-import io.warp10.continuum.KafkaSynchronizedConsumerPool;\n-import io.warp10.continuum.TimeSource;\n-import io.warp10.continuum.sensision.SensisionConstants;\n-import io.warp10.continuum.store.Constants;\n-import io.warp10.continuum.thrift.data.RunRequest;\n-import io.warp10.crypto.CryptoUtils;\n-import io.warp10.crypto.DummyKeyStore;\n-import io.warp10.crypto.KeyStore;\n-import io.warp10.crypto.OrderPreservingBase64;\n-import io.warp10.crypto.SipHashInline;\n-import io.warp10.sensision.Sensision;\n-import kafka.javaapi.producer.Producer;\n-import kafka.producer.KeyedMessage;\n-import kafka.producer.ProducerConfig;\n-\n /**\n  * Periodically submit WarpScript scripts residing in subdirectories of the given root.\n  * Greatly inspired by Sensision's own ScriptRunner\n  */\n public class ScriptRunner extends Thread {\n-  \n+\n+  private class NamedThreadFactory implements ThreadFactory {\n+    private AtomicLong threadNumber = new AtomicLong();\n+\n+    @Override\n+    public Thread newThread(Runnable r) {\n+      return new Thread(r, \"[Warp ScriptRunner Executor #\" + threadNumber.getAndIncrement() + \"]\");\n+    }\n+  }\n+\n   protected static final byte[] CLEAR = \"\\nCLEAR\\n\".getBytes(Charsets.UTF_8);\n-  \n+\n   protected ExecutorService executor;\n-  \n-  private int nthreads;\n-  \n+\n   private long scanperiod;\n-  \n+\n   private String root;\n \n   protected String endpoint;\n-  \n+\n   private long minperiod;\n \n   private LeaderLatch leaderLatch;\n \n   private KafkaProducerPool kafkaProducerPool;\n-  \n+\n   private String topic = null;\n-  \n+\n   private final String id;\n \n   protected byte[] KAFKA_AES = null;\n \n   protected long[] KAFKA_MAC = null;\n \n-  private KafkaSynchronizedConsumerPool consumerPool = null;\n-  \n   //## Add LeaderLatch configuration\n   //## Add Kafka configuration for outgoing RunRequests + MAC + AES\n-  \n+\n   /**\n    * Required properties for the standalone version of ScriptRunner\n    */\n   public static final String[] REQUIRED_PROPERTIES_STANDALONE = {\n-    Configuration.RUNNER_ENDPOINT,\n-    Configuration.RUNNER_NTHREADS,\n-    Configuration.RUNNER_ROOT,\n-    Configuration.RUNNER_SCANPERIOD,\n-    Configuration.RUNNER_MINPERIOD,    \n-    Configuration.RUNNER_ID,\n+      Configuration.RUNNER_ENDPOINT,\n+      Configuration.RUNNER_NTHREADS,\n+      Configuration.RUNNER_ROOT,\n+      Configuration.RUNNER_SCANPERIOD,\n+      Configuration.RUNNER_MINPERIOD,\n+      Configuration.RUNNER_ID,\n   };\n \n   /**\n    * Required properties for the distributed 'worker' role of ScriptRunner\n    */\n   public static final String[] REQUIRED_PROPERTIES_WORKER = {\n-    Configuration.RUNNER_KAFKA_ZKCONNECT,\n-    Configuration.RUNNER_KAFKA_TOPIC,\n-    Configuration.RUNNER_KAFKA_GROUPID,\n-    Configuration.RUNNER_KAFKA_COMMITPERIOD,\n-    Configuration.RUNNER_KAFKA_NTHREADS,\n-    Configuration.RUNNER_NTHREADS,\n-    Configuration.RUNNER_ENDPOINT,    \n-    Configuration.RUNNER_ID,\n+      Configuration.RUNNER_KAFKA_ZKCONNECT,\n+      Configuration.RUNNER_KAFKA_TOPIC,\n+      Configuration.RUNNER_KAFKA_GROUPID,\n+      Configuration.RUNNER_KAFKA_COMMITPERIOD,\n+      Configuration.RUNNER_KAFKA_NTHREADS,\n+      Configuration.RUNNER_NTHREADS,\n+      Configuration.RUNNER_ENDPOINT,\n+      Configuration.RUNNER_ID,\n   };\n \n   /**\n    * Required properties for the distributed 'scheduler' role of ScriptRunner\n    */\n   public static final String[] REQUIRED_PROPERTIES_SCHEDULER = {\n-    Configuration.RUNNER_KAFKA_BROKERLIST,\n-    Configuration.RUNNER_KAFKA_TOPIC,\n-    Configuration.RUNNER_KAFKA_POOLSIZE,\n-    Configuration.RUNNER_ROOT,\n-    Configuration.RUNNER_SCANPERIOD,\n-    Configuration.RUNNER_MINPERIOD,\n-    Configuration.RUNNER_ID,\n-    Configuration.RUNNER_ZK_QUORUM,\n-    Configuration.RUNNER_ZK_ZNODE,\n+      Configuration.RUNNER_KAFKA_BROKERLIST,\n+      Configuration.RUNNER_KAFKA_TOPIC,\n+      Configuration.RUNNER_KAFKA_POOLSIZE,\n+      Configuration.RUNNER_ROOT,\n+      Configuration.RUNNER_SCANPERIOD,\n+      Configuration.RUNNER_MINPERIOD,\n+      Configuration.RUNNER_ID,\n+      Configuration.RUNNER_ZK_QUORUM,\n+      Configuration.RUNNER_ZK_ZNODE,\n   };\n \n   private final boolean isScheduler;\n-  private final boolean isWorker;\n   private final boolean isStandalone;\n   private final KeyStore keystore;\n-  \n+\n   private final byte[] runnerPSK;\n-  \n+\n   private final boolean runAtStartup;\n-  \n+\n   public ScriptRunner(KeyStore keystore, Properties config) throws IOException {\n-      \n+\n     //\n     // Extract our roles\n     //\n-    \n+\n     Preconditions.checkNotNull(config.getProperty(Configuration.RUNNER_ROLES), \"Property '\" + Configuration.RUNNER_ROLES + \"' MUST be set.\");\n-    \n+\n     String[] roles = config.getProperty(Configuration.RUNNER_ROLES).split(\",\");\n-    \n+\n     if (roles.length > 2) {\n       throw new IOException(\"Role can only be 'standalone' or either or both 'scheduler' and 'worker'.\");\n     }\n \n     Set<String> configuredRoles = new HashSet<String>();\n-    \n-    for (String role: roles) {\n-      configuredRoles.add(role);\n-    }\n+    configuredRoles.addAll(Arrays.asList(roles));\n \n-    if (configuredRoles.contains(\"standalone\")) {\n-      isStandalone = true;\n-    } else {\n-      isStandalone = false;\n-    }\n-    \n-    if (configuredRoles.contains(\"scheduler\")) {\n-      isScheduler = true;\n-    } else {\n-      isScheduler = false;\n-    }\n-    \n-    if (configuredRoles.contains(\"worker\")) {\n-      isWorker = true;\n-    } else {\n-      isWorker = false;\n-    }\n-  \n-    if (isStandalone || isScheduler) {      \n+    isStandalone = configuredRoles.contains(\"standalone\");\n+\n+    isScheduler = configuredRoles.contains(\"scheduler\");\n+\n+    boolean isWorker = configuredRoles.contains(\"worker\");\n+\n+    if (isStandalone || isScheduler) {\n       this.runAtStartup = \"true\".equals(config.getProperty(Configuration.RUNNER_RUNATSTARTUP, \"true\"));\n     } else {\n       this.runAtStartup = true;\n     }\n-    \n+\n     if (isStandalone && (isWorker || isScheduler)) {\n       throw new IOException(\"Role is either 'standalone' or either or both 'scheduler' and 'worker'.\");\n     }\n-  \n+\n     this.keystore = keystore;\n-    \n+\n     this.runnerPSK = keystore.getKey(KeyStore.AES_RUNNER_PSK);\n \n     //\n     // Check the required properties and configure the various roles\n     //\n-    \n+\n     if (isStandalone) {\n       for (String required: REQUIRED_PROPERTIES_STANDALONE) {\n-        Preconditions.checkNotNull(config.getProperty(required), \"Missing configuration parameter '%s'.\", required);          \n+        Preconditions.checkNotNull(config.getProperty(required), \"Missing configuration parameter '%s'.\", required);\n       }\n-      \n+\n       this.root = config.getProperty(Configuration.RUNNER_ROOT);\n-      this.nthreads = Integer.parseInt(config.getProperty(Configuration.RUNNER_NTHREADS));\n+      int nthreads = Integer.parseInt(config.getProperty(Configuration.RUNNER_NTHREADS));\n       this.scanperiod = Long.parseLong(config.getProperty(Configuration.RUNNER_SCANPERIOD));\n       this.minperiod = Long.parseLong(config.getProperty(Configuration.RUNNER_MINPERIOD));\n       this.endpoint = config.getProperty(Configuration.RUNNER_ENDPOINT);\n-      \n-      this.executor = new ThreadPoolExecutor(1, nthreads, 30000L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(nthreads * 256));\n-  \n+\n+      ThreadPoolExecutor runnersExecutor = new ThreadPoolExecutor(nthreads, nthreads, 30000L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(nthreads * 256), new NamedThreadFactory());\n+      runnersExecutor.allowCoreThreadTimeOut(true);\n+\n+      this.executor = runnersExecutor;\n+\n       this.leaderLatch = null;\n-      \n+\n       this.setDaemon(true);\n       this.setName(\"[Warp ScriptRunner]\");\n-      this.start();      \n+      this.start();\n     }\n-    \n+\n     if (isWorker || isScheduler) {\n       extractKeys(config);\n-      \n+\n       byte[] k = this.keystore.getKey(KeyStore.SIPHASH_KAFKA_RUNNER);\n-      \n+\n       if (null != k) {\n         this.KAFKA_MAC = SipHashInline.getKey(k);\n       }\n     }\n-    \n+\n     if (isWorker) {\n       for (String required: REQUIRED_PROPERTIES_WORKER) {\n-        Preconditions.checkNotNull(config.getProperty(required), \"Missing configuration parameter '%s'.\", required);          \n+        Preconditions.checkNotNull(config.getProperty(required), \"Missing configuration parameter '%s'.\", required);\n       }\n-      \n+\n       this.endpoint = config.getProperty(Configuration.RUNNER_ENDPOINT);\n-      \n+\n       String zkconnect = config.getProperty(Configuration.RUNNER_KAFKA_ZKCONNECT);\n       this.topic = config.getProperty(Configuration.RUNNER_KAFKA_TOPIC);\n       String groupid = config.getProperty(Configuration.RUNNER_KAFKA_GROUPID);\n       String clientid = config.getProperty(Configuration.RUNNER_KAFKA_CONSUMER_CLIENTID);\n       String strategy = config.getProperty(Configuration.RUNNER_KAFKA_CONSUMER_PARTITION_ASSIGNMENT_STRATEGY);\n       int nthreads = Integer.parseInt(config.getProperty(Configuration.RUNNER_KAFKA_NTHREADS));\n       long commitPeriod = Long.parseLong(config.getProperty(Configuration.RUNNER_KAFKA_COMMITPERIOD));\n-      this.nthreads = Integer.parseInt(config.getProperty(Configuration.RUNNER_NTHREADS));\n-      this.executor = new ThreadPoolExecutor(1, nthreads, 30000L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(nthreads * 256));\n-      \n-      this.consumerPool = new KafkaSynchronizedConsumerPool(zkconnect, topic, clientid, groupid, strategy, nthreads, commitPeriod, new ScriptRunnerConsumerFactory(this));\n+\n+      ThreadPoolExecutor runnersExecutor = new ThreadPoolExecutor(nthreads, nthreads, 30000L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(nthreads * 256), new NamedThreadFactory());\n+      runnersExecutor.allowCoreThreadTimeOut(true);\n+\n+      this.executor = runnersExecutor;\n+\n+      new KafkaSynchronizedConsumerPool(zkconnect, topic, clientid, groupid, strategy, nthreads, commitPeriod, new ScriptRunnerConsumerFactory(this));","path":"warp10/src/main/java/io/warp10/script/ScriptRunner.java","position":358,"original_position":358,"commit_id":"d370f90f73b77903929aed264c56598328a53a42","original_commit_id":"d370f90f73b77903929aed264c56598328a53a42","user":{"login":"hbs","id":236594,"node_id":"MDQ6VXNlcjIzNjU5NA==","avatar_url":"https://avatars3.githubusercontent.com/u/236594?v=4","gravatar_id":"","url":"https://api.github.com/users/hbs","html_url":"https://github.com/hbs","followers_url":"https://api.github.com/users/hbs/followers","following_url":"https://api.github.com/users/hbs/following{/other_user}","gists_url":"https://api.github.com/users/hbs/gists{/gist_id}","starred_url":"https://api.github.com/users/hbs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hbs/subscriptions","organizations_url":"https://api.github.com/users/hbs/orgs","repos_url":"https://api.github.com/users/hbs/repos","events_url":"https://api.github.com/users/hbs/events{/privacy}","received_events_url":"https://api.github.com/users/hbs/received_events","type":"User","site_admin":false},"body":"Code is clearer if you keep a reference to the created consumer pool","created_at":"2018-08-23T21:01:02Z","updated_at":"2018-08-23T21:01:03Z","html_url":"https://github.com/cityzendata/warp10-platform/pull/342#discussion_r212455958","pull_request_url":"https://api.github.com/repos/cityzendata/warp10-platform/pulls/342","author_association":"COLLABORATOR","_links":{"self":{"href":"https://api.github.com/repos/cityzendata/warp10-platform/pulls/comments/212455958"},"html":{"href":"https://github.com/cityzendata/warp10-platform/pull/342#discussion_r212455958"},"pull_request":{"href":"https://api.github.com/repos/cityzendata/warp10-platform/pulls/342"}}},"pull_request":{"url":"https://api.github.com/repos/cityzendata/warp10-platform/pulls/342","id":210458073,"node_id":"MDExOlB1bGxSZXF1ZXN0MjEwNDU4MDcz","html_url":"https://github.com/cityzendata/warp10-platform/pull/342","diff_url":"https://github.com/cityzendata/warp10-platform/pull/342.diff","patch_url":"https://github.com/cityzendata/warp10-platform/pull/342.patch","issue_url":"https://api.github.com/repos/cityzendata/warp10-platform/issues/342","number":342,"state":"open","locked":false,"title":"Allow runners to really use runner.nthreads, code cleanup.","user":{"login":"ftence","id":22769955,"node_id":"MDQ6VXNlcjIyNzY5OTU1","avatar_url":"https://avatars2.githubusercontent.com/u/22769955?v=4","gravatar_id":"","url":"https://api.github.com/users/ftence","html_url":"https://github.com/ftence","followers_url":"https://api.github.com/users/ftence/followers","following_url":"https://api.github.com/users/ftence/following{/other_user}","gists_url":"https://api.github.com/users/ftence/gists{/gist_id}","starred_url":"https://api.github.com/users/ftence/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ftence/subscriptions","organizations_url":"https://api.github.com/users/ftence/orgs","repos_url":"https://api.github.com/users/ftence/repos","events_url":"https://api.github.com/users/ftence/events{/privacy}","received_events_url":"https://api.github.com/users/ftence/received_events","type":"User","site_admin":false},"body":"For a detailled explanation on ThreadPoolExecutor, see:\r\nhttp://www.bigsoft.co.uk/blog/2009/11/27/rules-of-a-threadpoolexecutor-pool-size","created_at":"2018-08-23T13:58:52Z","updated_at":"2018-08-23T21:01:03Z","closed_at":null,"merged_at":null,"merge_commit_sha":"34d47ea26dfc2111c94ee8314005bd6ad49bbb34","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/cityzendata/warp10-platform/pulls/342/commits","review_comments_url":"https://api.github.com/repos/cityzendata/warp10-platform/pulls/342/comments","review_comment_url":"https://api.github.com/repos/cityzendata/warp10-platform/pulls/comments{/number}","comments_url":"https://api.github.com/repos/cityzendata/warp10-platform/issues/342/comments","statuses_url":"https://api.github.com/repos/cityzendata/warp10-platform/statuses/d370f90f73b77903929aed264c56598328a53a42","head":{"label":"ftence:runnerThreads","ref":"runnerThreads","sha":"d370f90f73b77903929aed264c56598328a53a42","user":{"login":"ftence","id":22769955,"node_id":"MDQ6VXNlcjIyNzY5OTU1","avatar_url":"https://avatars2.githubusercontent.com/u/22769955?v=4","gravatar_id":"","url":"https://api.github.com/users/ftence","html_url":"https://github.com/ftence","followers_url":"https://api.github.com/users/ftence/followers","following_url":"https://api.github.com/users/ftence/following{/other_user}","gists_url":"https://api.github.com/users/ftence/gists{/gist_id}","starred_url":"https://api.github.com/users/ftence/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ftence/subscriptions","organizations_url":"https://api.github.com/users/ftence/orgs","repos_url":"https://api.github.com/users/ftence/repos","events_url":"https://api.github.com/users/ftence/events{/privacy}","received_events_url":"https://api.github.com/users/ftence/received_events","type":"User","site_admin":false},"repo":{"id":117815940,"node_id":"MDEwOlJlcG9zaXRvcnkxMTc4MTU5NDA=","name":"warp10-platform","full_name":"ftence/warp10-platform","owner":{"login":"ftence","id":22769955,"node_id":"MDQ6VXNlcjIyNzY5OTU1","avatar_url":"https://avatars2.githubusercontent.com/u/22769955?v=4","gravatar_id":"","url":"https://api.github.com/users/ftence","html_url":"https://github.com/ftence","followers_url":"https://api.github.com/users/ftence/followers","following_url":"https://api.github.com/users/ftence/following{/other_user}","gists_url":"https://api.github.com/users/ftence/gists{/gist_id}","starred_url":"https://api.github.com/users/ftence/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ftence/subscriptions","organizations_url":"https://api.github.com/users/ftence/orgs","repos_url":"https://api.github.com/users/ftence/repos","events_url":"https://api.github.com/users/ftence/events{/privacy}","received_events_url":"https://api.github.com/users/ftence/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/ftence/warp10-platform","description":null,"fork":true,"url":"https://api.github.com/repos/ftence/warp10-platform","forks_url":"https://api.github.com/repos/ftence/warp10-platform/forks","keys_url":"https://api.github.com/repos/ftence/warp10-platform/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ftence/warp10-platform/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ftence/warp10-platform/teams","hooks_url":"https://api.github.com/repos/ftence/warp10-platform/hooks","issue_events_url":"https://api.github.com/repos/ftence/warp10-platform/issues/events{/number}","events_url":"https://api.github.com/repos/ftence/warp10-platform/events","assignees_url":"https://api.github.com/repos/ftence/warp10-platform/assignees{/user}","branches_url":"https://api.github.com/repos/ftence/warp10-platform/branches{/branch}","tags_url":"https://api.github.com/repos/ftence/warp10-platform/tags","blobs_url":"https://api.github.com/repos/ftence/warp10-platform/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ftence/warp10-platform/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ftence/warp10-platform/git/refs{/sha}","trees_url":"https://api.github.com/repos/ftence/warp10-platform/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ftence/warp10-platform/statuses/{sha}","languages_url":"https://api.github.com/repos/ftence/warp10-platform/languages","stargazers_url":"https://api.github.com/repos/ftence/warp10-platform/stargazers","contributors_url":"https://api.github.com/repos/ftence/warp10-platform/contributors","subscribers_url":"https://api.github.com/repos/ftence/warp10-platform/subscribers","subscription_url":"https://api.github.com/repos/ftence/warp10-platform/subscription","commits_url":"https://api.github.com/repos/ftence/warp10-platform/commits{/sha}","git_commits_url":"https://api.github.com/repos/ftence/warp10-platform/git/commits{/sha}","comments_url":"https://api.github.com/repos/ftence/warp10-platform/comments{/number}","issue_comment_url":"https://api.github.com/repos/ftence/warp10-platform/issues/comments{/number}","contents_url":"https://api.github.com/repos/ftence/warp10-platform/contents/{+path}","compare_url":"https://api.github.com/repos/ftence/warp10-platform/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ftence/warp10-platform/merges","archive_url":"https://api.github.com/repos/ftence/warp10-platform/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ftence/warp10-platform/downloads","issues_url":"https://api.github.com/repos/ftence/warp10-platform/issues{/number}","pulls_url":"https://api.github.com/repos/ftence/warp10-platform/pulls{/number}","milestones_url":"https://api.github.com/repos/ftence/warp10-platform/milestones{/number}","notifications_url":"https://api.github.com/repos/ftence/warp10-platform/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ftence/warp10-platform/labels{/name}","releases_url":"https://api.github.com/repos/ftence/warp10-platform/releases{/id}","deployments_url":"https://api.github.com/repos/ftence/warp10-platform/deployments","created_at":"2018-01-17T09:41:02Z","updated_at":"2018-01-17T09:41:06Z","pushed_at":"2018-08-23T14:44:36Z","git_url":"git://github.com/ftence/warp10-platform.git","ssh_url":"git@github.com:ftence/warp10-platform.git","clone_url":"https://github.com/ftence/warp10-platform.git","svn_url":"https://github.com/ftence/warp10-platform","homepage":null,"size":3855,"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":"cityzendata:master","ref":"master","sha":"9247885edf56a2a1cf572b0d904a02df0e492208","user":{"login":"cityzendata","id":4659114,"node_id":"MDQ6VXNlcjQ2NTkxMTQ=","avatar_url":"https://avatars3.githubusercontent.com/u/4659114?v=4","gravatar_id":"","url":"https://api.github.com/users/cityzendata","html_url":"https://github.com/cityzendata","followers_url":"https://api.github.com/users/cityzendata/followers","following_url":"https://api.github.com/users/cityzendata/following{/other_user}","gists_url":"https://api.github.com/users/cityzendata/gists{/gist_id}","starred_url":"https://api.github.com/users/cityzendata/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cityzendata/subscriptions","organizations_url":"https://api.github.com/users/cityzendata/orgs","repos_url":"https://api.github.com/users/cityzendata/repos","events_url":"https://api.github.com/users/cityzendata/events{/privacy}","received_events_url":"https://api.github.com/users/cityzendata/received_events","type":"User","site_admin":false},"repo":{"id":50594316,"node_id":"MDEwOlJlcG9zaXRvcnk1MDU5NDMxNg==","name":"warp10-platform","full_name":"cityzendata/warp10-platform","owner":{"login":"cityzendata","id":4659114,"node_id":"MDQ6VXNlcjQ2NTkxMTQ=","avatar_url":"https://avatars3.githubusercontent.com/u/4659114?v=4","gravatar_id":"","url":"https://api.github.com/users/cityzendata","html_url":"https://github.com/cityzendata","followers_url":"https://api.github.com/users/cityzendata/followers","following_url":"https://api.github.com/users/cityzendata/following{/other_user}","gists_url":"https://api.github.com/users/cityzendata/gists{/gist_id}","starred_url":"https://api.github.com/users/cityzendata/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cityzendata/subscriptions","organizations_url":"https://api.github.com/users/cityzendata/orgs","repos_url":"https://api.github.com/users/cityzendata/repos","events_url":"https://api.github.com/users/cityzendata/events{/privacy}","received_events_url":"https://api.github.com/users/cityzendata/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/cityzendata/warp10-platform","description":null,"fork":false,"url":"https://api.github.com/repos/cityzendata/warp10-platform","forks_url":"https://api.github.com/repos/cityzendata/warp10-platform/forks","keys_url":"https://api.github.com/repos/cityzendata/warp10-platform/keys{/key_id}","collaborators_url":"https://api.github.com/repos/cityzendata/warp10-platform/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/cityzendata/warp10-platform/teams","hooks_url":"https://api.github.com/repos/cityzendata/warp10-platform/hooks","issue_events_url":"https://api.github.com/repos/cityzendata/warp10-platform/issues/events{/number}","events_url":"https://api.github.com/repos/cityzendata/warp10-platform/events","assignees_url":"https://api.github.com/repos/cityzendata/warp10-platform/assignees{/user}","branches_url":"https://api.github.com/repos/cityzendata/warp10-platform/branches{/branch}","tags_url":"https://api.github.com/repos/cityzendata/warp10-platform/tags","blobs_url":"https://api.github.com/repos/cityzendata/warp10-platform/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/cityzendata/warp10-platform/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/cityzendata/warp10-platform/git/refs{/sha}","trees_url":"https://api.github.com/repos/cityzendata/warp10-platform/git/trees{/sha}","statuses_url":"https://api.github.com/repos/cityzendata/warp10-platform/statuses/{sha}","languages_url":"https://api.github.com/repos/cityzendata/warp10-platform/languages","stargazers_url":"https://api.github.com/repos/cityzendata/warp10-platform/stargazers","contributors_url":"https://api.github.com/repos/cityzendata/warp10-platform/contributors","subscribers_url":"https://api.github.com/repos/cityzendata/warp10-platform/subscribers","subscription_url":"https://api.github.com/repos/cityzendata/warp10-platform/subscription","commits_url":"https://api.github.com/repos/cityzendata/warp10-platform/commits{/sha}","git_commits_url":"https://api.github.com/repos/cityzendata/warp10-platform/git/commits{/sha}","comments_url":"https://api.github.com/repos/cityzendata/warp10-platform/comments{/number}","issue_comment_url":"https://api.github.com/repos/cityzendata/warp10-platform/issues/comments{/number}","contents_url":"https://api.github.com/repos/cityzendata/warp10-platform/contents/{+path}","compare_url":"https://api.github.com/repos/cityzendata/warp10-platform/compare/{base}...{head}","merges_url":"https://api.github.com/repos/cityzendata/warp10-platform/merges","archive_url":"https://api.github.com/repos/cityzendata/warp10-platform/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/cityzendata/warp10-platform/downloads","issues_url":"https://api.github.com/repos/cityzendata/warp10-platform/issues{/number}","pulls_url":"https://api.github.com/repos/cityzendata/warp10-platform/pulls{/number}","milestones_url":"https://api.github.com/repos/cityzendata/warp10-platform/milestones{/number}","notifications_url":"https://api.github.com/repos/cityzendata/warp10-platform/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/cityzendata/warp10-platform/labels{/name}","releases_url":"https://api.github.com/repos/cityzendata/warp10-platform/releases{/id}","deployments_url":"https://api.github.com/repos/cityzendata/warp10-platform/deployments","created_at":"2016-01-28T15:56:55Z","updated_at":"2018-08-21T21:22:58Z","pushed_at":"2018-08-23T14:44:38Z","git_url":"git://github.com/cityzendata/warp10-platform.git","ssh_url":"git@github.com:cityzendata/warp10-platform.git","clone_url":"https://github.com/cityzendata/warp10-platform.git","svn_url":"https://github.com/cityzendata/warp10-platform","homepage":null,"size":3827,"stargazers_count":71,"watchers_count":71,"language":"Java","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":36,"mirror_url":null,"archived":false,"open_issues_count":24,"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":36,"open_issues":24,"watchers":71,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/cityzendata/warp10-platform/pulls/342"},"html":{"href":"https://github.com/cityzendata/warp10-platform/pull/342"},"issue":{"href":"https://api.github.com/repos/cityzendata/warp10-platform/issues/342"},"comments":{"href":"https://api.github.com/repos/cityzendata/warp10-platform/issues/342/comments"},"review_comments":{"href":"https://api.github.com/repos/cityzendata/warp10-platform/pulls/342/comments"},"review_comment":{"href":"https://api.github.com/repos/cityzendata/warp10-platform/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/cityzendata/warp10-platform/pulls/342/commits"},"statuses":{"href":"https://api.github.com/repos/cityzendata/warp10-platform/statuses/d370f90f73b77903929aed264c56598328a53a42"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"hbs"}}