Gannet simplifies the preprocessing, signal fitting, and quantification pipeline of edited MRS data. All you need to get started is a basic understanding of MATLAB and the five Gannet modules (listed below).

If this is your first time using Gannet, you should read through the Reference as well. If you have previously worked with Gannet and only need a quick refresher about the command syntax, this page will probably be all you need to get started again.

Modules

The linear workflow of Gannet is made up of five modules. For proper functionality, they need to be executed in the following order:

Module Description
GannetLoad Loads raw data exported from the scanner; preprocesses them; plots the edited spectra; and gives information about the time course of the experiment.
GannetFit Models the metabolite signals of interest in the difference spectra and the reference compounds; plots the data and the model fits; and gives basic quantification results and information about spectral quality.
GannetCoRegister Loads the provided structural image data files; co-registers the loaded MRS voxel to them; and produces a figure showing the localization of the voxel on the structural image on three orthogonal slices.
GannetSegment Calls SPM to segment the structural images; determines the fractional tissue composition (gray matter, white matter, and CSF) within the MRS voxel; produces a figure showing the tissue fractions as overlays and displays CSF-corrected metabolite estimates.
GannetQuantify Uses the segmentation information to perform partial volume tissue correction and produces a figure displaying several tissue-corrected metabolite measurements.

Familiarize yourself with the five basic Gannet commands, as described below. The number of commands is deliberately kept to a minimum, as is the number of possible input arguments to these commands. Incorrect syntax is a common source of user error, so make sure that you understand the argument structure of each function you intend to use.

Usage

GannetPreInitialise

The first step in using Gannet is to set up the GannetPreInitialise.m function. While the toolkit has many routines that automatically recognize data formats, sequences, and acquisition parameters from data file headers; some settings need to be set by the user to run Gannet properly. Additionally, GannetPreInitialise.m allows the user to choose how to process their data (for example, which frequency-and-phase correction algorithm to use).

  Any time you run Gannet, make sure to check that the settings in GannetPreInitialise.m are correct. Many errors can be avoided by following this simple step.

The default settings pre-initialize a standard analysis for in vivo GABA-edited MEGA-PRESS data. If you want to analyze data acquired with a different method or from a phantom, or target a different metabolite, you will need to make changes to this file. Please read the Reference for detailed explanations of the options and flags in GannetPreInitialise.m.

A screenshot example of GannetPreInitialise.m

Loading and fitting data

Depending on the format of your data, and if you have water reference data and/or structural images, the commands for running Gannet to load and fit your data follow a specific syntax.

For all modules, an output argument containing a structure should always be included, for example MRS_struct. Input arguments for GannetLoad.m are usually given as cell arrays. Water-suppressed metabolite files must be given as the first input argument, while unsuppressed water reference files must be given as the second input argument. The remaining modules require input of the output structure from GannetLoad.m. (The exception is GannetCoRegister.m, which additionally requires a cell array of structural images.)

Some examples for different data file formats:

DICOM data (*.dcm files)

The DICOM format saves each transient in a separate file, such that for an acquisition with 320 transients, there will be 320 DICOM files. Data from each acquisition should be stored in an individual directory. To run such data, use the following commands:

MRS_struct = GannetLoad({'metab/file1.dcm'}, {'water/file1.dcm'});
MRS_struct = GannetFit(MRS_struct);

  Note how the metabolite and water data are stored in separate directories and that a single DICOM file is selected for data loading (it does not matter which file in each directory is chosen).

GE data (*.7 files)

Data from GE scanners are exported as a P-file, with the extension *.7. Standard GE acquisitions automatically acquire a water reference, which is stored within the P-file. To run such data, use the following commands:

MRS_struct = GannetLoad({'sub-01.7'});
MRS_struct = GannetFit(MRS_struct);

NIfTI data (*.nii[.gz] files)

NIfTI-MRS was developed to serve as an open-source data format standard for MRS. Both compressed and uncompressed files can be processed in Gannet. To run such data, use the following commands:

MRS_struct = GannetLoad({'sub-01.nii'}, {'sub-01_ref.nii'});
MRS_struct = GannetFit(MRS_struct);

