{"action":"created","comment":{"url":"https://api.github.com/repos/mne-tools/mne-python/pulls/comments/113818398","pull_request_review_id":35238796,"id":113818398,"diff_hunk":"@@ -511,16 +481,529 @@ def _get_edf_info(fname, stim_channel, annot, annotmap, eog, misc, exclude,\n     # Some keys to be consistent with FIF measurement info\n     info['description'] = None\n     info['buffer_size_sec'] = 1.\n-    edf_info['nsamples'] = int(n_records * max_samp)\n+    edf_info['nsamples'] = int(edf_info['n_records'] * max_samp)\n \n     # These are the conditions under which a stim channel will be interpolated\n     if stim_channel is not None and not (annot and annotmap) and \\\n             tal_channel is None and n_samps[stim_channel] != int(max_samp):\n         warn('Interpolating stim channel. Events may jitter.')\n     info._update_redundant()\n+\n     return info, edf_info\n \n \n+def _read_edf_header(fname, stim_channel, annot, annotmap, exclude,\n+                     preload):\n+    \"\"\"Read header information from EDF+ or BDF file.\"\"\"\n+    edf_info = dict()\n+    edf_info['annot'] = annot\n+    edf_info['annotmap'] = annotmap\n+    edf_info['events'] = []\n+\n+    with open(fname, 'rb') as fid:\n+        assert(fid.tell() == 0)\n+\n+        fid.read(8)  # version (unused here)\n+        fid.seek(168)  # Seek 8+80 bytes for subj_id +80 bytes for rec_id\n+\n+        day, month, year = [int(x) for x in\n+                            re.findall('(\\d+)', fid.read(8).decode())]\n+        hour, minute, sec = [int(x) for x in\n+                             re.findall('(\\d+)', fid.read(8).decode())]\n+        century = 2000 if year < 50 else 1900\n+        date = datetime.datetime(year + century, month, day, hour, minute, sec)\n+\n+        header_nbytes = int(fid.read(8).decode())\n+\n+        subtype = fid.read(44).strip().decode()[:5]\n+        if len(subtype) == 0:\n+            subtype = os.path.splitext(fname)[1][1:].lower()\n+\n+        n_records = int(fid.read(8).decode())\n+        record_length = np.array([float(fid.read(8)), 1.])  # in seconds\n+        if record_length[0] == 0:\n+            record_length = record_length[0] = 1.\n+            warn('Header information is incorrect for record length. Default '\n+                 'record length set to 1.')\n+\n+        nchan = int(fid.read(4).decode())\n+        channels = list(range(nchan))\n+        ch_names = [fid.read(16).strip().decode() for ch in channels]\n+        exclude = [ch_names.index(idx) for idx in exclude]\n+        for ch in channels:\n+            fid.read(80)  # transducer\n+        units = [fid.read(8).strip().decode() for ch in channels]\n+        edf_info['units'] = list()\n+        include = list()\n+        for i, unit in enumerate(units):\n+            if i in exclude:\n+                continue\n+            if unit == 'uV':\n+                edf_info['units'].append(1e-6)\n+            else:\n+                edf_info['units'].append(1)\n+            include.append(i)\n+        ch_names = [ch_names[idx] for idx in include]\n+\n+        physical_min = np.array([float(fid.read(8).decode())\n+                                 for ch in channels])[include]\n+        physical_max = np.array([float(fid.read(8).decode())\n+                                 for ch in channels])[include]\n+        digital_min = np.array([float(fid.read(8).decode())\n+                                for ch in channels])[include]\n+        digital_max = np.array([float(fid.read(8).decode())\n+                                for ch in channels])[include]\n+        prefiltering = [fid.read(80).decode().strip(' \\x00')\n+                        for ch in channels][:-1]\n+        highpass = np.ravel([re.findall('HP:\\s+(\\w+)', filt)\n+                             for filt in prefiltering])\n+        lowpass = np.ravel([re.findall('LP:\\s+(\\w+)', filt)\n+                            for filt in prefiltering])\n+\n+        # number of samples per record\n+        n_samps = np.array([int(fid.read(8).decode()) for ch\n+                            in channels])\n+\n+        # Populate edf_info\n+        edf_info['ch_names'] = ch_names\n+        edf_info['data_offset'] = header_nbytes\n+        edf_info['date'] = date\n+        edf_info['digital_max'] = digital_max\n+        edf_info['digital_min'] = digital_min\n+        edf_info['exclude'] = exclude\n+        edf_info['highpass'] = highpass\n+        edf_info['include'] = include\n+        edf_info['lowpass'] = lowpass\n+        edf_info['n_records'] = n_records\n+        edf_info['n_samps'] = n_samps\n+        edf_info['nchan'] = nchan\n+        edf_info['physical_max'] = physical_max\n+        edf_info['physical_min'] = physical_min\n+        edf_info['record_length'] = record_length\n+        edf_info['subtype'] = subtype\n+\n+        fid.read(32 * nchan).decode()  # reserved\n+        assert fid.tell() == header_nbytes\n+\n+        fid.seek(0, 2)\n+        n_bytes = fid.tell()\n+        n_data_bytes = n_bytes - header_nbytes\n+        total_samps = (n_data_bytes // 3 if subtype == '24BIT'\n+                       else n_data_bytes // 2)\n+        read_records = total_samps // np.sum(n_samps)\n+        if n_records != read_records:\n+            warn('Number of records from the header does not match the file '\n+                 'size (perhaps the recording was not stopped before exiting).'\n+                 ' Inferring from the file size.')\n+            edf_info['n_records'] = n_records = read_records\n+\n+        if subtype in ('24BIT', 'bdf'):\n+            edf_info['data_size'] = 3  # 24-bit (3 byte) integers\n+        else:\n+            edf_info['data_size'] = 2  # 16-bit (2 byte) integers\n+\n+    return edf_info\n+\n+\n+def _read_gdf_header(fname, stim_channel, exclude):\n+    \"\"\"Read GDF 1.x and GDF 2.x header info.\"\"\"\n+    edf_info = dict()\n+    # edf_info['annot'] = annot\n+    # edf_info['annotmap'] = annotmap\n+    edf_info['events'] = []\n+\n+    with open(fname, 'rb') as fid:\n+        assert(fid.tell() == 0)\n+\n+        version = fid.read(8).decode()\n+\n+        gdftyp_np = (None, np.int8, np.uint8, np.int16, np.uint16, np.int32,\n+                     np.uint32, np.int64, np.uint64, None, None, None, None,\n+                     None, None, None, np.float32, np.float64)\n+        gdftyp_byte = [np.dtype(x).itemsize if x is not None else 0\n+                       for x in gdftyp_np]\n+        assert sum(gdftyp_byte) == 42\n+\n+        edf_info['type'] = edf_info['subtype'] = version[:3]\n+        edf_info['number'] = float(version[4:])\n+\n+        # GDF 1.x\n+        # ----------------------------------------------------------------------\n+        if edf_info['number'] < 1.9:\n+\n+            fid.read(80)  # subject id\n+            fid.read(80)  # recording id\n+\n+            # date\n+            tm = fid.read(16).decode().strip(' \\x00')\n+            try:\n+                if tm[14:16] == '  ':\n+                    tm = tm[:14] + '00' + tm[16:]\n+                date = (datetime.datetime(int(tm[0:4]), int(tm[4:6]),\n+                                          int(tm[6:8]), int(tm[8:10]),\n+                                          int(tm[10:12]), int(tm[12:14]),\n+                                          int(tm[14:16]) * pow(10, 4)))\n+            except:\n+                date = datetime.datetime(2000, 1, 1)\n+\n+            header_nbytes = np.fromfile(fid, np.int64, 1)[0]\n+            equipment = np.fromfile(fid, np.uint8, 8)[0]\n+            hospital = np.fromfile(fid, np.uint8, 8)[0]\n+            technician = np.fromfile(fid, np.uint8, 8)[0]\n+            fid.seek(20, 1)    # 20bytes reserved\n+\n+            n_records = np.fromfile(fid, np.int64, 1)[0]\n+            # record length in seconds\n+            record_length = np.fromfile(fid, np.uint32, 2)\n+            if record_length[0] == 0:\n+                record_length[0] = 1.\n+                warn('Header information is incorrect for record length. '\n+                     'Default record length set to 1.')\n+            nchan = np.fromfile(fid, np.uint32, 1)[0]\n+            channels = list(range(nchan))\n+            ch_names = [fid.read(16).decode().strip(' \\x00')\n+                        for ch in channels]\n+            fid.seek(80 * len(channels), 1)  # transducer\n+            units = [fid.read(8).decode().strip(' \\x00') for ch in channels]\n+\n+            exclude = [ch_names.index(idx) for idx in exclude]\n+            include = list()\n+            for i, unit in enumerate(units):\n+                if unit[:2] == 'uV':\n+                    units[i] = 1e-6\n+                else:\n+                    units[i] = 1\n+                include.append(i)\n+\n+            ch_names = [ch_names[idx] for idx in include]\n+            physical_min = np.fromfile(fid, np.float64, len(channels))\n+            physical_max = np.fromfile(fid, np.float64, len(channels))\n+            digital_min = np.fromfile(fid, np.int64, len(channels))\n+            digital_max = np.fromfile(fid, np.int64, len(channels))\n+            prefiltering = [fid.read(80).decode().strip(' \\x00')\n+                            for ch in channels][:-1]\n+            highpass = np.ravel([re.findall('HP:\\s+(\\w+)', filt)\n+                                 for filt in prefiltering])\n+            lowpass = np.ravel([re.findall('LP:\\s+(\\w+)', filt)\n+                                for filt in prefiltering])\n+\n+            # n samples per record\n+            n_samps = np.fromfile(fid, np.int32, len(channels))\n+\n+            # channel data type\n+            gdftype = np.fromfile(fid, np.int32, len(channels))\n+\n+            # populate edf_info\n+            edf_info['bytes_tot'] = \\\n+                np.sum([gdftyp_byte[t] * n_samps[i]     # total number of\n+                        for i, t in enumerate(gdftype)])  # bytes for data\n+            edf_info['ch_names'] = ch_names\n+            edf_info['data_offset'] = header_nbytes\n+            edf_info['data_size'] = gdftyp_byte[gdftype[0]]\n+            edf_info['date'] = date\n+            edf_info['digital_max'] = digital_max\n+            edf_info['digital_min'] = digital_min\n+            edf_info['equipment'] = equipment\n+            edf_info['exclude'] = exclude\n+            edf_info['gdftype'] = gdftype\n+            edf_info['gdftype_np'] = [gdftyp_np[t] for t in gdftype]\n+            edf_info['highpass'] = highpass\n+            edf_info['hospital'] = hospital\n+            edf_info['include'] = include\n+            edf_info['lowpass'] = lowpass\n+            edf_info['meas_date'] = calendar.timegm(date.utctimetuple())\n+            edf_info['n_records'] = n_records\n+            edf_info['n_samps'] = n_samps\n+            edf_info['nchan'] = nchan\n+            edf_info['physical_max'] = physical_max\n+            edf_info['physical_min'] = physical_min\n+            edf_info['record_length'] = record_length\n+            edf_info['technician'] = technician\n+            edf_info['units'] = units\n+\n+            fid.seek(32 * edf_info['nchan'], 1)  # reserved\n+            assert fid.tell() == header_nbytes\n+\n+            # Event table\n+            # ------------------------------------------------------------------\n+            etp = header_nbytes + n_records * edf_info['bytes_tot']\n+            # skip data to go to event table\n+            fid.seek(etp)\n+            etmode = fid.read(1).decode()\n+            if etmode != '':\n+                etmode = np.fromfile(fid, np.uint8, 1).tolist()\n+                sr = np.fromfile(fid, np.uint8, 3)\n+                event_sr = sr[0]\n+                events = []\n+                for i in range(1, len(sr)):\n+                    event_sr = event_sr + sr[i] * 256 ** i\n+                n_events = np.fromfile(fid, np.uint32, 1)[0]\n+                pos = np.fromfile(fid, np.uint32, n_events * 4)\n+                typ = np.fromfile(fid, np.uint16, n_events * 2)\n+\n+                if etmode == 3:\n+                    chn = np.fromfile(fid, np.uint16, n_events * 2)\n+                    dur = np.fromfile(fid, np.uint32, n_events * 4)\n+                    events.append([n_events, pos, typ, chn, dur])\n+                else:\n+                    dur = np.zeros(n_events, dtype=np.uint32)\n+                    events.append([n_events, pos, typ])\n+\n+                edf_info['events'] = events\n+                # info['events'] = np.c_[pos, dur, typ]\n+\n+        # GDF 2.x\n+        # ----------------------------------------------------------------------\n+        else:\n+            # FIXED HEADER\n+            handedness = ('Unknown', 'Right', 'Left', 'Equal')\n+            gender = ('Unknown', 'Male', 'Female')\n+            scale = ('Unknown', 'No', 'Yes', 'Corrected')\n+\n+            # date\n+            pid = fid.read(66).decode()\n+            pid = pid.split(' ', 2)\n+            patient = {}\n+            if len(pid) >= 2:\n+                patient['id'] = pid[0]\n+                patient['name'] = pid[1]\n+\n+            fid.seek(10, 1)  # 10bytes reserved\n+\n+            # Smoking / Alcohol abuse / drug abuse / medication\n+            sadm = np.fromfile(fid, np.uint8, 1)[0]\n+            patient['smoking'] = scale[sadm % 4]\n+            patient['alcohol_abuse'] = scale[(sadm >> 2) % 4]\n+            patient['drug_abuse'] = scale[(sadm >> 4) % 4]\n+            patient['medication'] = scale[(sadm >> 6) % 4]\n+            patient['weight'] = np.fromfile(fid, np.uint8, 1)[0]\n+            if patient['weight'] == 0 or patient['weight'] == 255:\n+                patient['weight'] = None\n+            patient['height'] = np.fromfile(fid, np.uint8, 1)[0]\n+            if patient['height'] == 0 or patient['height'] == 255:\n+                patient['height'] = None\n+\n+            # Gender / Handedness / Visual Impairment\n+            ghi = np.fromfile(fid, np.uint8, 1)[0]\n+            patient['sex'] = gender[ghi % 4]\n+            patient['handedness'] = handedness[(ghi >> 2) % 4]\n+            patient['visual'] = scale[(ghi >> 4) % 4]\n+\n+            fid.read(64)  # recording identification (unused here)\n+            # rl = fid.read(16).decode()  # Recording location (Lat, Long, Alt)\n+            vhsv = np.fromfile(fid, np.uint8, 4)\n+            loc = {}\n+            if vhsv[3] == 0:\n+                loc['vertpre'] = 10 * int(vhsv[0] >> 4) + int(vhsv[0] % 16)\n+                loc['horzpre'] = 10 * int(vhsv[1] >> 4) + int(vhsv[1] % 16)\n+                loc['size'] = 10 * int(vhsv[2] >> 4) + int(vhsv[2] % 16)\n+            else:\n+                loc['vertpre'] = 29\n+                loc['horzpre'] = 29\n+                loc['size'] = 29\n+            loc['version'] = 0\n+            loc['latitude'] = \\\n+                float(np.fromfile(fid, np.uint32, 1)[0]) / 3600000\n+            loc['longitude'] = \\\n+                float(np.fromfile(fid, np.uint32, 1)[0]) / 3600000\n+            loc['altitude'] = float(np.fromfile(fid, np.int32, 1)[0]) / 100\n+\n+            date = np.fromfile(fid, np.uint64, 1)[0]\n+            if date == 0:\n+                date = datetime.datetime(1, 1, 1)\n+            else:\n+                date = datetime.datetime(1, 1, 1) + \\\n+                    datetime.timedelta(date * pow(2, -32) - 367)\n+\n+            birthday = np.fromfile(fid, np.uint64, 1).tolist()[0]\n+            if birthday == 0:\n+                birthday = datetime.datetime(1, 1, 1)\n+            else:\n+                birthday = (datetime.datetime(1, 1, 1) +\n+                            datetime.timedelta(birthday * pow(2, -32) - 367))\n+            patient['birthday'] = birthday\n+            if patient['birthday'] != datetime.datetime(1, 1, 1, 0, 0):\n+                today = datetime.datetime.today()\n+                patient['age'] = today.year - patient['birthday'].year\n+                today = today.replace(year=patient['birthday'].year)\n+                if today < patient['birthday']:\n+                    patient['age'] -= 1\n+            else:\n+                patient['age'] = None\n+\n+            header_nbytes = np.fromfile(fid, np.uint16, 1)[0] * 256\n+\n+            fid.seek(6, 1)  # 6 bytes reserved\n+            equipment = np.fromfile(fid, np.uint8, 8)\n+            ip = np.fromfile(fid, np.uint8, 6)\n+            patient['headsize'] = np.fromfile(fid, np.uint16, 3)\n+            patient['headsize'] = np.asarray(patient['headsize'], np.float32)\n+            patient['headsize'] = np.ma.masked_array(\n+                patient['headsize'],\n+                np.equal(patient['headsize'], 0), None).filled()\n+            ref = np.fromfile(fid, np.float32, 3)\n+            gnd = np.fromfile(fid, np.float32, 3)\n+            n_records = np.fromfile(fid, np.int64, 1)[0]\n+\n+            # record length in seconds\n+            record_length = np.fromfile(fid, np.uint32, 2)\n+            if record_length[0] == 0:\n+                record_length[0] = 1.\n+                warn('Header information is incorrect for record length. '\n+                     'Default record length set to 1.')\n+\n+            nchan = np.fromfile(fid, np.uint16, 1)[0]\n+            fid.seek(2, 1)  # 2bytes reserved\n+\n+            # Channels (variable header)\n+            channels = list(range(nchan))\n+            ch_names = [fid.read(16).decode().strip(' \\x00')\n+                        for ch in channels]\n+            exclude = [ch_names.index(idx) for idx in exclude]\n+\n+            fid.seek(80 * len(channels), 1)  # reserved space\n+\n+            \"\"\"The Physical Dimensions are encoded with a 16 bit integer\n+            number, as a combination of 'unit code' + order of magnitude.\n+            The list of possible codes can be found in the following\n+            documents:\n+            - Units codes :\n+            https://sourceforge.net/p/biosig/svn/HEAD/tree/trunk/biosig/doc/units.csv\n+            - Decimal factors codes:\n+            https://sourceforge.net/p/biosig/svn/HEAD/tree/trunk/biosig/doc/DecimalFactors.txt\n+\n+            For example, the physical dimension 'uV' (microvolt) is\n+            encoded as 4256 (Volt) + 19 (micro) = 4275. The code 512\n+            stands for dimensionless.\n+            \"\"\"  # noqa\n+            fid.seek(6 * len(channels), 1)  # phys_dim, obsolete\n+            units = np.fromfile(fid, np.uint16, len(channels)).tolist()\n+            unitcodes = np.array(units[:])\n+            include = list()\n+            for i, unit in enumerate(units):\n+                if unit == 4275:  # microvolts","path":"mne/io/edf/edf.py","position":778,"original_position":760,"commit_id":"04cdfd8fd27c4739ee1168dd6be5133eb1233050","original_commit_id":"9d6bb174e510bcd18bfb48a1a9732d7c68b2fe89","user":{"login":"teonbrooks","id":1578674,"avatar_url":"https://avatars2.githubusercontent.com/u/1578674?v=3","gravatar_id":"","url":"https://api.github.com/users/teonbrooks","html_url":"https://github.com/teonbrooks","followers_url":"https://api.github.com/users/teonbrooks/followers","following_url":"https://api.github.com/users/teonbrooks/following{/other_user}","gists_url":"https://api.github.com/users/teonbrooks/gists{/gist_id}","starred_url":"https://api.github.com/users/teonbrooks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/teonbrooks/subscriptions","organizations_url":"https://api.github.com/users/teonbrooks/orgs","repos_url":"https://api.github.com/users/teonbrooks/repos","events_url":"https://api.github.com/users/teonbrooks/events{/privacy}","received_events_url":"https://api.github.com/users/teonbrooks/received_events","type":"User","site_admin":false},"body":"agreed, it would be nice to have constants there for quick ref","created_at":"2017-04-27T22:38:06Z","updated_at":"2017-04-27T22:46:57Z","html_url":"https://github.com/mne-tools/mne-python/pull/4205#discussion_r113818398","pull_request_url":"https://api.github.com/repos/mne-tools/mne-python/pulls/4205","_links":{"self":{"href":"https://api.github.com/repos/mne-tools/mne-python/pulls/comments/113818398"},"html":{"href":"https://github.com/mne-tools/mne-python/pull/4205#discussion_r113818398"},"pull_request":{"href":"https://api.github.com/repos/mne-tools/mne-python/pulls/4205"}}},"pull_request":{"url":"https://api.github.com/repos/mne-tools/mne-python/pulls/4205","id":116317323,"html_url":"https://github.com/mne-tools/mne-python/pull/4205","diff_url":"https://github.com/mne-tools/mne-python/pull/4205.diff","patch_url":"https://github.com/mne-tools/mne-python/pull/4205.patch","issue_url":"https://api.github.com/repos/mne-tools/mne-python/issues/4205","number":4205,"state":"open","locked":false,"title":"MRG+1: GDF support","user":{"login":"nbara","id":10333715,"avatar_url":"https://avatars2.githubusercontent.com/u/10333715?v=3","gravatar_id":"","url":"https://api.github.com/users/nbara","html_url":"https://github.com/nbara","followers_url":"https://api.github.com/users/nbara/followers","following_url":"https://api.github.com/users/nbara/following{/other_user}","gists_url":"https://api.github.com/users/nbara/gists{/gist_id}","starred_url":"https://api.github.com/users/nbara/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nbara/subscriptions","organizations_url":"https://api.github.com/users/nbara/orgs","repos_url":"https://api.github.com/users/nbara/repos","events_url":"https://api.github.com/users/nbara/events{/privacy}","received_events_url":"https://api.github.com/users/nbara/received_events","type":"User","site_admin":false},"body":"This is an attempt to allow reading GDF files in mne. The GDF format is described in detail here:\r\nhttps://arxiv.org/abs/cs/0608052\r\n\r\nThis file format is currently only supported by the [biosig toolbox](http://biosig.sourceforge.net) (which is used by fieldtrip & Co). There is an active homebrew port of the biosig toolbox (https://github.com/schloegl/homebrew-biosig). This would probably be the cleanest way to ensure long-lasting GDF support in python (especially since the format is still likely to evolve), but I wasn't able to install it on my machine, and it's macOS-only...\r\n\r\nSome of the code was taken from @alexandrebarachant's previous attempt (see #2136, and https://github.com/alexandrebarachant/mne-python/tree/gdf) and an apparently discontinued [biosig python port](https://github.com/donnchadh/biosig/blob/master/biosig4python/biosig.py), with the following improvements:\r\n- support for GDF 1.x *and* 2.x : this is a bit tricky since the format seems to have evolved a lot since its introduction, and AFAICT there is no backwards compatibility between the two. So I had no choice but write specific code for the two versions.\r\n- GDF support is embedded in the EDF/BDF module. This might sound nice, but it's not the cleanest piece of code either, so I would be glad if someone more experienced with eeg file formats could have a look (@teonbrooks maybe?)\r\n\r\nA few other notes :\r\n- I only have tested 2.x support with files generated with [`biosemi2ft`](http://www.fieldtriptoolbox.org/development/realtime/biosemi), which we use in the lab. We probably need to run more tests before merging but I couldn't find any publicly available dataset\r\n- @alexandrebarachant has provided a GDF 1.x test file, which I've attached to the present commit. Ideally we would also need more test files for version 2.x )\r\n- Event values for GDF 2.x files are detected as multiples of 256 on my test files, so I suspect there is still something fishy going on with the data types.\r\n- It's my first PR so any tips/comments welcome ! ","created_at":"2017-04-18T12:36:17Z","updated_at":"2017-04-27T22:46:57Z","closed_at":null,"merged_at":null,"merge_commit_sha":"7909523c04a0ec15736f969aa6b32c89358c6fdb","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/mne-tools/mne-python/pulls/4205/commits","review_comments_url":"https://api.github.com/repos/mne-tools/mne-python/pulls/4205/comments","review_comment_url":"https://api.github.com/repos/mne-tools/mne-python/pulls/comments{/number}","comments_url":"https://api.github.com/repos/mne-tools/mne-python/issues/4205/comments","statuses_url":"https://api.github.com/repos/mne-tools/mne-python/statuses/04cdfd8fd27c4739ee1168dd6be5133eb1233050","head":{"label":"nbara:gdf-support","ref":"gdf-support","sha":"04cdfd8fd27c4739ee1168dd6be5133eb1233050","user":{"login":"nbara","id":10333715,"avatar_url":"https://avatars2.githubusercontent.com/u/10333715?v=3","gravatar_id":"","url":"https://api.github.com/users/nbara","html_url":"https://github.com/nbara","followers_url":"https://api.github.com/users/nbara/followers","following_url":"https://api.github.com/users/nbara/following{/other_user}","gists_url":"https://api.github.com/users/nbara/gists{/gist_id}","starred_url":"https://api.github.com/users/nbara/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nbara/subscriptions","organizations_url":"https://api.github.com/users/nbara/orgs","repos_url":"https://api.github.com/users/nbara/repos","events_url":"https://api.github.com/users/nbara/events{/privacy}","received_events_url":"https://api.github.com/users/nbara/received_events","type":"User","site_admin":false},"repo":{"id":88133454,"name":"mne-python","full_name":"nbara/mne-python","owner":{"login":"nbara","id":10333715,"avatar_url":"https://avatars2.githubusercontent.com/u/10333715?v=3","gravatar_id":"","url":"https://api.github.com/users/nbara","html_url":"https://github.com/nbara","followers_url":"https://api.github.com/users/nbara/followers","following_url":"https://api.github.com/users/nbara/following{/other_user}","gists_url":"https://api.github.com/users/nbara/gists{/gist_id}","starred_url":"https://api.github.com/users/nbara/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nbara/subscriptions","organizations_url":"https://api.github.com/users/nbara/orgs","repos_url":"https://api.github.com/users/nbara/repos","events_url":"https://api.github.com/users/nbara/events{/privacy}","received_events_url":"https://api.github.com/users/nbara/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/nbara/mne-python","description":"MNE : Magnetoencephalography (MEG) and Electroencephalography (EEG) in Python","fork":true,"url":"https://api.github.com/repos/nbara/mne-python","forks_url":"https://api.github.com/repos/nbara/mne-python/forks","keys_url":"https://api.github.com/repos/nbara/mne-python/keys{/key_id}","collaborators_url":"https://api.github.com/repos/nbara/mne-python/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/nbara/mne-python/teams","hooks_url":"https://api.github.com/repos/nbara/mne-python/hooks","issue_events_url":"https://api.github.com/repos/nbara/mne-python/issues/events{/number}","events_url":"https://api.github.com/repos/nbara/mne-python/events","assignees_url":"https://api.github.com/repos/nbara/mne-python/assignees{/user}","branches_url":"https://api.github.com/repos/nbara/mne-python/branches{/branch}","tags_url":"https://api.github.com/repos/nbara/mne-python/tags","blobs_url":"https://api.github.com/repos/nbara/mne-python/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/nbara/mne-python/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/nbara/mne-python/git/refs{/sha}","trees_url":"https://api.github.com/repos/nbara/mne-python/git/trees{/sha}","statuses_url":"https://api.github.com/repos/nbara/mne-python/statuses/{sha}","languages_url":"https://api.github.com/repos/nbara/mne-python/languages","stargazers_url":"https://api.github.com/repos/nbara/mne-python/stargazers","contributors_url":"https://api.github.com/repos/nbara/mne-python/contributors","subscribers_url":"https://api.github.com/repos/nbara/mne-python/subscribers","subscription_url":"https://api.github.com/repos/nbara/mne-python/subscription","commits_url":"https://api.github.com/repos/nbara/mne-python/commits{/sha}","git_commits_url":"https://api.github.com/repos/nbara/mne-python/git/commits{/sha}","comments_url":"https://api.github.com/repos/nbara/mne-python/comments{/number}","issue_comment_url":"https://api.github.com/repos/nbara/mne-python/issues/comments{/number}","contents_url":"https://api.github.com/repos/nbara/mne-python/contents/{+path}","compare_url":"https://api.github.com/repos/nbara/mne-python/compare/{base}...{head}","merges_url":"https://api.github.com/repos/nbara/mne-python/merges","archive_url":"https://api.github.com/repos/nbara/mne-python/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/nbara/mne-python/downloads","issues_url":"https://api.github.com/repos/nbara/mne-python/issues{/number}","pulls_url":"https://api.github.com/repos/nbara/mne-python/pulls{/number}","milestones_url":"https://api.github.com/repos/nbara/mne-python/milestones{/number}","notifications_url":"https://api.github.com/repos/nbara/mne-python/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/nbara/mne-python/labels{/name}","releases_url":"https://api.github.com/repos/nbara/mne-python/releases{/id}","deployments_url":"https://api.github.com/repos/nbara/mne-python/deployments","created_at":"2017-04-13T06:41:09Z","updated_at":"2017-04-13T06:41:13Z","pushed_at":"2017-04-27T09:53:13Z","git_url":"git://github.com/nbara/mne-python.git","ssh_url":"git@github.com:nbara/mne-python.git","clone_url":"https://github.com/nbara/mne-python.git","svn_url":"https://github.com/nbara/mne-python","homepage":"http://martinos.org/mne/","size":101740,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"mne-tools:master","ref":"master","sha":"cda9d7b8362cb53618c71967b0b63ff46d311d9c","user":{"login":"mne-tools","id":583875,"avatar_url":"https://avatars0.githubusercontent.com/u/583875?v=3","gravatar_id":"","url":"https://api.github.com/users/mne-tools","html_url":"https://github.com/mne-tools","followers_url":"https://api.github.com/users/mne-tools/followers","following_url":"https://api.github.com/users/mne-tools/following{/other_user}","gists_url":"https://api.github.com/users/mne-tools/gists{/gist_id}","starred_url":"https://api.github.com/users/mne-tools/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mne-tools/subscriptions","organizations_url":"https://api.github.com/users/mne-tools/orgs","repos_url":"https://api.github.com/users/mne-tools/repos","events_url":"https://api.github.com/users/mne-tools/events{/privacy}","received_events_url":"https://api.github.com/users/mne-tools/received_events","type":"Organization","site_admin":false},"repo":{"id":1301584,"name":"mne-python","full_name":"mne-tools/mne-python","owner":{"login":"mne-tools","id":583875,"avatar_url":"https://avatars0.githubusercontent.com/u/583875?v=3","gravatar_id":"","url":"https://api.github.com/users/mne-tools","html_url":"https://github.com/mne-tools","followers_url":"https://api.github.com/users/mne-tools/followers","following_url":"https://api.github.com/users/mne-tools/following{/other_user}","gists_url":"https://api.github.com/users/mne-tools/gists{/gist_id}","starred_url":"https://api.github.com/users/mne-tools/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mne-tools/subscriptions","organizations_url":"https://api.github.com/users/mne-tools/orgs","repos_url":"https://api.github.com/users/mne-tools/repos","events_url":"https://api.github.com/users/mne-tools/events{/privacy}","received_events_url":"https://api.github.com/users/mne-tools/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/mne-tools/mne-python","description":"MNE : Magnetoencephalography (MEG) and Electroencephalography (EEG) in Python","fork":false,"url":"https://api.github.com/repos/mne-tools/mne-python","forks_url":"https://api.github.com/repos/mne-tools/mne-python/forks","keys_url":"https://api.github.com/repos/mne-tools/mne-python/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mne-tools/mne-python/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mne-tools/mne-python/teams","hooks_url":"https://api.github.com/repos/mne-tools/mne-python/hooks","issue_events_url":"https://api.github.com/repos/mne-tools/mne-python/issues/events{/number}","events_url":"https://api.github.com/repos/mne-tools/mne-python/events","assignees_url":"https://api.github.com/repos/mne-tools/mne-python/assignees{/user}","branches_url":"https://api.github.com/repos/mne-tools/mne-python/branches{/branch}","tags_url":"https://api.github.com/repos/mne-tools/mne-python/tags","blobs_url":"https://api.github.com/repos/mne-tools/mne-python/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mne-tools/mne-python/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mne-tools/mne-python/git/refs{/sha}","trees_url":"https://api.github.com/repos/mne-tools/mne-python/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mne-tools/mne-python/statuses/{sha}","languages_url":"https://api.github.com/repos/mne-tools/mne-python/languages","stargazers_url":"https://api.github.com/repos/mne-tools/mne-python/stargazers","contributors_url":"https://api.github.com/repos/mne-tools/mne-python/contributors","subscribers_url":"https://api.github.com/repos/mne-tools/mne-python/subscribers","subscription_url":"https://api.github.com/repos/mne-tools/mne-python/subscription","commits_url":"https://api.github.com/repos/mne-tools/mne-python/commits{/sha}","git_commits_url":"https://api.github.com/repos/mne-tools/mne-python/git/commits{/sha}","comments_url":"https://api.github.com/repos/mne-tools/mne-python/comments{/number}","issue_comment_url":"https://api.github.com/repos/mne-tools/mne-python/issues/comments{/number}","contents_url":"https://api.github.com/repos/mne-tools/mne-python/contents/{+path}","compare_url":"https://api.github.com/repos/mne-tools/mne-python/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mne-tools/mne-python/merges","archive_url":"https://api.github.com/repos/mne-tools/mne-python/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mne-tools/mne-python/downloads","issues_url":"https://api.github.com/repos/mne-tools/mne-python/issues{/number}","pulls_url":"https://api.github.com/repos/mne-tools/mne-python/pulls{/number}","milestones_url":"https://api.github.com/repos/mne-tools/mne-python/milestones{/number}","notifications_url":"https://api.github.com/repos/mne-tools/mne-python/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mne-tools/mne-python/labels{/name}","releases_url":"https://api.github.com/repos/mne-tools/mne-python/releases{/id}","deployments_url":"https://api.github.com/repos/mne-tools/mne-python/deployments","created_at":"2011-01-28T03:31:13Z","updated_at":"2017-04-21T13:17:25Z","pushed_at":"2017-04-27T13:02:52Z","git_url":"git://github.com/mne-tools/mne-python.git","ssh_url":"git@github.com:mne-tools/mne-python.git","clone_url":"https://github.com/mne-tools/mne-python.git","svn_url":"https://github.com/mne-tools/mne-python","homepage":"http://martinos.org/mne/","size":93332,"stargazers_count":299,"watchers_count":299,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":270,"mirror_url":null,"open_issues_count":203,"forks":270,"open_issues":203,"watchers":299,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/mne-tools/mne-python/pulls/4205"},"html":{"href":"https://github.com/mne-tools/mne-python/pull/4205"},"issue":{"href":"https://api.github.com/repos/mne-tools/mne-python/issues/4205"},"comments":{"href":"https://api.github.com/repos/mne-tools/mne-python/issues/4205/comments"},"review_comments":{"href":"https://api.github.com/repos/mne-tools/mne-python/pulls/4205/comments"},"review_comment":{"href":"https://api.github.com/repos/mne-tools/mne-python/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/mne-tools/mne-python/pulls/4205/commits"},"statuses":{"href":"https://api.github.com/repos/mne-tools/mne-python/statuses/04cdfd8fd27c4739ee1168dd6be5133eb1233050"}}}}
{"actor":{"display_login":"teonbrooks"}}