{"action":"created","comment":{"url":"https://api.github.com/repos/SuperDARNCanada/borealis/pulls/comments/123095868","pull_request_review_id":45253781,"id":123095868,"diff_hunk":"@@ -15,406 +15,234 @@\n #include <thrust/complex.h>\n #include <cuda_profiler_api.h>\n #include <thrust/system/cuda/experimental/pinned_allocator.h>\n-#include \"utils/protobuf/computationpacket.pb.h\"\n+#include \"utils/protobuf/rxsamplesmetadata.pb.h\"\n #include \"utils/protobuf/sigprocpacket.pb.h\"\n #include \"utils/driver_options/driveroptions.hpp\"\n #include \"utils/signal_processing_options/signalprocessingoptions.hpp\"\n #include \"utils/shared_memory/shared_memory.hpp\"\n \n #include \"dsp.hpp\"\n+#include \"filtering.hpp\"\n \n-extern \"C\" {\n-    #include \"remez.h\"\n-}\n+#ifdef DEBUG\n+#define DEBUG_MSG(x) do {std::cerr << x << std::endl;} while (0)\n+#else\n+#define DEBUG_MSG(x)\n+#endif\n \n-// REVIEW #30 all filter-building functions could be placed in a separate file?\n-// REPLY could be. Could potentially make a filter building class.\n+#define ERR_CHK_ZMQ(x) try {x;} catch (zmq::error_t& e) {} //TODO(keith): handle error\n \n-std::vector<double> create_normalized_lowpass_filter_bands(float cutoff, float transition_band,\n-                        float Fs) { //REVIEW #5 units for params //REPLY this should prolly go in the doc string\n-    std::vector<double> filterbands; //REVIEW #3 describe band choices and how this works //REPLY Should this description be here or in our written documentation?\n-    filterbands.push_back(0.0);\n-    filterbands.push_back(cutoff/Fs);\n-    filterbands.push_back((cutoff + transition_band)/Fs);\n-    filterbands.push_back(0.5);\n \n-    return filterbands;\n-}\n+int main(int argc, char **argv){\n+  GOOGLE_PROTOBUF_VERIFY_VERSION; // Verifies that header and lib are same version.\n+\n+  //TODO(keith): verify config options.\n+  auto driver_options = DriverOptions();\n+  auto sig_options = SignalProcessingOptions();\n+  auto rx_rate = driver_options.get_rx_rate(); //Hz\n+\n+  zmq::context_t sig_proc_context(1); // 1 is context num. Only need one per program as per examples\n+\n+  zmq::socket_t driver_socket(sig_proc_context, ZMQ_PAIR);\n+  ERR_CHK_ZMQ(driver_socket.bind(\"ipc:///tmp/feeds/1\"))\n+\n+\n+  //This socket is used to receive metadata about the sequence to process\n+  zmq::socket_t radar_control_socket(sig_proc_context, ZMQ_PAIR);\n+  ERR_CHK_ZMQ(radar_control_socket.bind(\"ipc:///tmp/feeds/2\"))\n+\n+  //This socket is used to acknowledge a completed sequence to radar_control\n+  zmq::socket_t ack_socket(sig_proc_context, ZMQ_PAIR);\n+  ERR_CHK_ZMQ(ack_socket.bind(\"ipc:///tmp/feeds/3\"))\n+\n+  //This socket is used to send the GPU kernel timing to radar_control to know if the processing\n+  //can be done in real-time.\n+  zmq::socket_t timing_socket(sig_proc_context, ZMQ_PAIR);\n+  ERR_CHK_ZMQ(timing_socket.bind(\"ipc:///tmp/feeds/4\"))\n+\n+\n+  auto gpu_properties = get_gpu_properties();\n+  print_gpu_properties(gpu_properties);\n+\n+  uint32_t first_stage_dm_rate = 0, second_stage_dm_rate = 0, third_stage_dm_rate = 0;\n+  //Check for non integer dm rates\n+  if (fmod(rx_rate,sig_options.get_first_stage_sample_rate()) > 0.0) {\n+    //TODO(keith): handle error\n+  } //TODO(keith): not sure these checks will work.\n+/*  else if (fmod(sig_options.get_first_stage_sample_rate(),\n+          sig_options.get_second_stage_sample_rate()) > 0.0) {\n+    //TODO(keith): handle error\n+  }\n+  else if(fmod(sig_options.get_second_stage_sample_rate(),\n+        sig_options.get_third_stage_sample_rate()) > 0.0) {\n+    //TODO(keith): handle error\n+  }*/\n+  else{\n+    auto float_dm_rate = rx_rate/sig_options.get_first_stage_sample_rate();\n+    first_stage_dm_rate = static_cast<uint32_t>(float_dm_rate);\n+\n+    float_dm_rate = sig_options.get_first_stage_sample_rate()/\n+          sig_options.get_second_stage_sample_rate();\n+    second_stage_dm_rate = static_cast<uint32_t>(float_dm_rate);\n+\n+    float_dm_rate = sig_options.get_second_stage_sample_rate()/\n+          sig_options.get_third_stage_sample_rate();\n+    third_stage_dm_rate = static_cast<uint32_t>(float_dm_rate);\n+  }\n+\n+  std::cout << \"1st stage dm rate: \" << first_stage_dm_rate << std::endl\n+    << \"2nd stage dm rate: \" << second_stage_dm_rate << std::endl\n+    << \"3rd stage dm rate: \" << third_stage_dm_rate << std::endl;\n+\n+\n+  auto filter_timing_start = std::chrono::steady_clock::now();\n+\n+  Filtering filters(rx_rate,sig_options);\n+\n+  DEBUG_MSG(\"Number of 1st stage taps: \" << filters.get_num_first_stage_taps() << std::endl\n+    << \"Number of 2nd stage taps: \" << filters.get_num_second_stage_taps() << std::endl\n+    << \"Number of 3rd stage taps: \" << filters.get_num_third_stage_taps() <<std::endl\n+    << \"Number of 1st stage taps after padding: \"\n+    << filters.get_first_stage_lowpass_taps().size() << std::endl\n+    << \"Number of 2nd stage taps after padding: \"\n+    << filters.get_second_stage_lowpass_taps().size() << std::endl\n+    << \"Number of 3rd stage taps after padding: \"\n+    << filters.get_third_stage_lowpass_taps().size());\n+\n+  auto filter_timing_end = std::chrono::steady_clock::now();\n+  auto time_diff = std::chrono::duration_cast<std::chrono::microseconds>(filter_timing_end -\n+                                                                       filter_timing_start).count();\n+  DEBUG_MSG(\"Time to create 3 filters: \" << time_diff << \"us\");\n+\n+  //FIXME(Keith): fix saving filter to file\n+  filters.save_filter_to_file(filters.get_first_stage_lowpass_taps(),\"filter1coefficients.dat\");\n+  filters.save_filter_to_file(filters.get_second_stage_lowpass_taps(),\"filter2coefficients.dat\");\n+  filters.save_filter_to_file(filters.get_third_stage_lowpass_taps(),\"filter3coefficients.dat\");\n+\n+  while(1){\n+    //Receive packet from radar control\n+    zmq::message_t radctl_request;\n+    radar_control_socket.recv(&radctl_request);\n+    sigprocpacket::SigProcPacket sp_packet;\n+    std::string radctrl_str(static_cast<char*>(radctl_request.data()), radctl_request.size());\n+    if (sp_packet.ParseFromString(radctrl_str) == false){\n+      //TODO(keith): handle error\n+    }\n \n-// REVIEW #30 Is this in the right file? Should it be in dsp.cu along with get_gpu_properties?\n-// REPLY Perhaps. I like to accurately build functions in places they are being used. This method\n-// is only being used in this file which is why I didnt build an interface for it.\n-\n-// REVIEW #4 not sure where cudaDeviceProp is found...\n-// REPLY NVCC doesn't need headers to know about common CUDA constructs. You basically\n-// have to study to cuda programming/library guides to know whats available.\n-// http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#multi-device-system\n-void print_gpu_properties(std::vector<cudaDeviceProp> gpu_properties) {\n-    for(auto i : gpu_properties) { // REVIEW #28 does this need to be \"auto&\" stackoverflow says use this way \"auto\" if you aren't changing anything, but use auto& if you are.?\n-                                   // REPLY auto& is only needed if need to modify your iterator. We dont need that feature here.\n-        std::cout << \"Device name: \" << i.name << std::endl;\n-        std::cout << \"  Max grid size x: \" << i.maxGridSize[0] << std::endl;\n-        std::cout << \"  Max grid size y: \" << i.maxGridSize[1] << std::endl;\n-        std::cout << \"  Max grid size z: \" << i.maxGridSize[2] << std::endl;\n-        std::cout << \"  Max threads per block: \" << i.maxThreadsPerBlock\n-            << std::endl;\n-        std::cout << \"  Max size of block dimension x: \" << i.maxThreadsDim[0]\n-                << std::endl;\n-        std::cout << \"  Max size of block dimension y: \" << i.maxThreadsDim[1]\n-                << std::endl;\n-        std::cout << \"  Max size of block dimension z: \" << i.maxThreadsDim[2]\n-                << std::endl;\n-        std::cout << \"  Memory Clock Rate (GHz): \" << i.memoryClockRate/1e6\n-            << std::endl;\n-        std::cout << \"  Memory Bus Width (bits): \" << i.memoryBusWidth\n-            << std::endl;\n-        std::cout << \"  Peak Memory Bandwidth (GB/s): \" <<\n-           2.0*i.memoryClockRate*(i.memoryBusWidth/8)/1.0e6 << std::endl; // REVIEW #29 magic calculation with magic numbers?\n-        std::cout << \"  Max shared memory per block: \" << i.sharedMemPerBlock\n-            << std::endl;\n-    }// REVIEW other properties: asyncEngineCount, totalGlobalMem, regsPerBlock, regsPerMultiprocessor, warpSize, memPitch, clockRate, totalConstMem, major, minor, textureAlignment, deviceOverlap, multiProcessorCount, kernelExecTimeoutEnabled, integrated, canMapHostMemory, computeMode, concurrentKernels, concurrentManagedAccess, ECCEnabled, pciBusID, pciDeviceID, pciDomainID, tccDriver, globalL1CacheSupported, hostNativeAtomicSupported, isMultiGpuBoard, l2CacheSize, localL1CacheSupported, managedMemory, maxSurface[1,2,3]D, maxSurface[1,2]DLayered, maxSurfaceCubemap, maxSurfaceCubemapLayered, maxTexture[1,2]D[Layered,Linear,Mipmap], maxTexture2DGather, maxTexture3D[Alt],maxThreadsPerMultiprocessor, multiGpuBoardGroupID, pageableMemoryAccess, sharedMemPerMultiprocessor, singleToDoublePrecisionPerfRatio, streamPrioritiesSupported, surfaceAlignment, texturePitchAlignment, unifiedAddressing,\n-}   //REPLY I feel like these properties are somewhat low level and dont offer much to be listed at this point.\n-\n-uint32_t calculate_num_filter_taps(float rate, float transition_width) { // REVIEW #26 transition_width and transition_band are both used?\n-    auto k = 3; //from formula 7-6 of Lyons text REVIEW #1 and #7 add some explanation for design of choice of k=3\n-                // REPLY this feels well suited for our written documentation.\n-    auto num_taps = k * (rate/transition_width); //REVIEW #5 provide units for rate & transition width\n-                                                 //REPLY This can be added to the docstring\n-\n-    return num_taps; // REVIEW #33\n-    //REVIEW #28 this function is returning a uint32; will this always round down? comment/document this\n-}   //REPLY conversion from float to int never rounds, it always truncates. I'm unsure this needs to\n-    //commented unless we need to choose and describe a particular choice of floor, ceil, or round\n-\n-std::vector<std::complex<float>> create_filter(uint32_t num_taps, float filter_cutoff,\n-                                                float transition_width, // REVIEW #31 this line is over 80 characters, need to be consistent. #31\n-                                                                        //REPLY I've been trying to stick to 100 lines. 80 is tough with all the templating\n-                                    float rate) { // REVIEW #5 filter_cutoff, transition_width, rate\n-                                                  //REPLY docstring\n-    // REVIEW #3 explain algorithm including weight\n-    // REPLY to be done in written documentation?\n-    std::vector<double> desired_band_gain = {1.0,0.0};\n-    std::vector<double> weight = {1.0,1.0};\n-\n-    auto filter_bands = create_normalized_lowpass_filter_bands(filter_cutoff,transition_width,\n-                            rate);\n-\n-    /*remez returns number of taps + 1. Should we use num_taps + 1\n-      or should we pass num_taps - 1 to remez?\n-    */ //REVIEW #6 make this a TODO - does this depend on num_taps being odd or even?\n-    //TODO(Keith): Investigate number of taps behaviour\n-    std::vector<double> filter_taps(num_taps + 1,0.0);\n-    auto converges = remez(filter_taps.data(), num_taps + 1, (filter_bands.size()/2), // REVIEW #32 declare and initialize number of bands for better readability\n-                                                                                      //REPLY I am unsure what you mean as filterbands is both declared and initialized. Do you just not want the use of auto here?\n-        filter_bands.data(),desired_band_gain.data(),weight.data(),BANDPASS,GRIDDENSITY); // REVIEW #15 are we passing the right values, should error check before passing these params\n-                                                                                          //REPLY We should maybe error check the function inputs. we should have a strong error case in the failure to converge, or verify the filters saved to file.\n-    if (converges < 0){ // REVIEW #10 remez returns True or False is this check correct?\n-        std::cerr << \"Filter failed to converge with cutoff of \" << filter_cutoff // REVIEW #5 & #34 print units\n-            << \", transition width \" << transition_width << \", and rate \"\n-            << rate << std::endl;\n-        //TODO(keith): throw error\n+    //Then receive packet from driver\n+    zmq::message_t driver_request;\n+    driver_socket.recv(&driver_request);\n+    rxsamplesmetadata::RxSamplesMetadata rx_metadata;\n+    std::string driver_str(static_cast<char*>(driver_request.data()), driver_request.size());\n+    if (rx_metadata.ParseFromString(driver_str) == false) {\n+      //TODO(keith): handle error\n     }\n \n-    std::vector<std::complex<float>> complex_taps;\n-    for (auto &i : filter_taps) {\n-        auto complex_tap = std::complex<float>(i,0.0);\n-        complex_taps.push_back(complex_tap); // REVIEW #0 does this work?\n-                                             // REPLY This is just converting real numbers to complex numbers with 0 in the imag part.\n-                                              //  I dont think this needs to be here anymore. It can be done during the mixing.\n+    DEBUG_MSG(\"Got driver request\");\n+\n+    //Verify driver and radar control packets align\n+    if (sp_packet.sequence_num() != rx_metadata.sequence_num()) {\n+      //TODO(keith): handle error\n+      DEBUG_MSG(\"SEQUENCE NUMBER mismatch radar_control: \" << sp_packet.sequence_num()\n+        << \" usrp_driver: \" << rx_metadata.sequence_num());\n     }\n \n-    //TODO(keith): either pad to pwr of 2 or make pwr of 2 filter len\n-    //Pads to at least len 32 or next pwr of 2 to stop seg fault for now.\n-\n-    //Quick and small lambda to get the next power of 2. Returns the same\n-    //number if already power of two.\n-    auto next_pwr2 = [](uint32_t n) -> uint32_t {\n-        n--;\n-        n |= n >> 1;\n-        n |= n >> 2;\n-        n |= n >> 4;\n-        n |= n >> 8;\n-        n |= n >> 16;\n-        n++;\n-        return n;\n-\n-    };\n-\n-    uint32_t size_difference = 0;\n-    if (complex_taps.size() < 32) {\n-        size_difference = 32 - complex_taps.size();\n+    //Parse needed packet values now\n+    if (sp_packet.rxchannel_size() == 0) {\n+      //TODO(keith): handle error\n     }\n-    else {\n-        size_difference = next_pwr2(complex_taps.size()) - complex_taps.size();\n+    std::vector<double> rx_freqs;\n+    for(int i=0; i<sp_packet.rxchannel_size(); i++) {\n+      rx_freqs.push_back(sp_packet.rxchannel(i).rxfreq());\n     }\n-    //pad the filter with the result.\n-    for (uint32_t i=0 ; i<size_difference; i++) {\n-        complex_taps.push_back(std::complex<float>(0.0,0.0));\n+\n+    auto mix_timing_start = std::chrono::steady_clock::now();\n+\n+    filters.mix_first_stage_to_bandpass(rx_freqs,rx_rate);","path":"rx_signal_processing/rx_dsp_chain.cu","position":265,"original_position":265,"commit_id":"64f0be108618dbf441e73eee4ec81653e5b68b46","original_commit_id":"64f0be108618dbf441e73eee4ec81653e5b68b46","user":{"login":"kevinkrieger","id":5935875,"avatar_url":"https://avatars2.githubusercontent.com/u/5935875?v=3","gravatar_id":"","url":"https://api.github.com/users/kevinkrieger","html_url":"https://github.com/kevinkrieger","followers_url":"https://api.github.com/users/kevinkrieger/followers","following_url":"https://api.github.com/users/kevinkrieger/following{/other_user}","gists_url":"https://api.github.com/users/kevinkrieger/gists{/gist_id}","starred_url":"https://api.github.com/users/kevinkrieger/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kevinkrieger/subscriptions","organizations_url":"https://api.github.com/users/kevinkrieger/orgs","repos_url":"https://api.github.com/users/kevinkrieger/repos","events_url":"https://api.github.com/users/kevinkrieger/events{/privacy}","received_events_url":"https://api.github.com/users/kevinkrieger/received_events","type":"User","site_admin":false},"body":"Hmm... you're continually adding to the vector with push_back (in mix_first_stage_to_bandpass) but it doesn't look like you ever clear it?","created_at":"2017-06-20T21:06:58Z","updated_at":"2017-06-20T21:12:27Z","html_url":"https://github.com/SuperDARNCanada/borealis/pull/1#discussion_r123095868","pull_request_url":"https://api.github.com/repos/SuperDARNCanada/borealis/pulls/1","_links":{"self":{"href":"https://api.github.com/repos/SuperDARNCanada/borealis/pulls/comments/123095868"},"html":{"href":"https://github.com/SuperDARNCanada/borealis/pull/1#discussion_r123095868"},"pull_request":{"href":"https://api.github.com/repos/SuperDARNCanada/borealis/pulls/1"}}},"pull_request":{"url":"https://api.github.com/repos/SuperDARNCanada/borealis/pulls/1","id":114028356,"html_url":"https://github.com/SuperDARNCanada/borealis/pull/1","diff_url":"https://github.com/SuperDARNCanada/borealis/pull/1.diff","patch_url":"https://github.com/SuperDARNCanada/borealis/pull/1.patch","issue_url":"https://api.github.com/repos/SuperDARNCanada/borealis/issues/1","number":1,"state":"open","locked":false,"title":"Dsp improvements and addressing code review","user":{"login":"kkotyk","id":7105882,"avatar_url":"https://avatars3.githubusercontent.com/u/7105882?v=3","gravatar_id":"","url":"https://api.github.com/users/kkotyk","html_url":"https://github.com/kkotyk","followers_url":"https://api.github.com/users/kkotyk/followers","following_url":"https://api.github.com/users/kkotyk/following{/other_user}","gists_url":"https://api.github.com/users/kkotyk/gists{/gist_id}","starred_url":"https://api.github.com/users/kkotyk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kkotyk/subscriptions","organizations_url":"https://api.github.com/users/kkotyk/orgs","repos_url":"https://api.github.com/users/kkotyk/repos","events_url":"https://api.github.com/users/kkotyk/events{/privacy}","received_events_url":"https://api.github.com/users/kkotyk/received_events","type":"User","site_admin":false},"body":"","created_at":"2017-04-03T21:36:47Z","updated_at":"2017-06-20T21:12:27Z","closed_at":null,"merged_at":null,"merge_commit_sha":"42d9d46b8c228fad088e49b7e1efa4195235633f","assignee":{"login":"kkotyk","id":7105882,"avatar_url":"https://avatars3.githubusercontent.com/u/7105882?v=3","gravatar_id":"","url":"https://api.github.com/users/kkotyk","html_url":"https://github.com/kkotyk","followers_url":"https://api.github.com/users/kkotyk/followers","following_url":"https://api.github.com/users/kkotyk/following{/other_user}","gists_url":"https://api.github.com/users/kkotyk/gists{/gist_id}","starred_url":"https://api.github.com/users/kkotyk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kkotyk/subscriptions","organizations_url":"https://api.github.com/users/kkotyk/orgs","repos_url":"https://api.github.com/users/kkotyk/repos","events_url":"https://api.github.com/users/kkotyk/events{/privacy}","received_events_url":"https://api.github.com/users/kkotyk/received_events","type":"User","site_admin":false},"assignees":[{"login":"kkotyk","id":7105882,"avatar_url":"https://avatars3.githubusercontent.com/u/7105882?v=3","gravatar_id":"","url":"https://api.github.com/users/kkotyk","html_url":"https://github.com/kkotyk","followers_url":"https://api.github.com/users/kkotyk/followers","following_url":"https://api.github.com/users/kkotyk/following{/other_user}","gists_url":"https://api.github.com/users/kkotyk/gists{/gist_id}","starred_url":"https://api.github.com/users/kkotyk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kkotyk/subscriptions","organizations_url":"https://api.github.com/users/kkotyk/orgs","repos_url":"https://api.github.com/users/kkotyk/repos","events_url":"https://api.github.com/users/kkotyk/events{/privacy}","received_events_url":"https://api.github.com/users/kkotyk/received_events","type":"User","site_admin":false}],"requested_reviewers":[{"login":"mardet987","id":19413948,"avatar_url":"https://avatars3.githubusercontent.com/u/19413948?v=3","gravatar_id":"","url":"https://api.github.com/users/mardet987","html_url":"https://github.com/mardet987","followers_url":"https://api.github.com/users/mardet987/followers","following_url":"https://api.github.com/users/mardet987/following{/other_user}","gists_url":"https://api.github.com/users/mardet987/gists{/gist_id}","starred_url":"https://api.github.com/users/mardet987/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mardet987/subscriptions","organizations_url":"https://api.github.com/users/mardet987/orgs","repos_url":"https://api.github.com/users/mardet987/repos","events_url":"https://api.github.com/users/mardet987/events{/privacy}","received_events_url":"https://api.github.com/users/mardet987/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/SuperDARNCanada/borealis/pulls/1/commits","review_comments_url":"https://api.github.com/repos/SuperDARNCanada/borealis/pulls/1/comments","review_comment_url":"https://api.github.com/repos/SuperDARNCanada/borealis/pulls/comments{/number}","comments_url":"https://api.github.com/repos/SuperDARNCanada/borealis/issues/1/comments","statuses_url":"https://api.github.com/repos/SuperDARNCanada/borealis/statuses/64f0be108618dbf441e73eee4ec81653e5b68b46","head":{"label":"SuperDARNCanada:dspimprovements","ref":"dspimprovements","sha":"64f0be108618dbf441e73eee4ec81653e5b68b46","user":{"login":"SuperDARNCanada","id":19173794,"avatar_url":"https://avatars3.githubusercontent.com/u/19173794?v=3","gravatar_id":"","url":"https://api.github.com/users/SuperDARNCanada","html_url":"https://github.com/SuperDARNCanada","followers_url":"https://api.github.com/users/SuperDARNCanada/followers","following_url":"https://api.github.com/users/SuperDARNCanada/following{/other_user}","gists_url":"https://api.github.com/users/SuperDARNCanada/gists{/gist_id}","starred_url":"https://api.github.com/users/SuperDARNCanada/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SuperDARNCanada/subscriptions","organizations_url":"https://api.github.com/users/SuperDARNCanada/orgs","repos_url":"https://api.github.com/users/SuperDARNCanada/repos","events_url":"https://api.github.com/users/SuperDARNCanada/events{/privacy}","received_events_url":"https://api.github.com/users/SuperDARNCanada/received_events","type":"Organization","site_admin":false},"repo":{"id":68139909,"name":"borealis","full_name":"SuperDARNCanada/borealis","owner":{"login":"SuperDARNCanada","id":19173794,"avatar_url":"https://avatars3.githubusercontent.com/u/19173794?v=3","gravatar_id":"","url":"https://api.github.com/users/SuperDARNCanada","html_url":"https://github.com/SuperDARNCanada","followers_url":"https://api.github.com/users/SuperDARNCanada/followers","following_url":"https://api.github.com/users/SuperDARNCanada/following{/other_user}","gists_url":"https://api.github.com/users/SuperDARNCanada/gists{/gist_id}","starred_url":"https://api.github.com/users/SuperDARNCanada/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SuperDARNCanada/subscriptions","organizations_url":"https://api.github.com/users/SuperDARNCanada/orgs","repos_url":"https://api.github.com/users/SuperDARNCanada/repos","events_url":"https://api.github.com/users/SuperDARNCanada/events{/privacy}","received_events_url":"https://api.github.com/users/SuperDARNCanada/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/SuperDARNCanada/borealis","description":"A control system for USRP based digital radars","fork":false,"url":"https://api.github.com/repos/SuperDARNCanada/borealis","forks_url":"https://api.github.com/repos/SuperDARNCanada/borealis/forks","keys_url":"https://api.github.com/repos/SuperDARNCanada/borealis/keys{/key_id}","collaborators_url":"https://api.github.com/repos/SuperDARNCanada/borealis/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/SuperDARNCanada/borealis/teams","hooks_url":"https://api.github.com/repos/SuperDARNCanada/borealis/hooks","issue_events_url":"https://api.github.com/repos/SuperDARNCanada/borealis/issues/events{/number}","events_url":"https://api.github.com/repos/SuperDARNCanada/borealis/events","assignees_url":"https://api.github.com/repos/SuperDARNCanada/borealis/assignees{/user}","branches_url":"https://api.github.com/repos/SuperDARNCanada/borealis/branches{/branch}","tags_url":"https://api.github.com/repos/SuperDARNCanada/borealis/tags","blobs_url":"https://api.github.com/repos/SuperDARNCanada/borealis/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/SuperDARNCanada/borealis/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/SuperDARNCanada/borealis/git/refs{/sha}","trees_url":"https://api.github.com/repos/SuperDARNCanada/borealis/git/trees{/sha}","statuses_url":"https://api.github.com/repos/SuperDARNCanada/borealis/statuses/{sha}","languages_url":"https://api.github.com/repos/SuperDARNCanada/borealis/languages","stargazers_url":"https://api.github.com/repos/SuperDARNCanada/borealis/stargazers","contributors_url":"https://api.github.com/repos/SuperDARNCanada/borealis/contributors","subscribers_url":"https://api.github.com/repos/SuperDARNCanada/borealis/subscribers","subscription_url":"https://api.github.com/repos/SuperDARNCanada/borealis/subscription","commits_url":"https://api.github.com/repos/SuperDARNCanada/borealis/commits{/sha}","git_commits_url":"https://api.github.com/repos/SuperDARNCanada/borealis/git/commits{/sha}","comments_url":"https://api.github.com/repos/SuperDARNCanada/borealis/comments{/number}","issue_comment_url":"https://api.github.com/repos/SuperDARNCanada/borealis/issues/comments{/number}","contents_url":"https://api.github.com/repos/SuperDARNCanada/borealis/contents/{+path}","compare_url":"https://api.github.com/repos/SuperDARNCanada/borealis/compare/{base}...{head}","merges_url":"https://api.github.com/repos/SuperDARNCanada/borealis/merges","archive_url":"https://api.github.com/repos/SuperDARNCanada/borealis/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/SuperDARNCanada/borealis/downloads","issues_url":"https://api.github.com/repos/SuperDARNCanada/borealis/issues{/number}","pulls_url":"https://api.github.com/repos/SuperDARNCanada/borealis/pulls{/number}","milestones_url":"https://api.github.com/repos/SuperDARNCanada/borealis/milestones{/number}","notifications_url":"https://api.github.com/repos/SuperDARNCanada/borealis/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/SuperDARNCanada/borealis/labels{/name}","releases_url":"https://api.github.com/repos/SuperDARNCanada/borealis/releases{/id}","deployments_url":"https://api.github.com/repos/SuperDARNCanada/borealis/deployments","created_at":"2016-09-13T19:22:53Z","updated_at":"2017-05-12T17:54:51Z","pushed_at":"2017-06-19T20:36:05Z","git_url":"git://github.com/SuperDARNCanada/borealis.git","ssh_url":"git@github.com:SuperDARNCanada/borealis.git","clone_url":"https://github.com/SuperDARNCanada/borealis.git","svn_url":"https://github.com/SuperDARNCanada/borealis","homepage":null,"size":54693,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"SuperDARNCanada:master","ref":"master","sha":"8144065de6ea2364125c94c1b23186b160c5f746","user":{"login":"SuperDARNCanada","id":19173794,"avatar_url":"https://avatars3.githubusercontent.com/u/19173794?v=3","gravatar_id":"","url":"https://api.github.com/users/SuperDARNCanada","html_url":"https://github.com/SuperDARNCanada","followers_url":"https://api.github.com/users/SuperDARNCanada/followers","following_url":"https://api.github.com/users/SuperDARNCanada/following{/other_user}","gists_url":"https://api.github.com/users/SuperDARNCanada/gists{/gist_id}","starred_url":"https://api.github.com/users/SuperDARNCanada/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SuperDARNCanada/subscriptions","organizations_url":"https://api.github.com/users/SuperDARNCanada/orgs","repos_url":"https://api.github.com/users/SuperDARNCanada/repos","events_url":"https://api.github.com/users/SuperDARNCanada/events{/privacy}","received_events_url":"https://api.github.com/users/SuperDARNCanada/received_events","type":"Organization","site_admin":false},"repo":{"id":68139909,"name":"borealis","full_name":"SuperDARNCanada/borealis","owner":{"login":"SuperDARNCanada","id":19173794,"avatar_url":"https://avatars3.githubusercontent.com/u/19173794?v=3","gravatar_id":"","url":"https://api.github.com/users/SuperDARNCanada","html_url":"https://github.com/SuperDARNCanada","followers_url":"https://api.github.com/users/SuperDARNCanada/followers","following_url":"https://api.github.com/users/SuperDARNCanada/following{/other_user}","gists_url":"https://api.github.com/users/SuperDARNCanada/gists{/gist_id}","starred_url":"https://api.github.com/users/SuperDARNCanada/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SuperDARNCanada/subscriptions","organizations_url":"https://api.github.com/users/SuperDARNCanada/orgs","repos_url":"https://api.github.com/users/SuperDARNCanada/repos","events_url":"https://api.github.com/users/SuperDARNCanada/events{/privacy}","received_events_url":"https://api.github.com/users/SuperDARNCanada/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/SuperDARNCanada/borealis","description":"A control system for USRP based digital radars","fork":false,"url":"https://api.github.com/repos/SuperDARNCanada/borealis","forks_url":"https://api.github.com/repos/SuperDARNCanada/borealis/forks","keys_url":"https://api.github.com/repos/SuperDARNCanada/borealis/keys{/key_id}","collaborators_url":"https://api.github.com/repos/SuperDARNCanada/borealis/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/SuperDARNCanada/borealis/teams","hooks_url":"https://api.github.com/repos/SuperDARNCanada/borealis/hooks","issue_events_url":"https://api.github.com/repos/SuperDARNCanada/borealis/issues/events{/number}","events_url":"https://api.github.com/repos/SuperDARNCanada/borealis/events","assignees_url":"https://api.github.com/repos/SuperDARNCanada/borealis/assignees{/user}","branches_url":"https://api.github.com/repos/SuperDARNCanada/borealis/branches{/branch}","tags_url":"https://api.github.com/repos/SuperDARNCanada/borealis/tags","blobs_url":"https://api.github.com/repos/SuperDARNCanada/borealis/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/SuperDARNCanada/borealis/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/SuperDARNCanada/borealis/git/refs{/sha}","trees_url":"https://api.github.com/repos/SuperDARNCanada/borealis/git/trees{/sha}","statuses_url":"https://api.github.com/repos/SuperDARNCanada/borealis/statuses/{sha}","languages_url":"https://api.github.com/repos/SuperDARNCanada/borealis/languages","stargazers_url":"https://api.github.com/repos/SuperDARNCanada/borealis/stargazers","contributors_url":"https://api.github.com/repos/SuperDARNCanada/borealis/contributors","subscribers_url":"https://api.github.com/repos/SuperDARNCanada/borealis/subscribers","subscription_url":"https://api.github.com/repos/SuperDARNCanada/borealis/subscription","commits_url":"https://api.github.com/repos/SuperDARNCanada/borealis/commits{/sha}","git_commits_url":"https://api.github.com/repos/SuperDARNCanada/borealis/git/commits{/sha}","comments_url":"https://api.github.com/repos/SuperDARNCanada/borealis/comments{/number}","issue_comment_url":"https://api.github.com/repos/SuperDARNCanada/borealis/issues/comments{/number}","contents_url":"https://api.github.com/repos/SuperDARNCanada/borealis/contents/{+path}","compare_url":"https://api.github.com/repos/SuperDARNCanada/borealis/compare/{base}...{head}","merges_url":"https://api.github.com/repos/SuperDARNCanada/borealis/merges","archive_url":"https://api.github.com/repos/SuperDARNCanada/borealis/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/SuperDARNCanada/borealis/downloads","issues_url":"https://api.github.com/repos/SuperDARNCanada/borealis/issues{/number}","pulls_url":"https://api.github.com/repos/SuperDARNCanada/borealis/pulls{/number}","milestones_url":"https://api.github.com/repos/SuperDARNCanada/borealis/milestones{/number}","notifications_url":"https://api.github.com/repos/SuperDARNCanada/borealis/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/SuperDARNCanada/borealis/labels{/name}","releases_url":"https://api.github.com/repos/SuperDARNCanada/borealis/releases{/id}","deployments_url":"https://api.github.com/repos/SuperDARNCanada/borealis/deployments","created_at":"2016-09-13T19:22:53Z","updated_at":"2017-05-12T17:54:51Z","pushed_at":"2017-06-19T20:36:05Z","git_url":"git://github.com/SuperDARNCanada/borealis.git","ssh_url":"git@github.com:SuperDARNCanada/borealis.git","clone_url":"https://github.com/SuperDARNCanada/borealis.git","svn_url":"https://github.com/SuperDARNCanada/borealis","homepage":null,"size":54693,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/SuperDARNCanada/borealis/pulls/1"},"html":{"href":"https://github.com/SuperDARNCanada/borealis/pull/1"},"issue":{"href":"https://api.github.com/repos/SuperDARNCanada/borealis/issues/1"},"comments":{"href":"https://api.github.com/repos/SuperDARNCanada/borealis/issues/1/comments"},"review_comments":{"href":"https://api.github.com/repos/SuperDARNCanada/borealis/pulls/1/comments"},"review_comment":{"href":"https://api.github.com/repos/SuperDARNCanada/borealis/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/SuperDARNCanada/borealis/pulls/1/commits"},"statuses":{"href":"https://api.github.com/repos/SuperDARNCanada/borealis/statuses/64f0be108618dbf441e73eee4ec81653e5b68b46"}}}}
{"actor":{"display_login":"kevinkrieger"}}