Philips data (*.sdat/*.spar files)

Data from Philips scanners are most commonly exported as a pair of *.sdat/*.spar files, where the *.sdat file contains the data and the *.spar contains the acquisition parameters. A water reference usually is also acquired and exported as a separate pair of files. The two are distinguished by the suffices _act and _ref. To run such data, use the following commands:

MRS_struct = GannetLoad({'sub-01_act.sdat'}, {'sub-01_ref.sdat'});
MRS_struct = GannetFit(MRS_struct);

  The *.spar files must be in the same directory as the *.sdat files, otherwise an error will occur.

Siemens data (*.dat files)

It is highly recommended that users export data in the TWIX format for Siemens data. This is a raw format that saves the MRS signal for each transient from each RF coil element separately. To run such data, use the following commands:

MRS_struct = GannetLoad({'sub-01.dat'}, {'sub-01_water.dat'});
MRS_struct = GannetFit(MRS_struct);

Siemens data (*.ima files)

The Siemens DICOM-structured IMA format saves each transient in a separate file, such that for an acquisition with 320 transients, there will be 320 IMA files. Data from each acquisition should be stored in an individual directory. To run such data, use the following commands:

MRS_struct = GannetLoad({'metab/file1.ima'}, {'water/file1.ima'});
MRS_struct = GannetFit(MRS_struct);

  Note how the metabolite and water data are stored in separate directories and that a single IMA file is selected for data loading (it does not matter which file in each directory is chosen).

Siemens data (*.rda files)

The Siemens RDA format for edited MRS data usually sums the edit-ON and edit-OFF transients and exports them as single files. A third file with the resulting difference spectrum may also be exported. This format is not recommended for use in Gannet as a number of important preprocessing steps cannot be run. However, to run such data, use the following commands:

MRS_struct = GannetLoad({'OFF.rda', 'ON.rda'});
MRS_struct = GannetFit(MRS_struct);

  Take note that the edit-OFF file must be input first.

Co-registration to MR images

After MRS data files are loaded and fitted, and if an structural MR image was acquired and used to place MRS voxels, Gannet can co-register the two. To do so, use the following command:

MRS_struct = GannetCoRegister(MRS_struct, {'T1w.nii'});

Segmenting MR images

Gannet uses SPM12’s segmentation routine to segment structural MR images. The grey matter, white matter, and cerebrospinal fluid fractions are then used in subsequent tissue corrections of metabolite concentration estimates.

Installation instructions for SPM12 can be found here.

Run segmentation using the following command:

MRS_struct = GannetSegment(MRS_struct);

Quantification

Following tissue segmentation, and assuming a water reference was inputted at data loading, pseudo-absolute quantification can be performed using the following command:

MRS_struct = GannetQuantify(MRS_struct);

Batch processing

One of the major strengths of Gannet is its ability to process datasets in batches using the same pipeline. To load and fit multiple files, simply add more filenames to the respective cell arrays that are passed to GannetLoad.m, as shown below for Philips data:

MRS_struct = GannetLoad({'sub-01_act.sdat', 'sub-02_act.sdat', 'sub-03_act.sdat'}, ...
                        {'sub-01_ref.sdat', 'sub-02_ref.sdat', 'sub-03_ref.sdat'});
MRS_struct = GannetFit(MRS_struct);
# Only if structural MR images are available can the next lines can be run
# Note that the number of structural images must match the number of MRS metabolite data files inputted in GannetLoad
MRS_struct = GannetCoRegister(MRS_struct, {'T1w.nii', 'T1w.nii', 'T1w.nii'});
MRS_struct = GannetSegment(MRS_struct);
MRS_struct = GannetQuantify(MRS_struct);

The respective water reference files sub-01_ref.sdat, sub-02_ref.sdat, etc. need to be listed in the same order as the water-suppressed files sub-01_act.sdat, sub-01_act.sdat, etc. If you intend to process a large number of datasets, we recommend writing a script as a clear way of defining the input cell arrays.

We have provided an example batch processing script that you may modify for your own purposes.

Joining data files

In some instances users may want to conjoin consecutively acquired data files, such that they are processed as if they were one single dataset. Gannet is able to do this. To enable this functionality, the join flag in GannetPreInitialise.m must be set to 1.

However, there is a different command syntax when batch-processing across multiple subjects’ datasets In such cases, rather than entering files as vectors, the input cell arrays must be M \(\times\) N matrices, where M is the number of files per subject to be conjoined and N is the number of subjects.

We have provided an example script for joining files.

Output

As shown in the syntax above, Gannet saves all relevant data and results in a structure (e.g., MRS_struct) at all steps in the analysis pipeline. After creating the initial output from GannetLoad.m, MRS_struct is used as both the output and input arguments for the other Gannet modules. (You need not use MRS_struct; you can use something more descriptive and relevant to your purposes if you wish.)

The output structure contains several fields and subfields, which grow in number as your proceed through the Gannet analysis pipeline. See the list of output structure attributes for a complete description.

You can also output a CSV file containing useful values from the output structure for further analysis in a statistical program of your choice. This functionality is set in GannetPreInitialise.m.

LS0tCnRpdGxlOiAiR2V0dGluZyBzdGFydGVkIgpkYXRlOiAiTGFzdCB1cGRhdGVkOiBgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVCICVkLCAlWScpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IFRSVUUKICAgIHRvY19kZXB0aDogMwogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IEZBTFNFCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGUgPSBGQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCmBgYHtyLCBjaGlsZCA9ICJqcy9iYWNrLXRvLXRvcC5qcyJ9CmBgYAoKPGJyPgoKR2FubmV0IHNpbXBsaWZpZXMgdGhlIHByZXByb2Nlc3NpbmcsIHNpZ25hbCBmaXR0aW5nLCBhbmQgcXVhbnRpZmljYXRpb24gcGlwZWxpbmUgb2YgZWRpdGVkIE1SUyBkYXRhLiBBbGwgeW91IG5lZWQgdG8gZ2V0IHN0YXJ0ZWQgaXMgYSBiYXNpYyB1bmRlcnN0YW5kaW5nIG9mIE1BVExBQiBhbmQgdGhlIGZpdmUgR2FubmV0IG1vZHVsZXMgKGxpc3RlZCBiZWxvdykuCgpJZiB0aGlzIGlzIHlvdXIgZmlyc3QgdGltZSB1c2luZyBHYW5uZXQsIHlvdSBzaG91bGQgcmVhZCB0aHJvdWdoIHRoZSBbUmVmZXJlbmNlXShodHRwczovL21hcmttaWtrZWxzZW4uZ2l0aHViLmlvL0dhbm5ldC1kb2NzL3JlZmVyZW5jZS5odG1sKSBhcyB3ZWxsLiBJZiB5b3UgaGF2ZSBwcmV2aW91c2x5IHdvcmtlZCB3aXRoIEdhbm5ldCBhbmQgb25seSBuZWVkIGEgcXVpY2sgcmVmcmVzaGVyIGFib3V0IHRoZSBjb21tYW5kIHN5bnRheCwgdGhpcyBwYWdlIHdpbGwgcHJvYmFibHkgYmUgYWxsIHlvdSBuZWVkIHRvIGdldCBzdGFydGVkIGFnYWluLgoKIyMgTW9kdWxlcwoKVGhlIGxpbmVhciB3b3JrZmxvdyBvZiBHYW5uZXQgaXMgbWFkZSB1cCBvZiBmaXZlIG1vZHVsZXMuIEZvciBwcm9wZXIgZnVuY3Rpb25hbGl0eSwgdGhleSBuZWVkIHRvIGJlIGV4ZWN1dGVkIGluIHRoZSBmb2xsb3dpbmcgb3JkZXI6Cgp8IDx1Pk1vZHVsZTwvdT4gfCA8dT5EZXNjcmlwdGlvbjwvdT4gfAp8IDotIHwgOi0tLS0tLS0tLSB8CnwgKipHYW5uZXRMb2FkKiogfCBMb2FkcyByYXcgZGF0YSBleHBvcnRlZCBmcm9tIHRoZSBzY2FubmVyOyBwcmVwcm9jZXNzZXMgdGhlbTsgcGxvdHMgdGhlIGVkaXRlZCBzcGVjdHJhOyBhbmQgZ2l2ZXMgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHRpbWUgY291cnNlIG9mIHRoZSBleHBlcmltZW50LiB8CnwgKipHYW5uZXRGaXQqKiB8IE1vZGVscyB0aGUgbWV0YWJvbGl0ZSBzaWduYWxzIG9mIGludGVyZXN0IGluIHRoZSBkaWZmZXJlbmNlIHNwZWN0cmEgYW5kIHRoZSByZWZlcmVuY2UgY29tcG91bmRzOyBwbG90cyB0aGUgZGF0YSBhbmQgdGhlIG1vZGVsIGZpdHM7IGFuZCBnaXZlcyBiYXNpYyBxdWFudGlmaWNhdGlvbiByZXN1bHRzIGFuZCBpbmZvcm1hdGlvbiBhYm91dCBzcGVjdHJhbCBxdWFsaXR5LiB8CnwgKipHYW5uZXRDb1JlZ2lzdGVyKiogfCBMb2FkcyB0aGUgcHJvdmlkZWQgc3RydWN0dXJhbCBpbWFnZSBkYXRhIGZpbGVzOyBjby1yZWdpc3RlcnMgdGhlIGxvYWRlZCBNUlMgdm94ZWwgdG8gdGhlbTsgYW5kIHByb2R1Y2VzIGEgZmlndXJlIHNob3dpbmcgdGhlIGxvY2FsaXphdGlvbiBvZiB0aGUgdm94ZWwgb24gdGhlIHN0cnVjdHVyYWwgaW1hZ2Ugb24gdGhyZWUgb3J0aG9nb25hbCBzbGljZXMuIHwKfCAqKkdhbm5ldFNlZ21lbnQqKiB8IENhbGxzIFNQTSB0byBzZWdtZW50IHRoZSBzdHJ1Y3R1cmFsIGltYWdlczsgZGV0ZXJtaW5lcyB0aGUgZnJhY3Rpb25hbCB0aXNzdWUgY29tcG9zaXRpb24gKGdyYXkgbWF0dGVyLCB3aGl0ZSBtYXR0ZXIsIGFuZCBDU0YpIHdpdGhpbiB0aGUgTVJTIHZveGVsOyBwcm9kdWNlcyBhIGZpZ3VyZSBzaG93aW5nIHRoZSB0aXNzdWUgZnJhY3Rpb25zIGFzIG92ZXJsYXlzIGFuZCBkaXNwbGF5cyBDU0YtY29ycmVjdGVkIG1ldGFib2xpdGUgZXN0aW1hdGVzLiB8CnwgKipHYW5uZXRRdWFudGlmeSoqIHwgVXNlcyB0aGUgc2VnbWVudGF0aW9uIGluZm9ybWF0aW9uIHRvIHBlcmZvcm0gcGFydGlhbCB2b2x1bWUgdGlzc3VlIGNvcnJlY3Rpb24gYW5kIHByb2R1Y2VzIGEgZmlndXJlIGRpc3BsYXlpbmcgc2V2ZXJhbCB0aXNzdWUtY29ycmVjdGVkIG1ldGFib2xpdGUgbWVhc3VyZW1lbnRzLiB8CgpGYW1pbGlhcml6ZSB5b3Vyc2VsZiB3aXRoIHRoZSBmaXZlIGJhc2ljIEdhbm5ldCBjb21tYW5kcywgYXMgZGVzY3JpYmVkIGJlbG93LiBUaGUgbnVtYmVyIG9mIGNvbW1hbmRzIGlzIGRlbGliZXJhdGVseSBrZXB0IHRvIGEgbWluaW11bSwgYXMgaXMgdGhlIG51bWJlciBvZiBwb3NzaWJsZSBpbnB1dCBhcmd1bWVudHMgdG8gdGhlc2UgY29tbWFuZHMuIEluY29ycmVjdCBzeW50YXggaXMgYSBjb21tb24gc291cmNlIG9mIHVzZXIgZXJyb3IsIHNvIG1ha2Ugc3VyZSB0aGF0IHlvdSB1bmRlcnN0YW5kIHRoZSBhcmd1bWVudCBzdHJ1Y3R1cmUgb2YgZWFjaCBmdW5jdGlvbiB5b3UgaW50ZW5kIHRvIHVzZS4KCiMjIFVzYWdlCgojIyMgR2FubmV0UHJlSW5pdGlhbGlzZQoKVGhlIGZpcnN0IHN0ZXAgaW4gdXNpbmcgR2FubmV0IGlzIHRvIHNldCB1cCB0aGUgYEdhbm5ldFByZUluaXRpYWxpc2UubWAgZnVuY3Rpb24uIFdoaWxlIHRoZSB0b29sa2l0IGhhcyBtYW55IHJvdXRpbmVzIHRoYXQgYXV0b21hdGljYWxseSByZWNvZ25pemUgZGF0YSBmb3JtYXRzLCBzZXF1ZW5jZXMsIGFuZCBhY3F1aXNpdGlvbiBwYXJhbWV0ZXJzIGZyb20gZGF0YSBmaWxlIGhlYWRlcnM7IHNvbWUgc2V0dGluZ3MgbmVlZCB0byBiZSBzZXQgYnkgdGhlIHVzZXIgdG8gcnVuIEdhbm5ldCBwcm9wZXJseS4gQWRkaXRpb25hbGx5LCBgR2FubmV0UHJlSW5pdGlhbGlzZS5tYCBhbGxvd3MgdGhlIHVzZXIgdG8gY2hvb3NlIGhvdyB0byBwcm9jZXNzIHRoZWlyIGRhdGEgKGZvciBleGFtcGxlLCB3aGljaCBmcmVxdWVuY3ktYW5kLXBoYXNlIGNvcnJlY3Rpb24gYWxnb3JpdGhtIHRvIHVzZSkuCgo6Ojogd2FybmluZwo8aSBjbGFzcz0iZmEgZmEtZXhjbGFtYXRpb24tY2lyY2xlIiBzdHlsZT0iY29sb3I6IHdoaXRlIj48L2k+Jm5ic3A7IEFueSB0aW1lIHlvdSBydW4gR2FubmV0LCBtYWtlIHN1cmUgdG8gY2hlY2sgdGhhdCB0aGUgc2V0dGluZ3MgaW4gYEdhbm5ldFByZUluaXRpYWxpc2UubWAgYXJlIGNvcnJlY3QuIE1hbnkgZXJyb3JzIGNhbiBiZSBhdm9pZGVkIGJ5IGZvbGxvd2luZyB0aGlzIHNpbXBsZSBzdGVwLgo6OjoKClRoZSBkZWZhdWx0IHNldHRpbmdzIHByZS1pbml0aWFsaXplIGEgc3RhbmRhcmQgYW5hbHlzaXMgZm9yIGluIHZpdm8gR0FCQS1lZGl0ZWQgTUVHQS1QUkVTUyBkYXRhLiBJZiB5b3Ugd2FudCB0byBhbmFseXplIGRhdGEgYWNxdWlyZWQgd2l0aCBhIGRpZmZlcmVudCBtZXRob2Qgb3IgZnJvbSBhIHBoYW50b20sIG9yIHRhcmdldCBhIGRpZmZlcmVudCBtZXRhYm9saXRlLCB5b3Ugd2lsbCBuZWVkIHRvIG1ha2UgY2hhbmdlcyB0byB0aGlzIGZpbGUuIFBsZWFzZSByZWFkIHRoZSBbUmVmZXJlbmNlXShodHRwczovL21hcmttaWtrZWxzZW4uZ2l0aHViLmlvL0dhbm5ldC1kb2NzL3JlZmVyZW5jZS5odG1sI3ByZS1pbml0aWFsaXppbmctZ2FubmV0KSBmb3IgZGV0YWlsZWQgZXhwbGFuYXRpb25zIG9mIHRoZSBvcHRpb25zIGFuZCBmbGFncyBpbiBgR2FubmV0UHJlSW5pdGlhbGlzZS5tYC4KCjxpbWcgc3JjPSJpbWFnZXMvZ2V0dGluZy1zdGFydGVkL0dhbm5ldFByZUluaXRpYWxpc2UtZXhhbXBsZS5wbmciIGFsdD0iQSBzY3JlZW5zaG90IGV4YW1wbGUgb2YgR2FubmV0UHJlSW5pdGlhbGlzZS5tIj4KCiMjIyBMb2FkaW5nIGFuZCBmaXR0aW5nIGRhdGEKCkRlcGVuZGluZyBvbiB0aGUgZm9ybWF0IG9mIHlvdXIgZGF0YSwgYW5kIGlmIHlvdSBoYXZlIHdhdGVyIHJlZmVyZW5jZSBkYXRhIGFuZC9vciBzdHJ1Y3R1cmFsIGltYWdlcywgdGhlIGNvbW1hbmRzIGZvciBydW5uaW5nIEdhbm5ldCB0byBsb2FkIGFuZCBmaXQgeW91ciBkYXRhIGZvbGxvdyBhIHNwZWNpZmljIHN5bnRheC4KCkZvciBhbGwgbW9kdWxlcywgYW4gb3V0cHV0IGFyZ3VtZW50IGNvbnRhaW5pbmcgYSBzdHJ1Y3R1cmUgc2hvdWxkIGFsd2F5cyBiZSBpbmNsdWRlZCwgZm9yIGV4YW1wbGUgYE1SU19zdHJ1Y3RgLiBJbnB1dCBhcmd1bWVudHMgZm9yIGBHYW5uZXRMb2FkLm1gIGFyZSB1c3VhbGx5IGdpdmVuIGFzIGNlbGwgYXJyYXlzLiBXYXRlci1zdXBwcmVzc2VkIG1ldGFib2xpdGUgZmlsZXMgbXVzdCBiZSBnaXZlbiBhcyB0aGUgZmlyc3QgaW5wdXQgYXJndW1lbnQsIHdoaWxlIHVuc3VwcHJlc3NlZCB3YXRlciByZWZlcmVuY2UgZmlsZXMgbXVzdCBiZSBnaXZlbiBhcyB0aGUgc2Vjb25kIGlucHV0IGFyZ3VtZW50LiBUaGUgcmVtYWluaW5nIG1vZHVsZXMgcmVxdWlyZSBpbnB1dCBvZiB0aGUgb3V0cHV0IHN0cnVjdHVyZSBmcm9tIGBHYW5uZXRMb2FkLm1gLiAoVGhlIGV4Y2VwdGlvbiBpcyBgR2FubmV0Q29SZWdpc3Rlci5tYCwgd2hpY2ggYWRkaXRpb25hbGx5IHJlcXVpcmVzIGEgY2VsbCBhcnJheSBvZiBzdHJ1Y3R1cmFsIGltYWdlcy4pCgpTb21lIGV4YW1wbGVzIGZvciBkaWZmZXJlbnQgZGF0YSBmaWxlIGZvcm1hdHM6CgojIyMjICoqRElDT00gZGF0YSAoXCouZGNtIGZpbGVzKSoqCgpUaGUgRElDT00gZm9ybWF0IHNhdmVzIGVhY2ggdHJhbnNpZW50IGluIGEgc2VwYXJhdGUgZmlsZSwgc3VjaCB0aGF0IGZvciBhbiBhY3F1aXNpdGlvbiB3aXRoIDMyMCB0cmFuc2llbnRzLCB0aGVyZSB3aWxsIGJlIDMyMCBESUNPTSBmaWxlcy4gRGF0YSBmcm9tIGVhY2ggYWNxdWlzaXRpb24gc2hvdWxkIGJlIHN0b3JlZCBpbiBhbiBpbmRpdmlkdWFsIGRpcmVjdG9yeS4gVG8gcnVuIHN1Y2ggZGF0YSwgdXNlIHRoZSBmb2xsb3dpbmcgY29tbWFuZHM6CgpgYGB7b2N0YXZlLCBldmFsID0gRkFMU0V9Ck1SU19zdHJ1Y3QgPSBHYW5uZXRMb2FkKHsnbWV0YWIvZmlsZTEuZGNtJ30sIHsnd2F0ZXIvZmlsZTEuZGNtJ30pOwpNUlNfc3RydWN0ID0gR2FubmV0Rml0KE1SU19zdHJ1Y3QpOwpgYGAKCjo6OiBpbmZvCjxpIGNsYXNzPSJmYSBmYS1pbmZvLWNpcmNsZSIgc3R5bGU9ImNvbG9yOiB3aGl0ZSI+PC9pPiZuYnNwOyBOb3RlIGhvdyB0aGUgbWV0YWJvbGl0ZSBhbmQgd2F0ZXIgZGF0YSBhcmUgc3RvcmVkIGluIHNlcGFyYXRlIGRpcmVjdG9yaWVzIGFuZCB0aGF0IGEgc2luZ2xlIERJQ09NIGZpbGUgaXMgc2VsZWN0ZWQgZm9yIGRhdGEgbG9hZGluZyAoaXQgZG9lcyBub3QgbWF0dGVyIHdoaWNoIGZpbGUgaW4gZWFjaCBkaXJlY3RvcnkgaXMgY2hvc2VuKS4KOjo6CgojIyMjICoqR0UgZGF0YSAoXCouNyBmaWxlcykqKgoKRGF0YSBmcm9tIEdFIHNjYW5uZXJzIGFyZSBleHBvcnRlZCBhcyBhIFAtZmlsZSwgd2l0aCB0aGUgZXh0ZW5zaW9uIFwqLjcuIFN0YW5kYXJkIEdFIGFjcXVpc2l0aW9ucyBhdXRvbWF0aWNhbGx5IGFjcXVpcmUgYSB3YXRlciByZWZlcmVuY2UsIHdoaWNoIGlzIHN0b3JlZCB3aXRoaW4gdGhlIFAtZmlsZS4gVG8gcnVuIHN1Y2ggZGF0YSwgdXNlIHRoZSBmb2xsb3dpbmcgY29tbWFuZHM6CgpgYGB7b2N0YXZlLCBldmFsID0gRkFMU0V9Ck1SU19zdHJ1Y3QgPSBHYW5uZXRMb2FkKHsnc3ViLTAxLjcnfSk7Ck1SU19zdHJ1Y3QgPSBHYW5uZXRGaXQoTVJTX3N0cnVjdCk7CmBgYAoKIyMjIyAqKk5JZlRJIGRhdGEgKFwqLm5paVsuZ3pdIGZpbGVzKSoqCgo8YSBocmVmPSJodHRwczovL2RvaS5vcmcvMTAuMTAwMi9tcm0uMjk0MTgiIHRhcmdldD0iX2JsYW5rIj5OSWZUSS1NUlM8L2E+IHdhcyBkZXZlbG9wZWQgdG8gc2VydmUgYXMgYW4gb3Blbi1zb3VyY2UgZGF0YSBmb3JtYXQgc3RhbmRhcmQgZm9yIE1SUy4gQm90aCBjb21wcmVzc2VkIGFuZCB1bmNvbXByZXNzZWQgZmlsZXMgY2FuIGJlIHByb2Nlc3NlZCBpbiBHYW5uZXQuIFRvIHJ1biBzdWNoIGRhdGEsIHVzZSB0aGUgZm9sbG93aW5nIGNvbW1hbmRzOgoKYGBge29jdGF2ZSwgZXZhbCA9IEZBTFNFfQpNUlNfc3RydWN0ID0gR2FubmV0TG9hZCh7J3N1Yi0wMS5uaWknfSwgeydzdWItMDFfcmVmLm5paSd9KTsKTVJTX3N0cnVjdCA9IEdhbm5ldEZpdChNUlNfc3RydWN0KTsKYGBgCgojIyMjICoqUGhpbGlwcyBkYXRhIChcKi5zZGF0L1wqLnNwYXIgZmlsZXMpKioKCkRhdGEgZnJvbSBQaGlsaXBzIHNjYW5uZXJzIGFyZSBtb3N0IGNvbW1vbmx5IGV4cG9ydGVkIGFzIGEgcGFpciBvZiBcKi5zZGF0L1wqLnNwYXIgZmlsZXMsIHdoZXJlIHRoZSBcKi5zZGF0IGZpbGUgY29udGFpbnMgdGhlIGRhdGEgYW5kIHRoZSBcKi5zcGFyIGNvbnRhaW5zIHRoZSBhY3F1aXNpdGlvbiBwYXJhbWV0ZXJzLiBBIHdhdGVyIHJlZmVyZW5jZSB1c3VhbGx5IGlzIGFsc28gYWNxdWlyZWQgYW5kIGV4cG9ydGVkIGFzIGEgc2VwYXJhdGUgcGFpciBvZiBmaWxlcy4gVGhlIHR3byBhcmUgZGlzdGluZ3Vpc2hlZCBieSB0aGUgc3VmZmljZXMgYF9hY3RgIGFuZCBgX3JlZmAuIFRvIHJ1biBzdWNoIGRhdGEsIHVzZSB0aGUgZm9sbG93aW5nIGNvbW1hbmRzOgoKYGBge29jdGF2ZSwgZXZhbCA9IEZBTFNFfQpNUlNfc3RydWN0ID0gR2FubmV0TG9hZCh7J3N1Yi0wMV9hY3Quc2RhdCd9LCB7J3N1Yi0wMV9yZWYuc2RhdCd9KTsKTVJTX3N0cnVjdCA9IEdhbm5ldEZpdChNUlNfc3RydWN0KTsKYGBgCgo6OjogaW5mbwo8aSBjbGFzcz0iZmEgZmEtaW5mby1jaXJjbGUiIHN0eWxlPSJjb2xvcjogd2hpdGUiPjwvaT4mbmJzcDsgVGhlIFwqLnNwYXIgZmlsZXMgbXVzdCBiZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkgYXMgdGhlIFwqLnNkYXQgZmlsZXMsIG90aGVyd2lzZSBhbiBlcnJvciB3aWxsIG9jY3VyLgo6OjoKCiMjIyMgKipTaWVtZW5zIGRhdGEgKFwqLmRhdCBmaWxlcykqKgoKSXQgaXMgaGlnaGx5IHJlY29tbWVuZGVkIHRoYXQgdXNlcnMgZXhwb3J0IGRhdGEgaW4gdGhlIFRXSVggZm9ybWF0IGZvciBTaWVtZW5zIGRhdGEuIFRoaXMgaXMgYSByYXcgZm9ybWF0IHRoYXQgc2F2ZXMgdGhlIE1SUyBzaWduYWwgZm9yIGVhY2ggdHJhbnNpZW50IGZyb20gZWFjaCBSRiBjb2lsIGVsZW1lbnQgc2VwYXJhdGVseS4gVG8gcnVuIHN1Y2ggZGF0YSwgdXNlIHRoZSBmb2xsb3dpbmcgY29tbWFuZHM6CgpgYGB7b2N0YXZlLCBldmFsID0gRkFMU0V9Ck1SU19zdHJ1Y3QgPSBHYW5uZXRMb2FkKHsnc3ViLTAxLmRhdCd9LCB7J3N1Yi0wMV93YXRlci5kYXQnfSk7Ck1SU19zdHJ1Y3QgPSBHYW5uZXRGaXQoTVJTX3N0cnVjdCk7CmBgYAoKIyMjIyAqKlNpZW1lbnMgZGF0YSAoXCouaW1hIGZpbGVzKSoqCgpUaGUgU2llbWVucyBESUNPTS1zdHJ1Y3R1cmVkIElNQSBmb3JtYXQgc2F2ZXMgZWFjaCB0cmFuc2llbnQgaW4gYSBzZXBhcmF0ZSBmaWxlLCBzdWNoIHRoYXQgZm9yIGFuIGFjcXVpc2l0aW9uIHdpdGggMzIwIHRyYW5zaWVudHMsIHRoZXJlIHdpbGwgYmUgMzIwIElNQSBmaWxlcy4gRGF0YSBmcm9tIGVhY2ggYWNxdWlzaXRpb24gc2hvdWxkIGJlIHN0b3JlZCBpbiBhbiBpbmRpdmlkdWFsIGRpcmVjdG9yeS4gVG8gcnVuIHN1Y2ggZGF0YSwgdXNlIHRoZSBmb2xsb3dpbmcgY29tbWFuZHM6CgpgYGB7b2N0YXZlLCBldmFsID0gRkFMU0V9Ck1SU19zdHJ1Y3QgPSBHYW5uZXRMb2FkKHsnbWV0YWIvZmlsZTEuaW1hJ30sIHsnd2F0ZXIvZmlsZTEuaW1hJ30pOwpNUlNfc3RydWN0ID0gR2FubmV0Rml0KE1SU19zdHJ1Y3QpOwpgYGAKCjo6OiBpbmZvCjxpIGNsYXNzPSJmYSBmYS1pbmZvLWNpcmNsZSIgc3R5bGU9ImNvbG9yOiB3aGl0ZSI+PC9pPiZuYnNwOyBOb3RlIGhvdyB0aGUgbWV0YWJvbGl0ZSBhbmQgd2F0ZXIgZGF0YSBhcmUgc3RvcmVkIGluIHNlcGFyYXRlIGRpcmVjdG9yaWVzIGFuZCB0aGF0IGEgc2luZ2xlIElNQSBmaWxlIGlzIHNlbGVjdGVkIGZvciBkYXRhIGxvYWRpbmcgKGl0IGRvZXMgbm90IG1hdHRlciB3aGljaCBmaWxlIGluIGVhY2ggZGlyZWN0b3J5IGlzIGNob3NlbikuCjo6OgoKIyMjIyAqKlNpZW1lbnMgZGF0YSAoXCoucmRhIGZpbGVzKSoqCgpUaGUgU2llbWVucyBSREEgZm9ybWF0IGZvciBlZGl0ZWQgTVJTIGRhdGEgdXN1YWxseSBzdW1zIHRoZSBlZGl0LU9OIGFuZCBlZGl0LU9GRiB0cmFuc2llbnRzIGFuZCBleHBvcnRzIHRoZW0gYXMgc2luZ2xlIGZpbGVzLiBBIHRoaXJkIGZpbGUgd2l0aCB0aGUgcmVzdWx0aW5nIGRpZmZlcmVuY2Ugc3BlY3RydW0gbWF5IGFsc28gYmUgZXhwb3J0ZWQuIFRoaXMgZm9ybWF0IGlzIG5vdCByZWNvbW1lbmRlZCBmb3IgdXNlIGluIEdhbm5ldCBhcyBhIG51bWJlciBvZiBpbXBvcnRhbnQgcHJlcHJvY2Vzc2luZyBzdGVwcyBjYW5ub3QgYmUgcnVuLiBIb3dldmVyLCB0byBydW4gc3VjaCBkYXRhLCB1c2UgdGhlIGZvbGxvd2luZyBjb21tYW5kczoKCmBgYHtvY3RhdmUsIGV2YWwgPSBGQUxTRX0KTVJTX3N0cnVjdCA9IEdhbm5ldExvYWQoeydPRkYucmRhJywgJ09OLnJkYSd9KTsKTVJTX3N0cnVjdCA9IEdhbm5ldEZpdChNUlNfc3RydWN0KTsKYGBgCgo6OjogaW5mbwo8aSBjbGFzcz0iZmEgZmEtaW5mby1jaXJjbGUiIHN0eWxlPSJjb2xvcjogd2hpdGUiPjwvaT4mbmJzcDsgVGFrZSBub3RlIHRoYXQgdGhlIGVkaXQtT0ZGIGZpbGUgbXVzdCBiZSBpbnB1dCBmaXJzdC4KOjo6CgojIyMgQ28tcmVnaXN0cmF0aW9uIHRvIE1SIGltYWdlcwoKQWZ0ZXIgTVJTIGRhdGEgZmlsZXMgYXJlIGxvYWRlZCBhbmQgZml0dGVkLCBhbmQgaWYgYW4gc3RydWN0dXJhbCBNUiBpbWFnZSB3YXMgYWNxdWlyZWQgYW5kIHVzZWQgdG8gcGxhY2UgTVJTIHZveGVscywgR2FubmV0IGNhbiBjby1yZWdpc3RlciB0aGUgdHdvLiBUbyBkbyBzbywgdXNlIHRoZSBmb2xsb3dpbmcgY29tbWFuZDogCgpgYGB7b2N0YXZlLCBldmFsID0gRkFMU0V9Ck1SU19zdHJ1Y3QgPSBHYW5uZXRDb1JlZ2lzdGVyKE1SU19zdHJ1Y3QsIHsnVDF3Lm5paSd9KTsKYGBgCgojIyMgU2VnbWVudGluZyBNUiBpbWFnZXMKCkdhbm5ldCB1c2VzIFNQTTEyJ3Mgc2VnbWVudGF0aW9uIHJvdXRpbmUgdG8gc2VnbWVudCBzdHJ1Y3R1cmFsIE1SIGltYWdlcy4gVGhlIGdyZXkgbWF0dGVyLCB3aGl0ZSBtYXR0ZXIsIGFuZCBjZXJlYnJvc3BpbmFsIGZsdWlkIGZyYWN0aW9ucyBhcmUgdGhlbiB1c2VkIGluIHN1YnNlcXVlbnQgdGlzc3VlIGNvcnJlY3Rpb25zIG9mIG1ldGFib2xpdGUgY29uY2VudHJhdGlvbiBlc3RpbWF0ZXMuCgpJbnN0YWxsYXRpb24gaW5zdHJ1Y3Rpb25zIGZvciBTUE0xMiBjYW4gYmUgZm91bmQgW2hlcmVdKGh0dHBzOi8vbWFya21pa2tlbHNlbi5naXRodWIuaW8vR2FubmV0LWRvY3MvaW5kZXguaHRtbCNpbnN0YWxsYXRpb24pLgoKUnVuIHNlZ21lbnRhdGlvbiB1c2luZyB0aGUgZm9sbG93aW5nIGNvbW1hbmQ6CgpgYGB7b2N0YXZlLCBldmFsID0gRkFMU0V9Ck1SU19zdHJ1Y3QgPSBHYW5uZXRTZWdtZW50KE1SU19zdHJ1Y3QpOwpgYGAKCiMjIyBRdWFudGlmaWNhdGlvbgoKRm9sbG93aW5nIHRpc3N1ZSBzZWdtZW50YXRpb24sIGFuZCBhc3N1bWluZyBhIHdhdGVyIHJlZmVyZW5jZSB3YXMgaW5wdXR0ZWQgYXQgZGF0YSBsb2FkaW5nLCBwc2V1ZG8tYWJzb2x1dGUgcXVhbnRpZmljYXRpb24gY2FuIGJlIHBlcmZvcm1lZCB1c2luZyB0aGUgZm9sbG93aW5nIGNvbW1hbmQ6CgpgYGB7b2N0YXZlLCBldmFsID0gRkFMU0V9Ck1SU19zdHJ1Y3QgPSBHYW5uZXRRdWFudGlmeShNUlNfc3RydWN0KTsKYGBgCgojIyBCYXRjaCBwcm9jZXNzaW5nCgpPbmUgb2YgdGhlIG1ham9yIHN0cmVuZ3RocyBvZiBHYW5uZXQgaXMgaXRzIGFiaWxpdHkgdG8gcHJvY2VzcyBkYXRhc2V0cyBpbiBiYXRjaGVzIHVzaW5nIHRoZSBzYW1lIHBpcGVsaW5lLiBUbyBsb2FkIGFuZCBmaXQgbXVsdGlwbGUgZmlsZXMsIHNpbXBseSBhZGQgbW9yZSBmaWxlbmFtZXMgdG8gdGhlIHJlc3BlY3RpdmUgY2VsbCBhcnJheXMgdGhhdCBhcmUgcGFzc2VkIHRvIGBHYW5uZXRMb2FkLm1gLCBhcyBzaG93biBiZWxvdyBmb3IgUGhpbGlwcyBkYXRhOgoKYGBge29jdGF2ZSwgZXZhbCA9IEZBTFNFfQpNUlNfc3RydWN0ID0gR2FubmV0TG9hZCh7J3N1Yi0wMV9hY3Quc2RhdCcsICdzdWItMDJfYWN0LnNkYXQnLCAnc3ViLTAzX2FjdC5zZGF0J30sIC4uLgogICAgICAgICAgICAgICAgICAgICAgICB7J3N1Yi0wMV9yZWYuc2RhdCcsICdzdWItMDJfcmVmLnNkYXQnLCAnc3ViLTAzX3JlZi5zZGF0J30pOwpNUlNfc3RydWN0ID0gR2FubmV0Rml0KE1SU19zdHJ1Y3QpOwojIE9ubHkgaWYgc3RydWN0dXJhbCBNUiBpbWFnZXMgYXJlIGF2YWlsYWJsZSBjYW4gdGhlIG5leHQgbGluZXMgY2FuIGJlIHJ1bgojIE5vdGUgdGhhdCB0aGUgbnVtYmVyIG9mIHN0cnVjdHVyYWwgaW1hZ2VzIG11c3QgbWF0Y2ggdGhlIG51bWJlciBvZiBNUlMgbWV0YWJvbGl0ZSBkYXRhIGZpbGVzIGlucHV0dGVkIGluIEdhbm5ldExvYWQKTVJTX3N0cnVjdCA9IEdhbm5ldENvUmVnaXN0ZXIoTVJTX3N0cnVjdCwgeydUMXcubmlpJywgJ1Qxdy5uaWknLCAnVDF3Lm5paSd9KTsKTVJTX3N0cnVjdCA9IEdhbm5ldFNlZ21lbnQoTVJTX3N0cnVjdCk7Ck1SU19zdHJ1Y3QgPSBHYW5uZXRRdWFudGlmeShNUlNfc3RydWN0KTsKYGBgCgpUaGUgcmVzcGVjdGl2ZSB3YXRlciByZWZlcmVuY2UgZmlsZXMgYHN1Yi0wMV9yZWYuc2RhdGAsIGBzdWItMDJfcmVmLnNkYXRgLCBldGMuIG5lZWQgdG8gYmUgbGlzdGVkIGluIHRoZSBzYW1lIG9yZGVyIGFzIHRoZSB3YXRlci1zdXBwcmVzc2VkIGZpbGVzIGBzdWItMDFfYWN0LnNkYXRgLCBgc3ViLTAxX2FjdC5zZGF0YCwgZXRjLiBJZiB5b3UgaW50ZW5kIHRvIHByb2Nlc3MgYSBsYXJnZSBudW1iZXIgb2YgZGF0YXNldHMsIHdlIHJlY29tbWVuZCB3cml0aW5nIGEgc2NyaXB0IGFzIGEgY2xlYXIgd2F5IG9mIGRlZmluaW5nIHRoZSBpbnB1dCBjZWxsIGFycmF5cy4KCldlIGhhdmUgcHJvdmlkZWQgYW4gW2V4YW1wbGUgYmF0Y2ggcHJvY2Vzc2luZyBzY3JpcHRdKGh0dHBzOi8vbWFya21pa2tlbHNlbi5naXRodWIuaW8vR2FubmV0LWRvY3MvYmF0Y2gtc2NyaXB0Lmh0bWwpIHRoYXQgeW91IG1heSBtb2RpZnkgZm9yIHlvdXIgb3duIHB1cnBvc2VzLgoKIyMgSm9pbmluZyBkYXRhIGZpbGVzCgpJbiBzb21lIGluc3RhbmNlcyB1c2VycyBtYXkgd2FudCB0byBjb25qb2luIGNvbnNlY3V0aXZlbHkgYWNxdWlyZWQgZGF0YSBmaWxlcywgc3VjaCB0aGF0IHRoZXkgYXJlIHByb2Nlc3NlZCBhcyBpZiB0aGV5IHdlcmUgb25lIHNpbmdsZSBkYXRhc2V0LiBHYW5uZXQgaXMgYWJsZSB0byBkbyB0aGlzLiBUbyBlbmFibGUgdGhpcyBmdW5jdGlvbmFsaXR5LCB0aGUgYGpvaW5gIGZsYWcgaW4gYEdhbm5ldFByZUluaXRpYWxpc2UubWAgbXVzdCBiZSBzZXQgdG8gYDFgLgoKSG93ZXZlciwgdGhlcmUgaXMgYSBkaWZmZXJlbnQgY29tbWFuZCBzeW50YXggd2hlbiBiYXRjaC1wcm9jZXNzaW5nIGFjcm9zcyBtdWx0aXBsZSBzdWJqZWN0cycgZGF0YXNldHMgSW4gc3VjaCBjYXNlcywgcmF0aGVyIHRoYW4gZW50ZXJpbmcgZmlsZXMgYXMgdmVjdG9ycywgdGhlIGlucHV0IGNlbGwgYXJyYXlzIG11c3QgYmUgTSAkXHRpbWVzJCBOIG1hdHJpY2VzLCB3aGVyZSBNIGlzIHRoZSBudW1iZXIgb2YgZmlsZXMgcGVyIHN1YmplY3QgdG8gYmUgY29uam9pbmVkIGFuZCBOIGlzIHRoZSBudW1iZXIgb2Ygc3ViamVjdHMuCgpXZSBoYXZlIHByb3ZpZGVkIGFuIFtleGFtcGxlIHNjcmlwdF0oaHR0cHM6Ly9tYXJrbWlra2Vsc2VuLmdpdGh1Yi5pby9HYW5uZXQtZG9jcy9qb2luaW5nLWRhdGEtZmlsZXMuaHRtbCkgZm9yIGpvaW5pbmcgZmlsZXMuCgojIyBPdXRwdXQKCkFzIHNob3duIGluIHRoZSBzeW50YXggYWJvdmUsIEdhbm5ldCBzYXZlcyBhbGwgcmVsZXZhbnQgZGF0YSBhbmQgcmVzdWx0cyBpbiBhIHN0cnVjdHVyZSAoZS5nLiwgYE1SU19zdHJ1Y3RgKSBhdCBhbGwgc3RlcHMgaW4gdGhlIGFuYWx5c2lzIHBpcGVsaW5lLiBBZnRlciBjcmVhdGluZyB0aGUgaW5pdGlhbCBvdXRwdXQgZnJvbSBgR2FubmV0TG9hZC5tYCwgYE1SU19zdHJ1Y3RgIGlzIHVzZWQgYXMgYm90aCB0aGUgb3V0cHV0IGFuZCBpbnB1dCBhcmd1bWVudHMgZm9yIHRoZSBvdGhlciBHYW5uZXQgbW9kdWxlcy4gKFlvdSBuZWVkIG5vdCB1c2UgYE1SU19zdHJ1Y3RgOyB5b3UgY2FuIHVzZSBzb21ldGhpbmcgbW9yZSBkZXNjcmlwdGl2ZSBhbmQgcmVsZXZhbnQgdG8geW91ciBwdXJwb3NlcyBpZiB5b3Ugd2lzaC4pCgpUaGUgb3V0cHV0IHN0cnVjdHVyZSBjb250YWlucyBzZXZlcmFsIGZpZWxkcyBhbmQgc3ViZmllbGRzLCB3aGljaCBncm93IGluIG51bWJlciBhcyB5b3VyIHByb2NlZWQgdGhyb3VnaCB0aGUgR2FubmV0IGFuYWx5c2lzIHBpcGVsaW5lLiBTZWUgdGhlIGxpc3Qgb2YgW291dHB1dCBzdHJ1Y3R1cmUgYXR0cmlidXRlc10oaHR0cHM6Ly9tYXJrbWlra2Vsc2VuLmdpdGh1Yi5pby9HYW5uZXQtZG9jcy9vdXRwdXQtc3RydWN0dXJlLWF0dHJpYnV0ZXMuaHRtbCkgZm9yIGEgY29tcGxldGUgZGVzY3JpcHRpb24uCgpZb3UgY2FuIGFsc28gb3V0cHV0IGEgQ1NWIGZpbGUgY29udGFpbmluZyB1c2VmdWwgdmFsdWVzIGZyb20gdGhlIG91dHB1dCBzdHJ1Y3R1cmUgZm9yIGZ1cnRoZXIgYW5hbHlzaXMgaW4gYSBzdGF0aXN0aWNhbCBwcm9ncmFtIG9mIHlvdXIgY2hvaWNlLiBUaGlzIGZ1bmN0aW9uYWxpdHkgaXMgc2V0IGluIGBHYW5uZXRQcmVJbml0aWFsaXNlLm1gLgoKCgo=


Built with R Markdown in RStudio

Copyright © 2020–2024, Mark Mikkelsen