{"action":"created","comment":{"url":"https://api.github.com/repos/Civcraft/CivModCore/pulls/comments/78003605","id":78003605,"diff_hunk":"@@ -0,0 +1,490 @@\n+package vg.civcraft.mc.civmodcore.dao;\n+\n+import java.util.concurrent.Executors;\n+import java.util.concurrent.ExecutorService;\n+import java.util.concurrent.Callable;\n+import java.util.concurrent.Future;\n+\n+import java.sql.Connection;\n+import java.sql.PreparedStatement;\n+import java.sql.ResultSet;\n+import java.sql.SQLException;\n+import java.sql.SQLWarning;\n+import java.sql.Statement;\n+import java.util.Arrays;\n+import java.util.LinkedList;\n+import java.util.NavigableMap;\n+import java.util.TreeMap;\n+import java.util.concurrent.TimeoutException;\n+import java.util.logging.Level;\n+import java.util.logging.Logger;\n+\n+import vg.civcraft.mc.civmodcore.ACivMod;\n+\n+/**\n+ * Plugins should replace their custom Database handlers with an instance of ManagedDatasource.\n+ * \n+ * See the {@link #ManagedDatasource} constructor for details on how to use the ManagedDatasource.\n+ * \n+ * To convert existing plugins, do the following:\n+ *\n+ *   1. Take existing database version code and refactor it.\n+ *      a. Any CREATE, UPDATE, ALTER, or similar statements, convert to a List of Strings and pass\n+ *         them into ManagedDatasource as a Migration using {@link #registerMigration(Integer, boolean, String...)}\n+ *      b. Find your prepared statements. Convert the string resources as static final in your plugin's DAO layer.\n+ *      c. Remove any \"is database alive\" check code. It's not needed.\n+ *      d. Remove any version management code that remains\n+ *      e. DO react to the results of the {@link #upgradeDatabase} call. \n+ *         i.   If false is returned, terminate your plugin.\n+ *         ii.  If false is returned and your plugin is critical to a host of other plugins, terminate the server.\n+ *         iii. If an Exception is thrown, I strongly recommend you consider it a \"false\" return value and react accordingly.\n+ *      f. Note: Create a \"first\" migration at index -1 that ignores errors and copies any \"current\" migration state data\n+ *         from the db_version or equivalent table into the <code>managed_plugin_data</code> table. \n+ *  2. Throughout your plugin, ensure that PreparedStatements are \"created\" new each request and against a \n+ *     newly retrieved Connection (using {@link #getConnection()} of this class). Don't worry about PrepareStatements.\n+ *     The driver will manage caching them efficiently.\n+ *  3. Make sure you release Connections using {@link Connection#close()} as soon as you can (when done with them). \n+ *     a. Don't hold on to Connections. \n+ *     b. Close them. \n+ *     c. Use \"try-with-resources\" where-ever possible so that they are auto-closed.\n+ *  4. If you have loops to insert a bunch of similar records, convert it to a batch. Find instructions in {@link #ManagedDatasource}.\n+ *  5. If you have special needs like atomic multi-statement, do all your work on a single Connection and return it to \n+ *     a clean state when you are done. (turn auto-commit back on, ensure all transactions are committed, etc.)\n+ *\n+ * That should cover most cases. Note that points 2 & 3 are critical. Point 1 is required. Point 4 and 5 are highly recommended.\n+ * \n+ * TODO: Make this instantiable via ConfigurationSerializable interface.\n+ *\n+ * @author ProgrammerDan\n+ */\n+public class ManagedDatasource {\n+\n+\tprivate static final long MAX_WAIT_FOR_LOCK = 600000l;\n+\tprivate static final long WAIT_PERIOD = 500l;\n+\t\n+\tprivate ConnectionPool connections;\n+\tprivate Logger logger;\n+\tprivate ACivMod plugin;\n+\t\n+\tprivate static final String CHECK_CREATE_MIGRATIONS_TABLE = \n+\t\t\t\"CREATE TABLE IF NOT EXISTS managed_plugin_data (\"\n+\t\t\t\t\t+ \"managed_id BIGINT NOT NULL AUTO_INCREMENT, \"\n+\t\t\t\t\t+ \"plugin_name VARCHAR(120) NOT NULL, \"\n+\t\t\t\t\t+ \"management_began TIMESTAMP NOT NULL DEFAULT NOW(), \"\n+\t\t\t\t\t+ \"current_migration_number INT NOT NULL, \"\n+\t\t\t\t\t+ \"last_migration TIMESTAMP, \"\n+\t\t\t\t\t+ \"CONSTRAINT pk_managed_plugin_data PRIMARY KEY (managed_id), \"\n+\t\t\t\t\t+ \"CONSTRAINT uniq_managed_plugin UNIQUE (plugin_name), \"\n+\t\t\t\t\t+ \"INDEX idx_managed_plugin USING BTREE (plugin_name)\" +\n+\t\t\t\t\t\");\";\n+\t\n+\tprivate static final String CHECK_LAST_MIGRATION = \n+\t\t\t\"SELECT current_migration_number FROM managed_plugin_data WHERE plugin_name = ?;\";\n+\t\n+\tprivate static final String RECORD_MIGRATION =\n+\t\t\t\"INSERT INTO managed_plugin_data (plugin_name, current_migration_number, last_migration) \" \n+\t\t\t\t\t+ \"VALUES (?, ?, NOW()) ON DUPLICATE KEY UPDATE plugin_name = VALUES(plugin_name), \"\n+\t\t\t\t\t+ \"current_migration_number = VALUES(current_migration_number), \"\n+\t\t\t\t\t+ \"last_migration = VALUES(last_migration);\";\n+\t\n+\tprivate static final String CHECK_CREATE_LOCK_TABLE = \n+\t\t\t\"CREATE TABLE IF NOT EXISTS managed_plugin_locks (\"\n+\t\t\t\t\t+ \"plugin_name VARCHAR(120) NOT NULL, \"\n+\t\t\t\t\t+ \"lock_time TIMESTAMP NOT NULL DEFAULT NOW(), \"\n+\t\t\t\t\t+ \"CONSTRAINT pk_managed_plugin_locks PRIMARY KEY (plugin_name)\" +\n+\t\t\t\t\t\");\";\n+\t\n+\tprivate static final String CLEANUP_LOCK_TABLE = \n+\t\t\t\"DELETE FROM managed_plugin_locks WHERE lock_time <= TIMESTAMPADD(HOUR, -8, NOW());\";\n+\t\n+\tprivate static final String ACQUIRE_LOCK = \n+\t\t\t\"INSERT IGNORE INTO managed_plugin_locks (plugin_name) VALUES (?);\";\n+\t\n+\tprivate static final String RELEASE_LOCK =\n+\t\t\t\"DELETE FROM managed_plugin_locks WHERE plugin_name = ?\";\n+\n+\tprivate int first_migration;\n+\tprivate TreeMap<Integer, LinkedList<String>> migrations;","path":"src/main/java/vg/civcraft/mc/civmodcore/dao/ManagedDatasource.java","position":107,"original_position":107,"commit_id":"536b6be6a7a265e7033be8ea59d8ef70bf75fa92","original_commit_id":"536b6be6a7a265e7033be8ea59d8ef70bf75fa92","user":{"login":"ProgrammerDan","id":409230,"avatar_url":"https://avatars.githubusercontent.com/u/409230?v=3","gravatar_id":"","url":"https://api.github.com/users/ProgrammerDan","html_url":"https://github.com/ProgrammerDan","followers_url":"https://api.github.com/users/ProgrammerDan/followers","following_url":"https://api.github.com/users/ProgrammerDan/following{/other_user}","gists_url":"https://api.github.com/users/ProgrammerDan/gists{/gist_id}","starred_url":"https://api.github.com/users/ProgrammerDan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ProgrammerDan/subscriptions","organizations_url":"https://api.github.com/users/ProgrammerDan/orgs","repos_url":"https://api.github.com/users/ProgrammerDan/repos","events_url":"https://api.github.com/users/ProgrammerDan/events{/privacy}","received_events_url":"https://api.github.com/users/ProgrammerDan/received_events","type":"User","site_admin":false},"body":"Yeah, code smell. Started as just a single map ... I'll make the conversion.","created_at":"2016-09-08T13:21:24Z","updated_at":"2016-09-08T13:21:24Z","html_url":"https://github.com/Civcraft/CivModCore/pull/23#discussion_r78003605","pull_request_url":"https://api.github.com/repos/Civcraft/CivModCore/pulls/23","_links":{"self":{"href":"https://api.github.com/repos/Civcraft/CivModCore/pulls/comments/78003605"},"html":{"href":"https://github.com/Civcraft/CivModCore/pull/23#discussion_r78003605"},"pull_request":{"href":"https://api.github.com/repos/Civcraft/CivModCore/pulls/23"}}},"pull_request":{"url":"https://api.github.com/repos/Civcraft/CivModCore/pulls/23","id":84412782,"html_url":"https://github.com/Civcraft/CivModCore/pull/23","diff_url":"https://github.com/Civcraft/CivModCore/pull/23.diff","patch_url":"https://github.com/Civcraft/CivModCore/pull/23.patch","issue_url":"https://api.github.com/repos/Civcraft/CivModCore/issues/23","number":23,"state":"open","locked":false,"title":"Adding Managed Database handling.","user":{"login":"ProgrammerDan","id":409230,"avatar_url":"https://avatars.githubusercontent.com/u/409230?v=3","gravatar_id":"","url":"https://api.github.com/users/ProgrammerDan","html_url":"https://github.com/ProgrammerDan","followers_url":"https://api.github.com/users/ProgrammerDan/followers","following_url":"https://api.github.com/users/ProgrammerDan/following{/other_user}","gists_url":"https://api.github.com/users/ProgrammerDan/gists{/gist_id}","starred_url":"https://api.github.com/users/ProgrammerDan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ProgrammerDan/subscriptions","organizations_url":"https://api.github.com/users/ProgrammerDan/orgs","repos_url":"https://api.github.com/users/ProgrammerDan/repos","events_url":"https://api.github.com/users/ProgrammerDan/events{/privacy}","received_events_url":"https://api.github.com/users/ProgrammerDan/received_events","type":"User","site_admin":false},"body":"Alright, this is a big PR, I guess.\r\n\r\nAdds HikariCP-backed database pooling as a general resource for all plugins to leverage.\r\n\r\nYes, we'll need to update all the plugins.\r\n\r\nNo, they won't break until we do.\r\n\r\nYes, we absolutely should.\r\n\r\nNote there is some serious javadoc comments describing how to use these new classes and how to migrate old code to use the new pattern, and it's all in the new \"dao\" package.\r\n\r\nPlease review and leave comments if I've missed anything.\r\n\r\nPlease see the companion PR in Namelayer to convert to this ManagedDatasource approach, as a proof of concept and an illustration of concept. Note that I've tested this compliant branch of Namelayer and it works great.","created_at":"2016-09-08T04:24:03Z","updated_at":"2016-09-08T13:21:24Z","closed_at":null,"merged_at":null,"merge_commit_sha":"22e8e70c2ca2d2ec79413cd3b9e2016bb931e97a","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/Civcraft/CivModCore/pulls/23/commits","review_comments_url":"https://api.github.com/repos/Civcraft/CivModCore/pulls/23/comments","review_comment_url":"https://api.github.com/repos/Civcraft/CivModCore/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Civcraft/CivModCore/issues/23/comments","statuses_url":"https://api.github.com/repos/Civcraft/CivModCore/statuses/536b6be6a7a265e7033be8ea59d8ef70bf75fa92","head":{"label":"Civcraft:adddb","ref":"adddb","sha":"536b6be6a7a265e7033be8ea59d8ef70bf75fa92","user":{"login":"Civcraft","id":3921874,"avatar_url":"https://avatars.githubusercontent.com/u/3921874?v=3","gravatar_id":"","url":"https://api.github.com/users/Civcraft","html_url":"https://github.com/Civcraft","followers_url":"https://api.github.com/users/Civcraft/followers","following_url":"https://api.github.com/users/Civcraft/following{/other_user}","gists_url":"https://api.github.com/users/Civcraft/gists{/gist_id}","starred_url":"https://api.github.com/users/Civcraft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Civcraft/subscriptions","organizations_url":"https://api.github.com/users/Civcraft/orgs","repos_url":"https://api.github.com/users/Civcraft/repos","events_url":"https://api.github.com/users/Civcraft/events{/privacy}","received_events_url":"https://api.github.com/users/Civcraft/received_events","type":"Organization","site_admin":false},"repo":{"id":36245057,"name":"CivModCore","full_name":"Civcraft/CivModCore","owner":{"login":"Civcraft","id":3921874,"avatar_url":"https://avatars.githubusercontent.com/u/3921874?v=3","gravatar_id":"","url":"https://api.github.com/users/Civcraft","html_url":"https://github.com/Civcraft","followers_url":"https://api.github.com/users/Civcraft/followers","following_url":"https://api.github.com/users/Civcraft/following{/other_user}","gists_url":"https://api.github.com/users/Civcraft/gists{/gist_id}","starred_url":"https://api.github.com/users/Civcraft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Civcraft/subscriptions","organizations_url":"https://api.github.com/users/Civcraft/orgs","repos_url":"https://api.github.com/users/Civcraft/repos","events_url":"https://api.github.com/users/Civcraft/events{/privacy}","received_events_url":"https://api.github.com/users/Civcraft/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Civcraft/CivModCore","description":"Common Plugin Core derived from Humbug","fork":true,"url":"https://api.github.com/repos/Civcraft/CivModCore","forks_url":"https://api.github.com/repos/Civcraft/CivModCore/forks","keys_url":"https://api.github.com/repos/Civcraft/CivModCore/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Civcraft/CivModCore/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Civcraft/CivModCore/teams","hooks_url":"https://api.github.com/repos/Civcraft/CivModCore/hooks","issue_events_url":"https://api.github.com/repos/Civcraft/CivModCore/issues/events{/number}","events_url":"https://api.github.com/repos/Civcraft/CivModCore/events","assignees_url":"https://api.github.com/repos/Civcraft/CivModCore/assignees{/user}","branches_url":"https://api.github.com/repos/Civcraft/CivModCore/branches{/branch}","tags_url":"https://api.github.com/repos/Civcraft/CivModCore/tags","blobs_url":"https://api.github.com/repos/Civcraft/CivModCore/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Civcraft/CivModCore/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Civcraft/CivModCore/git/refs{/sha}","trees_url":"https://api.github.com/repos/Civcraft/CivModCore/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Civcraft/CivModCore/statuses/{sha}","languages_url":"https://api.github.com/repos/Civcraft/CivModCore/languages","stargazers_url":"https://api.github.com/repos/Civcraft/CivModCore/stargazers","contributors_url":"https://api.github.com/repos/Civcraft/CivModCore/contributors","subscribers_url":"https://api.github.com/repos/Civcraft/CivModCore/subscribers","subscription_url":"https://api.github.com/repos/Civcraft/CivModCore/subscription","commits_url":"https://api.github.com/repos/Civcraft/CivModCore/commits{/sha}","git_commits_url":"https://api.github.com/repos/Civcraft/CivModCore/git/commits{/sha}","comments_url":"https://api.github.com/repos/Civcraft/CivModCore/comments{/number}","issue_comment_url":"https://api.github.com/repos/Civcraft/CivModCore/issues/comments{/number}","contents_url":"https://api.github.com/repos/Civcraft/CivModCore/contents/{+path}","compare_url":"https://api.github.com/repos/Civcraft/CivModCore/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Civcraft/CivModCore/merges","archive_url":"https://api.github.com/repos/Civcraft/CivModCore/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Civcraft/CivModCore/downloads","issues_url":"https://api.github.com/repos/Civcraft/CivModCore/issues{/number}","pulls_url":"https://api.github.com/repos/Civcraft/CivModCore/pulls{/number}","milestones_url":"https://api.github.com/repos/Civcraft/CivModCore/milestones{/number}","notifications_url":"https://api.github.com/repos/Civcraft/CivModCore/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Civcraft/CivModCore/labels{/name}","releases_url":"https://api.github.com/repos/Civcraft/CivModCore/releases{/id}","deployments_url":"https://api.github.com/repos/Civcraft/CivModCore/deployments","created_at":"2015-05-25T17:36:50Z","updated_at":"2016-03-18T21:57:39Z","pushed_at":"2016-09-08T04:24:03Z","git_url":"git://github.com/Civcraft/CivModCore.git","ssh_url":"git@github.com:Civcraft/CivModCore.git","clone_url":"https://github.com/Civcraft/CivModCore.git","svn_url":"https://github.com/Civcraft/CivModCore","homepage":null,"size":240,"stargazers_count":2,"watchers_count":2,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":6,"mirror_url":null,"open_issues_count":4,"forks":6,"open_issues":4,"watchers":2,"default_branch":"master"}},"base":{"label":"Civcraft:master","ref":"master","sha":"dc9335803a782e22570f13776822351dd63dc5a0","user":{"login":"Civcraft","id":3921874,"avatar_url":"https://avatars.githubusercontent.com/u/3921874?v=3","gravatar_id":"","url":"https://api.github.com/users/Civcraft","html_url":"https://github.com/Civcraft","followers_url":"https://api.github.com/users/Civcraft/followers","following_url":"https://api.github.com/users/Civcraft/following{/other_user}","gists_url":"https://api.github.com/users/Civcraft/gists{/gist_id}","starred_url":"https://api.github.com/users/Civcraft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Civcraft/subscriptions","organizations_url":"https://api.github.com/users/Civcraft/orgs","repos_url":"https://api.github.com/users/Civcraft/repos","events_url":"https://api.github.com/users/Civcraft/events{/privacy}","received_events_url":"https://api.github.com/users/Civcraft/received_events","type":"Organization","site_admin":false},"repo":{"id":36245057,"name":"CivModCore","full_name":"Civcraft/CivModCore","owner":{"login":"Civcraft","id":3921874,"avatar_url":"https://avatars.githubusercontent.com/u/3921874?v=3","gravatar_id":"","url":"https://api.github.com/users/Civcraft","html_url":"https://github.com/Civcraft","followers_url":"https://api.github.com/users/Civcraft/followers","following_url":"https://api.github.com/users/Civcraft/following{/other_user}","gists_url":"https://api.github.com/users/Civcraft/gists{/gist_id}","starred_url":"https://api.github.com/users/Civcraft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Civcraft/subscriptions","organizations_url":"https://api.github.com/users/Civcraft/orgs","repos_url":"https://api.github.com/users/Civcraft/repos","events_url":"https://api.github.com/users/Civcraft/events{/privacy}","received_events_url":"https://api.github.com/users/Civcraft/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Civcraft/CivModCore","description":"Common Plugin Core derived from Humbug","fork":true,"url":"https://api.github.com/repos/Civcraft/CivModCore","forks_url":"https://api.github.com/repos/Civcraft/CivModCore/forks","keys_url":"https://api.github.com/repos/Civcraft/CivModCore/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Civcraft/CivModCore/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Civcraft/CivModCore/teams","hooks_url":"https://api.github.com/repos/Civcraft/CivModCore/hooks","issue_events_url":"https://api.github.com/repos/Civcraft/CivModCore/issues/events{/number}","events_url":"https://api.github.com/repos/Civcraft/CivModCore/events","assignees_url":"https://api.github.com/repos/Civcraft/CivModCore/assignees{/user}","branches_url":"https://api.github.com/repos/Civcraft/CivModCore/branches{/branch}","tags_url":"https://api.github.com/repos/Civcraft/CivModCore/tags","blobs_url":"https://api.github.com/repos/Civcraft/CivModCore/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Civcraft/CivModCore/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Civcraft/CivModCore/git/refs{/sha}","trees_url":"https://api.github.com/repos/Civcraft/CivModCore/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Civcraft/CivModCore/statuses/{sha}","languages_url":"https://api.github.com/repos/Civcraft/CivModCore/languages","stargazers_url":"https://api.github.com/repos/Civcraft/CivModCore/stargazers","contributors_url":"https://api.github.com/repos/Civcraft/CivModCore/contributors","subscribers_url":"https://api.github.com/repos/Civcraft/CivModCore/subscribers","subscription_url":"https://api.github.com/repos/Civcraft/CivModCore/subscription","commits_url":"https://api.github.com/repos/Civcraft/CivModCore/commits{/sha}","git_commits_url":"https://api.github.com/repos/Civcraft/CivModCore/git/commits{/sha}","comments_url":"https://api.github.com/repos/Civcraft/CivModCore/comments{/number}","issue_comment_url":"https://api.github.com/repos/Civcraft/CivModCore/issues/comments{/number}","contents_url":"https://api.github.com/repos/Civcraft/CivModCore/contents/{+path}","compare_url":"https://api.github.com/repos/Civcraft/CivModCore/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Civcraft/CivModCore/merges","archive_url":"https://api.github.com/repos/Civcraft/CivModCore/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Civcraft/CivModCore/downloads","issues_url":"https://api.github.com/repos/Civcraft/CivModCore/issues{/number}","pulls_url":"https://api.github.com/repos/Civcraft/CivModCore/pulls{/number}","milestones_url":"https://api.github.com/repos/Civcraft/CivModCore/milestones{/number}","notifications_url":"https://api.github.com/repos/Civcraft/CivModCore/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Civcraft/CivModCore/labels{/name}","releases_url":"https://api.github.com/repos/Civcraft/CivModCore/releases{/id}","deployments_url":"https://api.github.com/repos/Civcraft/CivModCore/deployments","created_at":"2015-05-25T17:36:50Z","updated_at":"2016-03-18T21:57:39Z","pushed_at":"2016-09-08T04:24:03Z","git_url":"git://github.com/Civcraft/CivModCore.git","ssh_url":"git@github.com:Civcraft/CivModCore.git","clone_url":"https://github.com/Civcraft/CivModCore.git","svn_url":"https://github.com/Civcraft/CivModCore","homepage":null,"size":240,"stargazers_count":2,"watchers_count":2,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":6,"mirror_url":null,"open_issues_count":4,"forks":6,"open_issues":4,"watchers":2,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Civcraft/CivModCore/pulls/23"},"html":{"href":"https://github.com/Civcraft/CivModCore/pull/23"},"issue":{"href":"https://api.github.com/repos/Civcraft/CivModCore/issues/23"},"comments":{"href":"https://api.github.com/repos/Civcraft/CivModCore/issues/23/comments"},"review_comments":{"href":"https://api.github.com/repos/Civcraft/CivModCore/pulls/23/comments"},"review_comment":{"href":"https://api.github.com/repos/Civcraft/CivModCore/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Civcraft/CivModCore/pulls/23/commits"},"statuses":{"href":"https://api.github.com/repos/Civcraft/CivModCore/statuses/536b6be6a7a265e7033be8ea59d8ef70bf75fa92"}}}}
{"actor":{"display_login":"ProgrammerDan"}}