{"action":"created","comment":{"url":"https://api.github.com/repos/aodn/data-services/pulls/comments/64528977","id":64528977,"diff_hunk":"@@ -0,0 +1,388 @@\n+#!/usr/bin/env python\n+# -*- coding: utf-8 -*-\n+\"\"\"\n+Burst Average Product creation for WQM and CTD FV01 files\n+./burst_average_product.py input_netcdf.nc /ouput_dir\n+TODO\n+- logging\n+- case when all vars are empty ?ie no valid data\n+- handle maisSalinity\n+\"\"\"\n+from datetime import datetime\n+from file_classifier import MooringFileClassifier\n+from generate_netcdf_att import generate_netcdf_att, get_imos_parameter_info\n+from math import isnan\n+from netCDF4 import Dataset, num2date, date2num\n+import numpy as np\n+import os\n+import pandas as pd\n+import re\n+import shutil\n+import sys\n+import tempfile\n+import time\n+\n+\n+def get_input_file_rel_path(input_netcdf_file_path):\n+    \"\"\"\n+    find the relative path hierarchy of an input FV01 file. The value will be\n+    used in a gatt of the burst netcdf file\n+    \"\"\"\n+    # following lines could maybe be removed. Testing if opening the same file\n+    # twice in subfunction would have an effect on segmentation fault issue\n+    # tempdir = tempfile.mkdtemp()\n+    # shutil.copy(input_netcdf_file_path, tempdir)\n+    # file_path = MooringFileClassifier.dest_path(os.path.join(tempdir, os.path.basename(input_netcdf_file_path)))\n+    # shutil.rmtree(tempdir)\n+    file_path = MooringFileClassifier.dest_path(input_netcdf_file_path)\n+    return file_path\n+\n+def get_burst_duration(netcdf_file_obj):\n+    \"\"\"\n+    returns the burst duration as float defined in the NetCDF file if exists\n+    \"\"\"\n+    burst_duration  = getattr(netcdf_file_obj, 'instrument_burst_duration', 60.0)\n+    return burst_duration\n+\n+def min_bad_qc_flag(varname):\n+    \"\"\"returns the min IMOS IODE qc flag value to get rid of per variable\"\"\"\n+    default_min_qc_flag_value = 3\n+    dict_var = {\n+        'CHLF':     4,\n+        'CHLR':     4,\n+        'CHLU':     4,\n+        'CPHL':     4,\n+        'DOX1_2':   3,\n+        'DOX2':     3,\n+        'FLU2':     4,\n+        'FLNTU':    4,\n+        'PRES_REL': 4,\n+        'PSAL':     4,\n+        'TEMP':     4,\n+        'TURB':     4,\n+    }\n+\n+    if varname in dict_var.keys():\n+        return dict_var[varname]\n+    else:\n+        return default_min_qc_flag_value\n+\n+def create_burst_average_var(netcdf_file_obj):\n+    \"\"\"\n+    create burst data from all vars available in netcdf\n+    \"\"\"\n+    time_values              = get_time_val(netcdf_file_obj)\n+    varname_to_burst_average = list_var_to_average(netcdf_file_obj)\n+    burst_duration           = get_burst_duration(netcdf_file_obj)\n+    burst_vars               = {}\n+\n+    for varname in varname_to_burst_average:\n+        var_values, var_qc_flag_exclusion = get_var_val_var_qc_exclusion(\n+            netcdf_file_obj, varname, min_bad_qc_flag(varname)\n+        )\n+        burst_vars[varname] = list(\n+            burst_average_data(time_values, var_values, burst_duration, var_qc_flag_exclusion)\n+        )\n+\n+    burst_vars = clean_burst_vars(burst_vars)\n+    return burst_vars\n+\n+def clean_burst_vars(burst_vars):\n+    \"\"\"\n+    For every burst var created, look for the first index of non NaN value. The\n+    lower value will be the one kept, and the new start index of each burst variable\n+    including the TIME.\n+    \"\"\"\n+    min_index = None\n+\n+    for var in burst_vars.keys():\n+        var_mean_burst = burst_vars[var][1] # first non TIME product\n+        if not np.isnan(var_mean_burst).all():\n+            min_index_var  = next(x for x, y in enumerate(var_mean_burst) if not isnan(y))\n+        else:\n+            min_index_var = 0\n+\n+        if min_index == None:\n+            min_index = min_index_var\n+        else:\n+            min_index = min(min_index, min_index_var)\n+\n+    # remove the first common NaN to all variables\n+    for var in burst_vars.keys():\n+        for product in range(len(burst_vars[var])):\n+            burst_vars[var][product] = burst_vars[var][product][min_index:-1]\n+\n+    # look for last non NaN. we just have to reverse the list\n+    max_non_nan_idx = None\n+    for var in burst_vars.keys():\n+        var_mean_burst       = burst_vars[var][1] # first non TIME product\n+        var_mean_burst       = pd.Series(var_mean_burst) # create a pandas series to find easily last non nan index\n+        max_last_non_nan_var = var_mean_burst.last_valid_index()\n+        if max_non_nan_idx == None:\n+            max_non_nan_idx = max_last_non_nan_var\n+        else:\n+            max_non_nan_idx = max(max_non_nan_idx, max_last_non_nan_var)\n+\n+    # remove the last common NaN to all variables\n+    if max_non_nan_idx is not None:\n+        for var in burst_vars.keys():\n+            for product in range(len(burst_vars[var])):\n+                burst_vars[var][product] = burst_vars[var][product][:max_non_nan_idx]\n+\n+    return burst_vars\n+\n+def get_time_val(netcdf_file_obj):\n+    \"\"\"\n+    return the TIME numeric values from a NetCDF file\n+    \"\"\"\n+    time        = netcdf_file_obj.variables['TIME']\n+    time_values = time[:]\n+    return time_values\n+\n+def get_var_val_var_qc_exclusion(netcdf_file_obj, varname, qc_flag):\n+    \"\"\"\n+    for a qc flag values [0:9], returns the var_values array, and var_qc_flag_exclusion\n+    which is a boolean array returning True for all qc >= qc_flag\n+\n+    Also exlude all TIME values outside of deployment range as defined in gatts\n+    \"\"\"\n+    var_values            = netcdf_file_obj.variables[varname][:]\n+    var_qc_flag_exclusion = netcdf_file_obj.variables['%s_quality_control' % varname][:] >= qc_flag\n+\n+    # we exclude as well ALL TIMES before date_deployment_start, and after\n+    # date_deployment_end\n+    time                  = netcdf_file_obj.variables['TIME']\n+    date_deployment_start = date2num(datetime.strptime(netcdf_file_obj.time_deployment_start, '%Y-%m-%dT%H:%M:%SZ'), time.units, time.calendar)\n+    date_deployment_end   = date2num(datetime.strptime(netcdf_file_obj.time_deployment_end, '%Y-%m-%dT%H:%M:%SZ'), time.units, time.calendar)\n+\n+    time_before = date_deployment_start >= time[:]\n+    time_after  = date_deployment_end <= time[:]\n+\n+    var_qc_flag_exclusion = [a or b for a, b in zip(time_before, var_qc_flag_exclusion)]\n+    var_qc_flag_exclusion = [a or b for a, b in zip(time_after, var_qc_flag_exclusion)]\n+\n+    return var_values, var_qc_flag_exclusion\n+\n+def list_var_to_average(netcdf_file_obj):\n+    \"\"\"\n+    return a list of variable to create a burst average for\n+    \"\"\"\n+    var_list = netcdf_file_obj.variables.keys()\n+    var_list = [x for x in var_list if not x.endswith('_quality_control')]\n+\n+    for var_to_remove in ['TIME', 'LATITUDE', 'LONGITUDE', 'NOMINAL_DEPTH', 'VOLT', 'TIMESERIES', 'SSPD', 'CNDC']:\n+        if var_to_remove in var_list:\n+            var_list.remove(var_to_remove)\n+\n+    return var_list\n+\n+def burst_average_data(time_values, var_values, burst_duration, var_qc_exclusion):\n+    \"\"\"\n+    create burst average data for var_values. This is the core of the script\n+    \"\"\"\n+    n_seconds_day = 24 * 3600\n+    difft         = np.round(np.diff(time_values) * n_seconds_day) # this gives us a spike for each new burst\n+    allowed_gap   = burst_duration\n+    fill_value    = float('nan')\n+\n+    # look for start index of each burst, ie the index of each new spike of\n+    # difft variable\n+    idx_spike = [0] # initialise first index\n+    spikes    = np.where(difft >= allowed_gap)[0] + 1\n+    idx_spike.extend(spikes)\n+\n+    # initialise arrays\n+    time_mean_burst   = []\n+    var_mean_burst    = []\n+    var_min_burst     = []\n+    var_max_burst     = []\n+    var_std_burst     = []\n+    var_num_obs_burst = []\n+\n+    for idx_spike_idx, idx_spike_val in enumerate(idx_spike[:-1]):\n+        index_burst_range = range(idx_spike_val, idx_spike[idx_spike_idx + 1])\n+\n+        # burst average of TIME variable. All the range of the burst is used\n+        time_mean_burst.append((time_values[index_burst_range[0]] + time_values[index_burst_range[-1]]) / 2)\n+\n+        # For NON TIME variables, the operations are only performed in respect\n+        # to boolean values found in var_qc_exclusion variable.\n+        # this var_qc_exclusion variable is set to True for all IMOS IODE flags\n+        # greater than a specific value\n+        valid_index_burst_range = [val for val in index_burst_range if not var_qc_exclusion[val]]\n+\n+        # condition in case no good qc data was found for one burst\n+        if valid_index_burst_range:\n+            var_mean_burst   .append(np.mean(var_values[valid_index_burst_range]))\n+            var_min_burst    .append(np.min(var_values[valid_index_burst_range]))\n+            var_max_burst    .append(np.max(var_values[valid_index_burst_range]))\n+            var_std_burst    .append(np.std(var_values[valid_index_burst_range]))\n+            var_num_obs_burst.append(len(valid_index_burst_range))\n+        else:\n+            var_mean_burst   .append(fill_value)\n+            var_min_burst    .append(fill_value)\n+            var_max_burst    .append(fill_value)\n+            var_std_burst    .append(fill_value)\n+            var_num_obs_burst.append(0)\n+\n+    return time_mean_burst, var_mean_burst, var_min_burst, var_max_burst, var_std_burst, var_num_obs_burst\n+\n+def generate_netcdf_burst_filename(netcdf_file_obj, burst_vars):\n+    \"\"\"\n+    generate the filename of a burst average netcdf for both CTD and WQM\n+    \"\"\"\n+    site_code         = netcdf_file_obj.site_code\n+    input_netcdf_name = os.path.basename(input_netcdf_file_path)\n+    pattern           = re.compile(\"^(IMOS_.*)_([0-9]{8}T[0-9]{6}Z)_(.*)_(FV0[0-9])_(.*)_END\")\n+    match_group       = pattern.match(input_netcdf_name)\n+\n+    time_burst_vals = burst_vars['TEMP'][0]\n+    time_min        = num2date(time_burst_vals, netcdf_file_obj['TIME'].units, netcdf_file_obj['TIME'].calendar).min().strftime('%Y%m%dT%H%M%SZ')\n+    time_max        = num2date(time_burst_vals, netcdf_file_obj['TIME'].units, netcdf_file_obj['TIME'].calendar).max().strftime('%Y%m%dT%H%M%SZ')\n+    burst_filename  = \"%s_%s_%s_FV02_%s-burst-averaged_END-%s_C-%s.nc\" % (match_group.group(1), time_min, \\\n+                                                                          site_code, match_group.group(5), \\\n+                                                                          time_max, datetime.now().strftime(\"%Y%m%dT%H%M%SZ\"))\n+\n+    return burst_filename\n+\n+def create_burst_average_netcdf(input_netcdf_file_path, output_dir):\n+    \"\"\"\n+    generate the burst netcdf file for WQM product.\n+    see variable conf_file if editing of gatt and var att need to be done\n+    \"\"\"\n+    input_netcdf_obj = Dataset(input_netcdf_file_path, 'r')\n+    burst_vars       = create_burst_average_var(input_netcdf_obj)\n+    time_burst_vals  = burst_vars['TEMP'][0]\n+    tmp_netcdf_dir   = tempfile.mkdtemp()\n+\n+    output_netcdf_file_path = os.path.join(tmp_netcdf_dir, generate_netcdf_burst_filename(input_netcdf_obj, burst_vars))\n+    output_netcdf_obj       = Dataset(output_netcdf_file_path, \"w\", format=\"NETCDF4\")\n+\n+    # read gatts from input, add them to output. Some gatts will be\n+    # overwritten\n+    input_gatts     = input_netcdf_obj.__dict__.keys()\n+    gatt_to_dispose = ['author', 'toolbox_input_file', 'file_version_quality_control', 'quality_control_set',\n+                       'history', 'CoordSysBuilder_', 'netcdf_filename', 'metadata', 'featureType']\n+    for gatt in input_gatts:\n+        if gatt not in gatt_to_dispose:\n+            setattr(output_netcdf_obj, gatt, getattr(input_netcdf_obj, gatt))\n+\n+    if 'WQM' in output_netcdf_obj.instrument:\n+        instrument_type = 'WQM'\n+    elif 'CTD' in output_netcdf_obj.instrument:\n+        instrument_type = 'CTD'\n+\n+    if instrument_type == 'WQM':\n+        output_netcdf_obj.title = 'Burst-averaged biogeochemical measurements at %s' % (input_netcdf_obj.site_code)\n+    elif instrument_type == 'CTD':\n+        output_netcdf_obj.title = 'Burst-averaged moored CTD measurements at %s' % (input_netcdf_obj.site_code)\n+\n+    output_netcdf_obj.input_file   = get_input_file_rel_path(input_netcdf_file_path)\n+    output_netcdf_obj.history      = \"Created \" + time.ctime(time.time())\n+    output_netcdf_obj.date_created = datetime.now().strftime(\"%Y-%m-%dT%H:%M:%SZ\")\n+\n+    if np.ndim(input_netcdf_obj['LATITUDE'][:]) == 0 :\n+        output_netcdf_obj.geospatial_lat_min = input_netcdf_obj['LATITUDE'][0]\n+        output_netcdf_obj.geospatial_lat_max = input_netcdf_obj['LATITUDE'][0]\n+        output_netcdf_obj.geospatial_lon_min = input_netcdf_obj['LONGITUDE'][0]\n+        output_netcdf_obj.geospatial_lon_max = input_netcdf_obj['LONGITUDE'][0]\n+    else:\n+        output_netcdf_obj.geospatial_lat_min = min(input_netcdf_obj['LATITUDE'][:])\n+        output_netcdf_obj.geospatial_lat_max = min(input_netcdf_obj['LATITUDE'][:])\n+        output_netcdf_obj.geospatial_lon_min = min(input_netcdf_obj['LONGITUDE'][:])\n+        output_netcdf_obj.geospatial_lon_max = min(input_netcdf_obj['LONGITUDE'][:])\n+\n+    output_netcdf_obj.geospatial_vertical_min = min(burst_vars['DEPTH'][1])\n+    output_netcdf_obj.geospatial_vertical_max = max(burst_vars['DEPTH'][1])\n+    output_netcdf_obj.time_coverage_start     = num2date(time_burst_vals, input_netcdf_obj['TIME'].units, input_netcdf_obj['TIME'].calendar).min().strftime('%Y-%m-%dT%H:%M:%SZ')\n+    output_netcdf_obj.time_coverage_end       = num2date(time_burst_vals, input_netcdf_obj['TIME'].units, input_netcdf_obj['TIME'].calendar).max().strftime('%Y-%m-%dT%H:%M:%SZ')\n+\n+    # set up dimensions\n+    output_netcdf_obj.createDimension(\"TIME\", len(burst_vars['TEMP'][0]))\n+\n+    # set up variables\n+    var_time = output_netcdf_obj.createVariable(\"TIME\", \"d\", (\"TIME\",), fill_value=get_imos_parameter_info('TIME', '_FillValue'))\n+    var_lat  = output_netcdf_obj.createVariable(\"LATITUDE\", \"d\", fill_value=get_imos_parameter_info('LATITUDE', '_FillValue'))\n+    var_lon  = output_netcdf_obj.createVariable(\"LONGITUDE\", \"d\", fill_value=get_imos_parameter_info('LONGITUDE', '_FillValue'))\n+\n+    for var in burst_vars.keys():\n+        fillvalue = get_imos_parameter_info(var, '_FillValue')\n+        if fillvalue == []:\n+            fillvalue = 999999.0\n+\n+        output_netcdf_obj.createVariable(var, \"f4\", (\"TIME\",), fill_value=fillvalue)\n+        output_netcdf_obj.createVariable('%s_burst_min' % var, \"f4\", (\"TIME\",), fill_value=fillvalue)\n+        output_netcdf_obj.createVariable('%s_burst_max' % var, \"f4\", (\"TIME\",), fill_value=fillvalue)\n+        output_netcdf_obj.createVariable('%s_burst_sd' % var, \"f4\", (\"TIME\",), fill_value=fillvalue)\n+        output_netcdf_obj.createVariable('%s_num_obs' % var, \"i4\", (\"TIME\",), fill_value=fillvalue)\n+\n+        # set up 'bonus' var att from original FV01 file to FV02\n+        input_var_object   = input_netcdf_obj[var]\n+        input_var_list_att = input_var_object.__dict__.keys()\n+        var_att_disposable = ['name', 'standard_name', 'long_name', 'valid_min', 'valid_max', '_FillValue', 'ancillary_variables', 'axis', 'units', 'ChunkSize']\n+        for var_att in [att for att in input_var_list_att if att not in var_att_disposable]:\n+            setattr(output_netcdf_obj[var], var_att, getattr(input_netcdf_obj[var], var_att))\n+            if var_att != 'comment':\n+                setattr(output_netcdf_obj['%s_burst_min' % var], var_att, getattr(input_netcdf_obj[var], var_att))\n+                setattr(output_netcdf_obj['%s_burst_max' % var], var_att, getattr(input_netcdf_obj[var], var_att))\n+                setattr(output_netcdf_obj['%s_burst_sd' % var], var_att, getattr(input_netcdf_obj[var], var_att))\n+\n+        var_units = get_imos_parameter_info(var, 'units')\n+        if var_units:\n+            setattr(output_netcdf_obj[var], 'units', var_units)\n+            setattr(output_netcdf_obj['%s_burst_min' % var], 'units', var_units)\n+            setattr(output_netcdf_obj['%s_burst_max' % var], 'units', var_units)\n+            setattr(output_netcdf_obj['%s_burst_sd' % var], 'units', var_units)\n+\n+        if get_imos_parameter_info(var, 'standard_name'):\n+            setattr(output_netcdf_obj['%s_num_obs' % var], 'standard_name', \"%s number_of_observations\" % get_imos_parameter_info(var, 'standard_name'))\n+\n+        setattr(output_netcdf_obj['%s_num_obs' % var], 'units', \"1\")\n+        if var != 'DEPTH':\n+            setattr(output_netcdf_obj[var], \"coordinates\" , \"TIME LATITUDE LONGITUDE DEPTH\")\n+\n+        # set up var values\n+        output_netcdf_obj[var][:]                  = np.ma.masked_invalid(burst_vars[var][1])\n+        output_netcdf_obj['%s_burst_min' % var][:] = np.ma.masked_invalid(burst_vars[var][2])\n+        output_netcdf_obj['%s_burst_max' % var][:] = np.ma.masked_invalid(burst_vars[var][3])\n+        output_netcdf_obj['%s_burst_sd' % var][:]  = np.ma.masked_invalid(burst_vars[var][4])\n+        output_netcdf_obj['%s_num_obs' % var][:]   = np.ma.masked_invalid(burst_vars[var][5])\n+\n+    # add gatts and variable attributes as stored in config files\n+    conf_file_generic = os.path.join(os.path.dirname(__file__), 'generate_nc_file_att')\n+    generate_netcdf_att(output_netcdf_obj, conf_file_generic, conf_file_point_of_truth = True)\n+\n+    if instrument_type == 'WQM':\n+        conf_file = os.path.join(os.path.dirname(__file__), 'generate_wqm_nc_file_gatt')\n+    elif instrument_type == 'CTD':\n+        conf_file = os.path.join(os.path.dirname(__file__), 'generate_ctd_nc_file_gatt')\n+    generate_netcdf_att(output_netcdf_obj, conf_file)\n+\n+    # append original comment gatt to burst average comment gatt\n+    if hasattr(input_netcdf_obj, 'comment'):\n+        gatt = 'comment'\n+        setattr(output_netcdf_obj, gatt, '%s. %s' % (getattr(input_netcdf_obj, gatt), getattr(output_netcdf_obj, gatt) ))\n+\n+    # add values to variables\n+    output_netcdf_obj['TIME'][:]      = np.ma.masked_invalid(time_burst_vals)\n+    output_netcdf_obj['LATITUDE'][:]  = np.ma.masked_invalid(input_netcdf_obj['LATITUDE'][:])\n+    output_netcdf_obj['LONGITUDE'][:] = np.ma.masked_invalid(input_netcdf_obj['LONGITUDE'][:])\n+\n+    output_netcdf_obj.close()\n+    input_netcdf_obj.close()","path":"ANMN/burst_averaged_product/burst_average_product.py","position":372,"original_position":372,"commit_id":"9440b3057c60f21f03a8fb92e249683aa8a5bea6","original_commit_id":"9440b3057c60f21f03a8fb92e249683aa8a5bea6","user":{"login":"lbesnard","id":2382814,"avatar_url":"https://avatars.githubusercontent.com/u/2382814?v=3","gravatar_id":"","url":"https://api.github.com/users/lbesnard","html_url":"https://github.com/lbesnard","followers_url":"https://api.github.com/users/lbesnard/followers","following_url":"https://api.github.com/users/lbesnard/following{/other_user}","gists_url":"https://api.github.com/users/lbesnard/gists{/gist_id}","starred_url":"https://api.github.com/users/lbesnard/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lbesnard/subscriptions","organizations_url":"https://api.github.com/users/lbesnard/orgs","repos_url":"https://api.github.com/users/lbesnard/repos","events_url":"https://api.github.com/users/lbesnard/events{/privacy}","received_events_url":"https://api.github.com/users/lbesnard/received_events","type":"User","site_admin":false},"body":" @mhidas \r\nCould you please test this script on your PO box ? I somehow get a segmentation fault, apparently due closing file objects. And it works well on my host","created_at":"2016-05-25T07:49:44Z","updated_at":"2016-05-25T07:49:44Z","html_url":"https://github.com/aodn/data-services/pull/462#discussion_r64528977","pull_request_url":"https://api.github.com/repos/aodn/data-services/pulls/462","_links":{"self":{"href":"https://api.github.com/repos/aodn/data-services/pulls/comments/64528977"},"html":{"href":"https://github.com/aodn/data-services/pull/462#discussion_r64528977"},"pull_request":{"href":"https://api.github.com/repos/aodn/data-services/pulls/462"}}},"pull_request":{"url":"https://api.github.com/repos/aodn/data-services/pulls/462","id":70501733,"html_url":"https://github.com/aodn/data-services/pull/462","diff_url":"https://github.com/aodn/data-services/pull/462.diff","patch_url":"https://github.com/aodn/data-services/pull/462.patch","issue_url":"https://api.github.com/repos/aodn/data-services/issues/462","number":462,"state":"open","locked":false,"title":"Burst average python conversion","user":{"login":"lbesnard","id":2382814,"avatar_url":"https://avatars.githubusercontent.com/u/2382814?v=3","gravatar_id":"","url":"https://api.github.com/users/lbesnard","html_url":"https://github.com/lbesnard","followers_url":"https://api.github.com/users/lbesnard/followers","following_url":"https://api.github.com/users/lbesnard/following{/other_user}","gists_url":"https://api.github.com/users/lbesnard/gists{/gist_id}","starred_url":"https://api.github.com/users/lbesnard/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lbesnard/subscriptions","organizations_url":"https://api.github.com/users/lbesnard/orgs","repos_url":"https://api.github.com/users/lbesnard/repos","events_url":"https://api.github.com/users/lbesnard/events{/privacy}","received_events_url":"https://api.github.com/users/lbesnard/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-05-18T10:15:12Z","updated_at":"2016-05-25T07:49:45Z","closed_at":null,"merged_at":null,"merge_commit_sha":"8eebc8238ce9b84de72ed95672dbb5baa52b8096","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/aodn/data-services/pulls/462/commits","review_comments_url":"https://api.github.com/repos/aodn/data-services/pulls/462/comments","review_comment_url":"https://api.github.com/repos/aodn/data-services/pulls/comments{/number}","comments_url":"https://api.github.com/repos/aodn/data-services/issues/462/comments","statuses_url":"https://api.github.com/repos/aodn/data-services/statuses/9440b3057c60f21f03a8fb92e249683aa8a5bea6","head":{"label":"aodn:burstAveragePythonConversion","ref":"burstAveragePythonConversion","sha":"9440b3057c60f21f03a8fb92e249683aa8a5bea6","user":{"login":"aodn","id":2802166,"avatar_url":"https://avatars.githubusercontent.com/u/2802166?v=3","gravatar_id":"","url":"https://api.github.com/users/aodn","html_url":"https://github.com/aodn","followers_url":"https://api.github.com/users/aodn/followers","following_url":"https://api.github.com/users/aodn/following{/other_user}","gists_url":"https://api.github.com/users/aodn/gists{/gist_id}","starred_url":"https://api.github.com/users/aodn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aodn/subscriptions","organizations_url":"https://api.github.com/users/aodn/orgs","repos_url":"https://api.github.com/users/aodn/repos","events_url":"https://api.github.com/users/aodn/events{/privacy}","received_events_url":"https://api.github.com/users/aodn/received_events","type":"Organization","site_admin":false},"repo":{"id":17236639,"name":"data-services","full_name":"aodn/data-services","owner":{"login":"aodn","id":2802166,"avatar_url":"https://avatars.githubusercontent.com/u/2802166?v=3","gravatar_id":"","url":"https://api.github.com/users/aodn","html_url":"https://github.com/aodn","followers_url":"https://api.github.com/users/aodn/followers","following_url":"https://api.github.com/users/aodn/following{/other_user}","gists_url":"https://api.github.com/users/aodn/gists{/gist_id}","starred_url":"https://api.github.com/users/aodn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aodn/subscriptions","organizations_url":"https://api.github.com/users/aodn/orgs","repos_url":"https://api.github.com/users/aodn/repos","events_url":"https://api.github.com/users/aodn/events{/privacy}","received_events_url":"https://api.github.com/users/aodn/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/aodn/data-services","description":"Data Services scripts","fork":false,"url":"https://api.github.com/repos/aodn/data-services","forks_url":"https://api.github.com/repos/aodn/data-services/forks","keys_url":"https://api.github.com/repos/aodn/data-services/keys{/key_id}","collaborators_url":"https://api.github.com/repos/aodn/data-services/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/aodn/data-services/teams","hooks_url":"https://api.github.com/repos/aodn/data-services/hooks","issue_events_url":"https://api.github.com/repos/aodn/data-services/issues/events{/number}","events_url":"https://api.github.com/repos/aodn/data-services/events","assignees_url":"https://api.github.com/repos/aodn/data-services/assignees{/user}","branches_url":"https://api.github.com/repos/aodn/data-services/branches{/branch}","tags_url":"https://api.github.com/repos/aodn/data-services/tags","blobs_url":"https://api.github.com/repos/aodn/data-services/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/aodn/data-services/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/aodn/data-services/git/refs{/sha}","trees_url":"https://api.github.com/repos/aodn/data-services/git/trees{/sha}","statuses_url":"https://api.github.com/repos/aodn/data-services/statuses/{sha}","languages_url":"https://api.github.com/repos/aodn/data-services/languages","stargazers_url":"https://api.github.com/repos/aodn/data-services/stargazers","contributors_url":"https://api.github.com/repos/aodn/data-services/contributors","subscribers_url":"https://api.github.com/repos/aodn/data-services/subscribers","subscription_url":"https://api.github.com/repos/aodn/data-services/subscription","commits_url":"https://api.github.com/repos/aodn/data-services/commits{/sha}","git_commits_url":"https://api.github.com/repos/aodn/data-services/git/commits{/sha}","comments_url":"https://api.github.com/repos/aodn/data-services/comments{/number}","issue_comment_url":"https://api.github.com/repos/aodn/data-services/issues/comments{/number}","contents_url":"https://api.github.com/repos/aodn/data-services/contents/{+path}","compare_url":"https://api.github.com/repos/aodn/data-services/compare/{base}...{head}","merges_url":"https://api.github.com/repos/aodn/data-services/merges","archive_url":"https://api.github.com/repos/aodn/data-services/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/aodn/data-services/downloads","issues_url":"https://api.github.com/repos/aodn/data-services/issues{/number}","pulls_url":"https://api.github.com/repos/aodn/data-services/pulls{/number}","milestones_url":"https://api.github.com/repos/aodn/data-services/milestones{/number}","notifications_url":"https://api.github.com/repos/aodn/data-services/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/aodn/data-services/labels{/name}","releases_url":"https://api.github.com/repos/aodn/data-services/releases{/id}","deployments_url":"https://api.github.com/repos/aodn/data-services/deployments","created_at":"2014-02-27T04:30:35Z","updated_at":"2016-03-06T23:16:26Z","pushed_at":"2016-05-25T07:45:30Z","git_url":"git://github.com/aodn/data-services.git","ssh_url":"git@github.com:aodn/data-services.git","clone_url":"https://github.com/aodn/data-services.git","svn_url":"https://github.com/aodn/data-services","homepage":null,"size":52140,"stargazers_count":0,"watchers_count":0,"language":"Matlab","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":15,"forks":0,"open_issues":15,"watchers":0,"default_branch":"master"}},"base":{"label":"aodn:master","ref":"master","sha":"90c60fa96986ab82869f80e9e5717fc1614d8975","user":{"login":"aodn","id":2802166,"avatar_url":"https://avatars.githubusercontent.com/u/2802166?v=3","gravatar_id":"","url":"https://api.github.com/users/aodn","html_url":"https://github.com/aodn","followers_url":"https://api.github.com/users/aodn/followers","following_url":"https://api.github.com/users/aodn/following{/other_user}","gists_url":"https://api.github.com/users/aodn/gists{/gist_id}","starred_url":"https://api.github.com/users/aodn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aodn/subscriptions","organizations_url":"https://api.github.com/users/aodn/orgs","repos_url":"https://api.github.com/users/aodn/repos","events_url":"https://api.github.com/users/aodn/events{/privacy}","received_events_url":"https://api.github.com/users/aodn/received_events","type":"Organization","site_admin":false},"repo":{"id":17236639,"name":"data-services","full_name":"aodn/data-services","owner":{"login":"aodn","id":2802166,"avatar_url":"https://avatars.githubusercontent.com/u/2802166?v=3","gravatar_id":"","url":"https://api.github.com/users/aodn","html_url":"https://github.com/aodn","followers_url":"https://api.github.com/users/aodn/followers","following_url":"https://api.github.com/users/aodn/following{/other_user}","gists_url":"https://api.github.com/users/aodn/gists{/gist_id}","starred_url":"https://api.github.com/users/aodn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aodn/subscriptions","organizations_url":"https://api.github.com/users/aodn/orgs","repos_url":"https://api.github.com/users/aodn/repos","events_url":"https://api.github.com/users/aodn/events{/privacy}","received_events_url":"https://api.github.com/users/aodn/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/aodn/data-services","description":"Data Services scripts","fork":false,"url":"https://api.github.com/repos/aodn/data-services","forks_url":"https://api.github.com/repos/aodn/data-services/forks","keys_url":"https://api.github.com/repos/aodn/data-services/keys{/key_id}","collaborators_url":"https://api.github.com/repos/aodn/data-services/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/aodn/data-services/teams","hooks_url":"https://api.github.com/repos/aodn/data-services/hooks","issue_events_url":"https://api.github.com/repos/aodn/data-services/issues/events{/number}","events_url":"https://api.github.com/repos/aodn/data-services/events","assignees_url":"https://api.github.com/repos/aodn/data-services/assignees{/user}","branches_url":"https://api.github.com/repos/aodn/data-services/branches{/branch}","tags_url":"https://api.github.com/repos/aodn/data-services/tags","blobs_url":"https://api.github.com/repos/aodn/data-services/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/aodn/data-services/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/aodn/data-services/git/refs{/sha}","trees_url":"https://api.github.com/repos/aodn/data-services/git/trees{/sha}","statuses_url":"https://api.github.com/repos/aodn/data-services/statuses/{sha}","languages_url":"https://api.github.com/repos/aodn/data-services/languages","stargazers_url":"https://api.github.com/repos/aodn/data-services/stargazers","contributors_url":"https://api.github.com/repos/aodn/data-services/contributors","subscribers_url":"https://api.github.com/repos/aodn/data-services/subscribers","subscription_url":"https://api.github.com/repos/aodn/data-services/subscription","commits_url":"https://api.github.com/repos/aodn/data-services/commits{/sha}","git_commits_url":"https://api.github.com/repos/aodn/data-services/git/commits{/sha}","comments_url":"https://api.github.com/repos/aodn/data-services/comments{/number}","issue_comment_url":"https://api.github.com/repos/aodn/data-services/issues/comments{/number}","contents_url":"https://api.github.com/repos/aodn/data-services/contents/{+path}","compare_url":"https://api.github.com/repos/aodn/data-services/compare/{base}...{head}","merges_url":"https://api.github.com/repos/aodn/data-services/merges","archive_url":"https://api.github.com/repos/aodn/data-services/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/aodn/data-services/downloads","issues_url":"https://api.github.com/repos/aodn/data-services/issues{/number}","pulls_url":"https://api.github.com/repos/aodn/data-services/pulls{/number}","milestones_url":"https://api.github.com/repos/aodn/data-services/milestones{/number}","notifications_url":"https://api.github.com/repos/aodn/data-services/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/aodn/data-services/labels{/name}","releases_url":"https://api.github.com/repos/aodn/data-services/releases{/id}","deployments_url":"https://api.github.com/repos/aodn/data-services/deployments","created_at":"2014-02-27T04:30:35Z","updated_at":"2016-03-06T23:16:26Z","pushed_at":"2016-05-25T07:45:30Z","git_url":"git://github.com/aodn/data-services.git","ssh_url":"git@github.com:aodn/data-services.git","clone_url":"https://github.com/aodn/data-services.git","svn_url":"https://github.com/aodn/data-services","homepage":null,"size":52140,"stargazers_count":0,"watchers_count":0,"language":"Matlab","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":15,"forks":0,"open_issues":15,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/aodn/data-services/pulls/462"},"html":{"href":"https://github.com/aodn/data-services/pull/462"},"issue":{"href":"https://api.github.com/repos/aodn/data-services/issues/462"},"comments":{"href":"https://api.github.com/repos/aodn/data-services/issues/462/comments"},"review_comments":{"href":"https://api.github.com/repos/aodn/data-services/pulls/462/comments"},"review_comment":{"href":"https://api.github.com/repos/aodn/data-services/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/aodn/data-services/pulls/462/commits"},"statuses":{"href":"https://api.github.com/repos/aodn/data-services/statuses/9440b3057c60f21f03a8fb92e249683aa8a5bea6"}}}}
{"actor":{"display_login":"lbesnard"}}