{"action":"created","comment":{"url":"https://api.github.com/repos/ding2/ding2/pulls/comments/168434008","pull_request_review_id":96797265,"id":168434008,"diff_hunk":"@@ -0,0 +1,470 @@\n+<?php\n+/**\n+ * @file\n+ * Admin page callback file for the opensearch module.\n+ */\n+\n+/**\n+ * Form builder; Configure custom search result ranking for this site.\n+ *\n+ * @ingroup forms\n+ */\n+function opensearch_admin_ranking_settings($form, &$form_state) {\n+  form_load_include($form_state, 'admin.inc', 'opensearch');\n+  $form = array(\n+    '#after_build' => array('opensearch_admin_ranking_form_after_build'),\n+  );\n+\n+  $form['opensearch_ranking_custom'] = array(\n+    '#title' => t('Enable custom ranking'),\n+    '#type' => 'checkbox',\n+    '#default_value' => variable_get('opensearch_ranking_custom', 0),\n+    '#description' => t('If enabled, the Opensearch client will use the custom ranking settings provided below when making queries to Opensearch.'),\n+  );\n+\n+  // Get our stored data.\n+  $field_data = variable_get('opensearch_ranking_fields', array());\n+\n+  if (!isset($form_state['ranking_field_count'])) {\n+    $form_state['ranking_field_count'] = count($field_data) + 1;\n+  }\n+\n+  // Wrapper, so that the AJAX callback have some place to put new elements.\n+  $form['opensearch_ranking_fields'] = array(\n+    '#title' => t('Custom ranking fields'),\n+    '#type' => 'fieldset',\n+    '#prefix' => '<div id=\"ranking-fields-wrapper\">',\n+    '#suffix' => '</div>',\n+    '#tree' => TRUE,\n+  );\n+\n+  for ($i = 0; $i < $form_state['ranking_field_count']; $i++) {\n+    $form['opensearch_ranking_fields']['fields'][$i] = array(\n+      '#type' => 'opensearch_ranking_field',\n+      '#default_value' => (isset($field_data[$i])) ? $field_data[$i] : array(),\n+    );\n+  }\n+\n+  $form['opensearch_ranking_fields']['allindexes_notice'] = array(\n+    '#markup' => t('In addition to the boost values selected above, we will add a boost value of 1 to anyIndexes for both phrase and word matches. This is done to ensure that all matches is included in the result, regardless of how they are ranked.'),\n+    '#prefix' => '<p>',\n+    '#suffix' => '</p>',\n+  );\n+\n+  $form['opensearch_ranking_fields']['add_field'] = array(\n+    '#type' => 'submit',\n+    '#value' => t('Add another ranking field'),\n+    '#submit' => array('opensearch_admin_ranking_add_more_submit'),\n+    '#weight' => 10,\n+    '#ajax' => array(\n+      'callback' => 'opensearch_admin_ranking_add_more_js',\n+      'wrapper' => 'ranking-fields-wrapper',\n+      'effect' => 'fade',\n+    ),\n+  );\n+\n+  $opensearch_sort_value = variable_get('opensearch_sort_default', 'rank_frequency');\n+  $form['opensearch_sort_default'] = array(\n+    '#title' => t('Default sort method (best match)'),\n+    '#type' => 'fieldset',\n+    '#tree' => TRUE,\n+  );\n+\n+  $form['opensearch_sort_default']['fields']['sort_type'] = array(\n+    '#title' => t('Type'),\n+    '#type' => 'select',\n+    '#options' => array(\n+      'rank_frequency' => t('Best match'),\n+      'rank_general' => t('General Rank'),\n+      'rank_none' => t('No rank'),\n+    ),\n+    '#default_value' => array('sort_type' => $opensearch_sort_value),\n+  );\n+\n+  $form['buttons']['save'] = array(\n+    '#type' => 'submit',\n+    '#value' => t('Save changes'),\n+  );\n+\n+  return $form;\n+}\n+\n+\n+/**\n+ * Submit handler for the \"Add another item\" button of a field form.\n+ *\n+ * This handler is run regardless of whether JS is enabled or not. It makes\n+ * changes to the form state. If the button was clicked with JS disabled, then\n+ * the page is reloaded with the complete rebuilt form. If the button was\n+ * clicked with JS enabled, then ajax_form_callback() calls field_add_more_js()\n+ * to return just the changed part of the form.\n+ */\n+function opensearch_admin_ranking_add_more_submit($form, &$form_state) {\n+  // Simply add another empty set of values to the field array and ask\n+  // to have the form rebuilt. The form code will take care of the rest.\n+  $form_state['ranking_field_count'] += 1;\n+  $form_state['rebuild'] = TRUE;\n+}\n+\n+/**\n+ * Ajax callback in response to a new empty widget being added to the form.\n+ */\n+function opensearch_admin_ranking_add_more_js($form, &$form_state) {\n+  return $form['opensearch_ranking_fields'];\n+}\n+\n+/**\n+ * After build callback to the ranking settings form.\n+ *\n+ * Add a little bit of CSS and JS to the form.\n+ */\n+function opensearch_admin_ranking_form_after_build($form, &$form_state) {\n+  $path = drupal_get_path('module', 'opensearch');\n+  drupal_add_css($path . '/css/opensearch_admin_ranking_form.css');\n+\n+  return $form;\n+}\n+\n+/**\n+ * Submit handler for ranking settings form.\n+ */\n+function opensearch_admin_ranking_settings_submit($form, &$form_state) {\n+  variable_set('opensearch_ranking_custom', (integer) $form_state['values']['opensearch_ranking_custom']);\n+\n+  $fields = $form_state['values']['opensearch_ranking_fields']['fields'];\n+\n+  $fields = array_filter($fields, '_opensearch_ranking_field_filter');\n+  usort($fields, '_opensearch_ranking_field_sort');\n+\n+  variable_set('opensearch_ranking_fields', $fields);\n+\n+  $default_sort = $form_state['values']['opensearch_sort_default']['fields']['sort_type'];\n+  variable_set('opensearch_sort_default', $default_sort);\n+\n+  drupal_set_message(t('Settings has been saved'), 'status');\n+}\n+\n+/**\n+ * Array_filter() callback to remove empty/deleted elements.\n+ */\n+function _opensearch_ranking_field_filter($element) {\n+  return !empty($element['field_name']);\n+}\n+\n+/**\n+ * Usort() callback to remove empty/deleted elements.\n+ */\n+function _opensearch_ranking_field_sort($a, $b) {\n+  if ($a['weight'] == $b['weight']) {\n+    return 0;\n+  }\n+  return ($a['weight'] > $b['weight']) ? -1 : 1;\n+}\n+\n+/**\n+ * Form builder; Configure custom search result ranking for this site.\n+ *\n+ * @ingroup forms\n+ */\n+function opensearch_admin_boost_settings($form, &$form_state) {\n+  form_load_include($form_state, 'admin.inc', 'opensearch');\n+  $form = array('#after_build' => array('opensearch_admin_boost_form_after_build'));\n+\n+  // Get our stored data.\n+  $field_data = variable_get('opensearch_boost_fields', array());\n+\n+  if (!isset($form_state['boost_field_count'])) {\n+    $form_state['boost_field_count'] = count($field_data);\n+  }\n+\n+  // Wrapper, so that the AJAX callback have some place to put new elements.\n+  $form['opensearch_boost_fields'] = array(\n+    '#title' => t('Custom fields boost values'),\n+    '#type' => 'fieldset',\n+    '#prefix' => '<div id=\"boost-fields-wrapper\">',\n+    '#suffix' => '</div>',\n+    '#tree' => TRUE,\n+  );\n+\n+  foreach (range(0, $form_state['boost_field_count']) as $i) {\n+    $form['opensearch_boost_fields']['fields'][$i] = array(\n+      '#type' => 'opensearch_boost_field',\n+      '#default_value' => (isset($field_data[$i])) ? $field_data[$i] : array(),\n+    );\n+  }\n+\n+  $form['opensearch_boost_fields']['add_value'] = array(\n+    '#type' => 'submit',\n+    '#value' => t('Add another boost value'),\n+    '#submit' => array('opensearch_admin_boost_add_more_submit'),\n+    '#weight' => 10,\n+    '#ajax' => array(\n+      'callback' => 'opensearch_admin_boost_add_more_js',\n+      'wrapper' => 'boost-fields-wrapper',\n+      'effect' => 'fade',\n+    ),\n+  );\n+\n+  $form['buttons']['save'] = array(\n+    '#type' => 'submit',\n+    '#value' => t('Save changes'),\n+  );\n+\n+  return $form;\n+}\n+\n+/**\n+ * Autocomplete settings.\n+ */\n+function opensearch_search_autocomplete_admin($form, &$form_state) {\n+  $form['opensearch_autocomplete'] = array(\n+    '#type' => 'fieldset',\n+    '#title' => t('Opensearch autocomplete settings'),\n+    '#tree' => TRUE,\n+  );\n+\n+  $default_settings = opensearch_search_autocomplete_settings();\n+\n+  // Attach the CSS to the form.\n+  $path = drupal_get_path('module', 'opensearch');\n+  $form['#attached'] = array(\n+    'css' => array(\n+      'type' => 'file',\n+      'data' => $path . '/css/opensearch_autocomplete_admin_form.css',\n+    ),\n+  );\n+\n+  $form['opensearch_autocomplete']['opensearch_search_autocomplete_webservice'] = array(\n+    '#type' => 'fieldset',\n+    '#title' => t('Autocomplete URL', array(), array('context' => 'opensearch_search_autocomplete')),\n+    '#tree' => FALSE,\n+    '#collapsible' => TRUE,\n+    '#collapsed' => FALSE,\n+  );\n+\n+  $form['opensearch_autocomplete']['opensearch_search_autocomplete_webservice']['opensearch_search_autocomplete_suggestion_url'] = array(\n+    '#type' => 'textfield',\n+    '#title' => t('Autocomplete URL', array(), array('context' => 'opensearch_search_autocomplete')),\n+    '#size' => 73,\n+    '#description' => t('URL to Autocomplete webservice. F.ex.: http://opensuggestion.addi.dk/1.0/', array(), array('context' => 'opensearch_search_autocomplete')),\n+    '#default_value' => variable_get('opensearch_search_autocomplete_suggestion_url',\n+      NULL),\n+    '#required' => TRUE,\n+    '#element_validate' => array('opensearch_search_autocomplete_admin_validate'),\n+  );\n+\n+  $form['opensearch_autocomplete']['opensearch_search_autocomplete_webservice']['opensearch_search_autocomplete_method'] = array(\n+    '#type' => 'textfield',\n+    '#title' => t('Autocomplete method', array(), array('context' => 'opensearch_search_autocomplete')),\n+    '#size' => 73,\n+    '#description' => t('The method to use. Currently there are two methods: terms and facets. Version 2.0 exposes facetSpell method', array(), array('context' => 'opensearch_search_autocomplete')),\n+    '#default_value' => variable_get('opensearch_search_autocomplete_method',\n+      'facets'),\n+    '#required' => TRUE,\n+  );\n+\n+  $form['opensearch_autocomplete']['opensearch_search_autocomplete_settings'] = array(\n+    '#type' => 'fieldset',\n+    '#title' => t('Autocomplete settings', array(), array('context' => 'opensearch_search_autocomplete')),\n+    '#tree' => TRUE,\n+    '#collapsible' => TRUE,\n+    '#collapsed' => FALSE,\n+  );\n+\n+  $form['opensearch_autocomplete']['opensearch_search_autocomplete_settings']['index'] = array(\n+    '#type' => 'textfield',\n+    '#title' => t('Match index', array(), array('context' => 'opensearch_search_autocomplete')),\n+    '#size' => 25,\n+    '#default_value' => $default_settings['index'],\n+    '#required' => TRUE,\n+  );\n+\n+  $form['opensearch_autocomplete']['opensearch_search_autocomplete_settings']['facetIndex'] = array(\n+    '#type' => 'textfield',\n+    '#title' => t('Facet Index', array(), array('context' => 'opensearch_search_autocomplete')),\n+    '#size' => 25,\n+    '#default_value' => $default_settings['facetIndex'],\n+    '#required' => TRUE,\n+  );\n+\n+  $form['opensearch_autocomplete']['opensearch_search_autocomplete_settings']['filterQuery'] = array(\n+    '#type' => 'textfield',\n+    '#title' => t('Filter Query', array(), array('context' => 'opensearch_search_autocomplete')),\n+    '#size' => 25,\n+    '#default_value' => $default_settings['filterQuery'],\n+  );\n+\n+  $form['opensearch_autocomplete']['opensearch_search_autocomplete_settings']['sort'] = array(\n+    '#type' => 'radios',\n+    '#title' => t('Output sort order', array(), array('context' => 'opensearch_search_autocomplete')),\n+    '#options' => array('count' => 'count', 'index' => 'index'),\n+    '#default_value' => $default_settings['sort'],\n+  );\n+\n+  $form['opensearch_autocomplete']['opensearch_search_autocomplete_settings']['agency'] = array(\n+    '#type' => 'textfield',\n+    '#title' => t('Agency', array(), array('context' => 'opensearch_search_autocomplete')),\n+    '#size' => 26,\n+    '#default_value' => $default_settings['agency'],\n+  );\n+\n+  $form['opensearch_autocomplete']['opensearch_search_autocomplete_settings']['profile'] = array(\n+    '#type' => 'textfield',\n+    '#title' => t('Profile', array(), array('context' => 'opensearch_search_autocomplete')),\n+    '#size' => 26,\n+    '#default_value' => $default_settings['profile'],\n+  );\n+\n+  $form['opensearch_autocomplete']['opensearch_search_autocomplete_settings']['maxSuggestions'] = array(\n+    '#type' => 'textfield',\n+    '#title' => t('Max suggestions', array(), array('context' => 'opensearch_search_autocomplete')),\n+    '#size' => 26,\n+    '#default_value' => $default_settings['maxSuggestions'],\n+  );\n+\n+  $form['opensearch_autocomplete']['opensearch_search_autocomplete_settings']['maxTime'] = array(\n+    '#type' => 'textfield',\n+    '#title' => t('Max request time', array(), array('context' => 'opensearch_search_autocomplete')),\n+    '#size' => 26,\n+    '#default_value' => $default_settings['maxTime'],\n+  );\n+\n+  $form['opensearch_autocomplete']['opensearch_search_autocomplete_settings']['highlight'] = array(\n+    '#type' => 'checkbox',\n+    '#title' => t('Highlight', array(), array('context' => 'opensearch_search_autocomplete')),\n+    '#description' => t('If checked, search prefix will be enclosed in highlight prefix and suffix', array(), array('context' => 'opensearch_search_autocomplete')),\n+    '#default_value' => $default_settings['highlight'],\n+    '#return_value' => 'true',\n+  );\n+\n+  $form['opensearch_autocomplete']['opensearch_search_autocomplete_settings']['highlight.pre'] = array(","path":"modules/opensearch/opensearch.admin.inc","position":131,"original_position":340,"commit_id":"96d0486caf72fe1f0ed34b0e37940e85cb4c59ed","original_commit_id":"5dbc7bea21f4e6c266526ecd7402d3f3329b9d62","user":{"login":"cableman","id":111397,"avatar_url":"https://avatars1.githubusercontent.com/u/111397?v=4","gravatar_id":"","url":"https://api.github.com/users/cableman","html_url":"https://github.com/cableman","followers_url":"https://api.github.com/users/cableman/followers","following_url":"https://api.github.com/users/cableman/following{/other_user}","gists_url":"https://api.github.com/users/cableman/gists{/gist_id}","starred_url":"https://api.github.com/users/cableman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cableman/subscriptions","organizations_url":"https://api.github.com/users/cableman/orgs","repos_url":"https://api.github.com/users/cableman/repos","events_url":"https://api.github.com/users/cableman/events{/privacy}","received_events_url":"https://api.github.com/users/cableman/received_events","type":"User","site_admin":false},"body":"👍 ","created_at":"2018-02-15T10:27:10Z","updated_at":"2018-02-15T10:27:11Z","html_url":"https://github.com/ding2/ding2/pull/982#discussion_r168434008","pull_request_url":"https://api.github.com/repos/ding2/ding2/pulls/982","author_association":"OWNER","_links":{"self":{"href":"https://api.github.com/repos/ding2/ding2/pulls/comments/168434008"},"html":{"href":"https://github.com/ding2/ding2/pull/982#discussion_r168434008"},"pull_request":{"href":"https://api.github.com/repos/ding2/ding2/pulls/982"}},"in_reply_to_id":164997088},"pull_request":{"url":"https://api.github.com/repos/ding2/ding2/pulls/982","id":165671228,"html_url":"https://github.com/ding2/ding2/pull/982","diff_url":"https://github.com/ding2/ding2/pull/982.diff","patch_url":"https://github.com/ding2/ding2/pull/982.patch","issue_url":"https://api.github.com/repos/ding2/ding2/issues/982","number":982,"state":"open","locked":false,"title":"2685: Search abstraction layer","user":{"login":"kasperg","id":73966,"avatar_url":"https://avatars2.githubusercontent.com/u/73966?v=4","gravatar_id":"","url":"https://api.github.com/users/kasperg","html_url":"https://github.com/kasperg","followers_url":"https://api.github.com/users/kasperg/followers","following_url":"https://api.github.com/users/kasperg/following{/other_user}","gists_url":"https://api.github.com/users/kasperg/gists{/gist_id}","starred_url":"https://api.github.com/users/kasperg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kasperg/subscriptions","organizations_url":"https://api.github.com/users/kasperg/orgs","repos_url":"https://api.github.com/users/kasperg/repos","events_url":"https://api.github.com/users/kasperg/events{/privacy}","received_events_url":"https://api.github.com/users/kasperg/received_events","type":"User","site_admin":false},"body":"Issue: https://platform.dandigbib.org/issues/2685\r\n\r\nThis pull request implements an abstraction layer between Open Search and other Open* services and the rest of Ding2. The purpose of this is twofold:\r\n\r\n1. The system is no longer intrinsically tied to Open* services and can be used with other search systems such as OpenPlatform and ExLibris Primo\r\n2. Code which accesses data from search services become much cleaner as it does not have to relate to Open Search specific terms and data structures.\r\n\r\nThe changes consists of 3 parts:\r\n\r\n1. Update `ting` modules to use new `search` provider\r\n2. Introduction of a new Open Search `search` provider\r\n3. Update other modules which previously depended on Open* services to use new provider\r\n\r\n### Update ting modules to use new search provider\r\n\r\nThe core of the change is the introduction of a new `search` ding provider type ([see test example](https://github.com/rvk-utd/ding2/blob/bbs-sal/modules/ding_provider/connie_search/includes/connie_search.search.inc)) and [a collection of interfaces which define what data can be returned from such a provider](https://github.com/rvk-utd/ding2/tree/bbs-sal/modules/ting/src).\r\n\r\nThese changes are all located in the `ting` and `ting_search` modules.\r\n\r\n### Introduction of a new Open Search search provider\r\n\r\nThe Open Search module has been created to provide [an implementation of the `search` provider](https://github.com/rvk-utd/ding2/blob/bbs-sal/modules/opensearch/includes/opensearch.search.inc) as well as [implementations of the new interfaces](https://github.com/rvk-utd/ding2/tree/bbs-sal/modules/opensearch/src).\r\n\r\nCode for accessing the Open* services were previously located in the `ting-client`library and in `ting.client.inc`. The library has not been changed in relation to this. The only change in that regard is the fact that it has been moved from the `ting` module to the `opensearch` module. `ting.client.inc` has been moved and renamed to [`opensearch.client.inc`](https://github.com/rvk-utd/ding2/blob/bbs-sal/modules/opensearch/opensearch.client.inc).\r\n\r\nMethods, administration interfaces variables etc. have been updated accordingly. Modules provide install/update hooks to move variables between modules.\r\n\r\n### Update other modules which previously depended on Open* services to use new provider\r\n\r\nModules which should not depend on Open Search have been updated to use new provider hooks and using methods defined by interfaces of the returned objects instead of loading `ting.client.inc` and calling `ting_get_object()`, `ting_do_search()` and accessing the deeply nested `reply` property.\r\n\r\nThe functionality of some modules are directly tied to Open* systems. These have been updated to use `opensearch.client.inc` to signal this dependency instead of calling `ting.client.inc` or the `search` provider. Such modules have also been removed as hard dependencies and are instead enabled on install time.\r\n\r\n### Backwards compatibility \r\n\r\nAs we cannot rely on all third party modules to be updated the PR currently proposes that [the `ting` module still contains a `ting.client.inc` file](https://github.com/rvk-utd/ding2/blob/bbs-sal/modules/ting/ting.client.inc) as that has been a central approach to accessing Open * services. This file contain most of the same methods as the existing file but passes all method invocations to `opensearch.client.inc` and returns the result.\r\n\r\nAll methods here have been marked as `@deprecated` and DocBlocks have been updated with instructions to use the `search` provider or `opensearch` directly.\r\n\r\nNote that commits have not been prefixed with the issue number. This project started before the issue was created.","created_at":"2018-01-29T10:50:37Z","updated_at":"2018-02-15T10:27:11Z","closed_at":null,"merged_at":null,"merge_commit_sha":null,"assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/ding2/ding2/pulls/982/commits","review_comments_url":"https://api.github.com/repos/ding2/ding2/pulls/982/comments","review_comment_url":"https://api.github.com/repos/ding2/ding2/pulls/comments{/number}","comments_url":"https://api.github.com/repos/ding2/ding2/issues/982/comments","statuses_url":"https://api.github.com/repos/ding2/ding2/statuses/96d0486caf72fe1f0ed34b0e37940e85cb4c59ed","head":{"label":"rvk-utd:bbs-sal","ref":"bbs-sal","sha":"96d0486caf72fe1f0ed34b0e37940e85cb4c59ed","user":{"login":"rvk-utd","id":5630373,"avatar_url":"https://avatars2.githubusercontent.com/u/5630373?v=4","gravatar_id":"","url":"https://api.github.com/users/rvk-utd","html_url":"https://github.com/rvk-utd","followers_url":"https://api.github.com/users/rvk-utd/followers","following_url":"https://api.github.com/users/rvk-utd/following{/other_user}","gists_url":"https://api.github.com/users/rvk-utd/gists{/gist_id}","starred_url":"https://api.github.com/users/rvk-utd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rvk-utd/subscriptions","organizations_url":"https://api.github.com/users/rvk-utd/orgs","repos_url":"https://api.github.com/users/rvk-utd/repos","events_url":"https://api.github.com/users/rvk-utd/events{/privacy}","received_events_url":"https://api.github.com/users/rvk-utd/received_events","type":"Organization","site_admin":false},"repo":{"id":92285196,"name":"ding2","full_name":"rvk-utd/ding2","owner":{"login":"rvk-utd","id":5630373,"avatar_url":"https://avatars2.githubusercontent.com/u/5630373?v=4","gravatar_id":"","url":"https://api.github.com/users/rvk-utd","html_url":"https://github.com/rvk-utd","followers_url":"https://api.github.com/users/rvk-utd/followers","following_url":"https://api.github.com/users/rvk-utd/following{/other_user}","gists_url":"https://api.github.com/users/rvk-utd/gists{/gist_id}","starred_url":"https://api.github.com/users/rvk-utd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rvk-utd/subscriptions","organizations_url":"https://api.github.com/users/rvk-utd/orgs","repos_url":"https://api.github.com/users/rvk-utd/repos","events_url":"https://api.github.com/users/rvk-utd/events{/privacy}","received_events_url":"https://api.github.com/users/rvk-utd/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/rvk-utd/ding2","description":"Ding install profile","fork":true,"url":"https://api.github.com/repos/rvk-utd/ding2","forks_url":"https://api.github.com/repos/rvk-utd/ding2/forks","keys_url":"https://api.github.com/repos/rvk-utd/ding2/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rvk-utd/ding2/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rvk-utd/ding2/teams","hooks_url":"https://api.github.com/repos/rvk-utd/ding2/hooks","issue_events_url":"https://api.github.com/repos/rvk-utd/ding2/issues/events{/number}","events_url":"https://api.github.com/repos/rvk-utd/ding2/events","assignees_url":"https://api.github.com/repos/rvk-utd/ding2/assignees{/user}","branches_url":"https://api.github.com/repos/rvk-utd/ding2/branches{/branch}","tags_url":"https://api.github.com/repos/rvk-utd/ding2/tags","blobs_url":"https://api.github.com/repos/rvk-utd/ding2/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rvk-utd/ding2/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rvk-utd/ding2/git/refs{/sha}","trees_url":"https://api.github.com/repos/rvk-utd/ding2/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rvk-utd/ding2/statuses/{sha}","languages_url":"https://api.github.com/repos/rvk-utd/ding2/languages","stargazers_url":"https://api.github.com/repos/rvk-utd/ding2/stargazers","contributors_url":"https://api.github.com/repos/rvk-utd/ding2/contributors","subscribers_url":"https://api.github.com/repos/rvk-utd/ding2/subscribers","subscription_url":"https://api.github.com/repos/rvk-utd/ding2/subscription","commits_url":"https://api.github.com/repos/rvk-utd/ding2/commits{/sha}","git_commits_url":"https://api.github.com/repos/rvk-utd/ding2/git/commits{/sha}","comments_url":"https://api.github.com/repos/rvk-utd/ding2/comments{/number}","issue_comment_url":"https://api.github.com/repos/rvk-utd/ding2/issues/comments{/number}","contents_url":"https://api.github.com/repos/rvk-utd/ding2/contents/{+path}","compare_url":"https://api.github.com/repos/rvk-utd/ding2/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rvk-utd/ding2/merges","archive_url":"https://api.github.com/repos/rvk-utd/ding2/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rvk-utd/ding2/downloads","issues_url":"https://api.github.com/repos/rvk-utd/ding2/issues{/number}","pulls_url":"https://api.github.com/repos/rvk-utd/ding2/pulls{/number}","milestones_url":"https://api.github.com/repos/rvk-utd/ding2/milestones{/number}","notifications_url":"https://api.github.com/repos/rvk-utd/ding2/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rvk-utd/ding2/labels{/name}","releases_url":"https://api.github.com/repos/rvk-utd/ding2/releases{/id}","deployments_url":"https://api.github.com/repos/rvk-utd/ding2/deployments","created_at":"2017-05-24T11:31:15Z","updated_at":"2017-05-24T11:31:19Z","pushed_at":"2018-02-12T13:11:56Z","git_url":"git://github.com/rvk-utd/ding2.git","ssh_url":"git@github.com:rvk-utd/ding2.git","clone_url":"https://github.com/rvk-utd/ding2.git","svn_url":"https://github.com/rvk-utd/ding2","homepage":"","size":94377,"stargazers_count":0,"watchers_count":0,"language":"PHP","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":1,"mirror_url":null,"archived":false,"open_issues_count":2,"license":{"key":"other","name":"Other","spdx_id":null,"url":null},"forks":1,"open_issues":2,"watchers":0,"default_branch":"bbs-master"}},"base":{"label":"ding2:master","ref":"master","sha":"7fae0ce885b9e961eee39023ce981e70b42552ec","user":{"login":"ding2","id":564698,"avatar_url":"https://avatars0.githubusercontent.com/u/564698?v=4","gravatar_id":"","url":"https://api.github.com/users/ding2","html_url":"https://github.com/ding2","followers_url":"https://api.github.com/users/ding2/followers","following_url":"https://api.github.com/users/ding2/following{/other_user}","gists_url":"https://api.github.com/users/ding2/gists{/gist_id}","starred_url":"https://api.github.com/users/ding2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ding2/subscriptions","organizations_url":"https://api.github.com/users/ding2/orgs","repos_url":"https://api.github.com/users/ding2/repos","events_url":"https://api.github.com/users/ding2/events{/privacy}","received_events_url":"https://api.github.com/users/ding2/received_events","type":"Organization","site_admin":false},"repo":{"id":1266749,"name":"ding2","full_name":"ding2/ding2","owner":{"login":"ding2","id":564698,"avatar_url":"https://avatars0.githubusercontent.com/u/564698?v=4","gravatar_id":"","url":"https://api.github.com/users/ding2","html_url":"https://github.com/ding2","followers_url":"https://api.github.com/users/ding2/followers","following_url":"https://api.github.com/users/ding2/following{/other_user}","gists_url":"https://api.github.com/users/ding2/gists{/gist_id}","starred_url":"https://api.github.com/users/ding2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ding2/subscriptions","organizations_url":"https://api.github.com/users/ding2/orgs","repos_url":"https://api.github.com/users/ding2/repos","events_url":"https://api.github.com/users/ding2/events{/privacy}","received_events_url":"https://api.github.com/users/ding2/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/ding2/ding2","description":"Ding install profile","fork":false,"url":"https://api.github.com/repos/ding2/ding2","forks_url":"https://api.github.com/repos/ding2/ding2/forks","keys_url":"https://api.github.com/repos/ding2/ding2/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ding2/ding2/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ding2/ding2/teams","hooks_url":"https://api.github.com/repos/ding2/ding2/hooks","issue_events_url":"https://api.github.com/repos/ding2/ding2/issues/events{/number}","events_url":"https://api.github.com/repos/ding2/ding2/events","assignees_url":"https://api.github.com/repos/ding2/ding2/assignees{/user}","branches_url":"https://api.github.com/repos/ding2/ding2/branches{/branch}","tags_url":"https://api.github.com/repos/ding2/ding2/tags","blobs_url":"https://api.github.com/repos/ding2/ding2/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ding2/ding2/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ding2/ding2/git/refs{/sha}","trees_url":"https://api.github.com/repos/ding2/ding2/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ding2/ding2/statuses/{sha}","languages_url":"https://api.github.com/repos/ding2/ding2/languages","stargazers_url":"https://api.github.com/repos/ding2/ding2/stargazers","contributors_url":"https://api.github.com/repos/ding2/ding2/contributors","subscribers_url":"https://api.github.com/repos/ding2/ding2/subscribers","subscription_url":"https://api.github.com/repos/ding2/ding2/subscription","commits_url":"https://api.github.com/repos/ding2/ding2/commits{/sha}","git_commits_url":"https://api.github.com/repos/ding2/ding2/git/commits{/sha}","comments_url":"https://api.github.com/repos/ding2/ding2/comments{/number}","issue_comment_url":"https://api.github.com/repos/ding2/ding2/issues/comments{/number}","contents_url":"https://api.github.com/repos/ding2/ding2/contents/{+path}","compare_url":"https://api.github.com/repos/ding2/ding2/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ding2/ding2/merges","archive_url":"https://api.github.com/repos/ding2/ding2/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ding2/ding2/downloads","issues_url":"https://api.github.com/repos/ding2/ding2/issues{/number}","pulls_url":"https://api.github.com/repos/ding2/ding2/pulls{/number}","milestones_url":"https://api.github.com/repos/ding2/ding2/milestones{/number}","notifications_url":"https://api.github.com/repos/ding2/ding2/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ding2/ding2/labels{/name}","releases_url":"https://api.github.com/repos/ding2/ding2/releases{/id}","deployments_url":"https://api.github.com/repos/ding2/ding2/deployments","created_at":"2011-01-18T10:54:00Z","updated_at":"2016-10-22T05:55:29Z","pushed_at":"2018-02-15T09:59:10Z","git_url":"git://github.com/ding2/ding2.git","ssh_url":"git@github.com:ding2/ding2.git","clone_url":"https://github.com/ding2/ding2.git","svn_url":"https://github.com/ding2/ding2","homepage":"","size":92856,"stargazers_count":12,"watchers_count":12,"language":"PHP","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":37,"mirror_url":null,"archived":false,"open_issues_count":166,"license":{"key":"other","name":"Other","spdx_id":null,"url":null},"forks":37,"open_issues":166,"watchers":12,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/ding2/ding2/pulls/982"},"html":{"href":"https://github.com/ding2/ding2/pull/982"},"issue":{"href":"https://api.github.com/repos/ding2/ding2/issues/982"},"comments":{"href":"https://api.github.com/repos/ding2/ding2/issues/982/comments"},"review_comments":{"href":"https://api.github.com/repos/ding2/ding2/pulls/982/comments"},"review_comment":{"href":"https://api.github.com/repos/ding2/ding2/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/ding2/ding2/pulls/982/commits"},"statuses":{"href":"https://api.github.com/repos/ding2/ding2/statuses/96d0486caf72fe1f0ed34b0e37940e85cb4c59ed"}},"author_association":"OWNER"}}
{"actor":{"display_login":"cableman"}}