{"action":"created","comment":{"url":"https://api.github.com/repos/BallAerospace/COSMOS/pulls/comments/94506551","pull_request_review_id":15033535,"id":94506551,"diff_hunk":"@@ -315,640 +385,398 @@ def initialize_menus(no_tables = false)\n     end\n \n     def initialize_central_widget\n-      # Create the central widget\n-      @central_widget = Qt::Widget.new\n-      setCentralWidget(@central_widget)\n-\n-      # Create the top level vertical layout\n-      @top_layout = Qt::VBoxLayout.new(@central_widget)\n+      central_widget = Qt::Widget.new\n+      setCentralWidget(central_widget)\n+      top_layout = Qt::VBoxLayout.new(central_widget)\n \n       # Create the information pane with the filenames\n-      @filename_layout = Qt::FormLayout.new\n+      filename_layout = Qt::FormLayout.new\n       @table_def_label = Qt::Label.new(\"\")\n-      @filename_layout.addRow(tr(\"Definition File:\"), @table_def_label)\n+      filename_layout.addRow(tr(\"Definition File:\"), @table_def_label)\n       @table_bin_label = Qt::Label.new(\"\")\n-      @filename_layout.addRow(tr(\"Binary File:\"), @table_bin_label)\n-      @top_layout.addLayout(@filename_layout)\n+      filename_layout.addRow(tr(\"Binary File:\"), @table_bin_label)\n+      top_layout.addLayout(filename_layout)\n \n       # Separator before editor\n-      @sep1 = Qt::Frame.new(@central_widget)\n-      @sep1.setFrameStyle(Qt::Frame::HLine | Qt::Frame::Sunken)\n-      @top_layout.addWidget(@sep1)\n+      sep1 = Qt::Frame.new(central_widget)\n+      sep1.setFrameStyle(Qt::Frame::HLine | Qt::Frame::Sunken)\n+      top_layout.addWidget(sep1)\n \n       @tabbook = Qt::TabWidget.new\n-      connect(@tabbook, SIGNAL('currentChanged(int)'), self, SLOT('handle_tab_change(int)'))\n-      @top_layout.addWidget(@tabbook)\n+      top_layout.addWidget(@tabbook)\n \n       @check_icons = []\n       @check_icons << Cosmos.get_icon(\"CheckBoxEmpty.gif\")\n       @check_icons << Cosmos.get_icon(\"CheckBoxCheck.gif\")\n     end\n \n-    # Menu option to check every table tab's values against their allowable ranges\n-    def file_check\n-      begin\n-        result = \"\"\n-        @ordered_gui_table_names.each do |name|\n-          save_result = save_gui_data(name)\n-          check_result = @core.table_check(name)\n-          if not save_result.nil? or not check_result.empty?\n-            result << \"Error(s) in #{name}:\\n\" << save_result.to_s << check_result.to_s\n+    # Menu option to create a new table binary file based on a table definition file.\n+    #\n+    # @param def_path [String] Path to a directory containing definition files\n+    def file_new(def_path)\n+      return if abort_on_modified()\n+\n+      filenames = Qt::FileDialog.getOpenFileNames(self, \"Open Binary Definition Text File(s)\",\n+                                                  def_path, \"Config File (*.txt)\\nAll Files (*)\")\n+      return if filenames.length == 0 # User cancelled dialog\n+\n+      bin_path = bin_path_from_def_path(File.dirname(filenames[0]))\n+      output_path = Qt::FileDialog.getExistingDirectory(self, \"Select Output Directory\", bin_path)\n+      return unless output_path # User cancelled dialog\n+\n+      return if abort_on_check_for_existing(filenames, output_path)\n+\n+      success = false\n+      bin_files = []\n+      ProgressDialog.execute(self, 'Create New Files', 500, 50, true, false, false, false, false) do |dialog|\n+        begin\n+          filenames.each do |filename|\n+            bin_files << @core.file_new(filename, output_path) do |progress|\n+              dialog.set_overall_progress(progress)\n+            end\n           end\n+          success = true\n+          dialog.close_done\n+        rescue => err\n+          Qt.execute_in_main_thread(true) {|| ExceptionDialog.new(self, err, \"File New Errors\", false)}\n+          dialog.close_done\n         end\n-        if result.empty?\n-          result = \"All parameters are within their constraints.\"\n-        end\n-        Qt::MessageBox.information(self, \"File Check\", result)\n-      rescue => err\n-        ExceptionDialog.new(self, err, \"File Check Errors\", false)\n       end\n+      if success\n+        file_close()\n+        file_open(bin_files[0], filenames[0])\n+      end\n+    rescue TableManagerCore::CoreError => err\n+      Qt::MessageBox.warning(self, \"File New Errors\", err.message)\n+    rescue => err\n+      ExceptionDialog.new(self, err, \"File New Errors\", false)\n     end\n \n-    # Menu option to check the table values against their allowable ranges\n-    def table_check\n-      begin\n-        save_result = save_gui_data(@currently_displayed_table_name)\n-        check_result = @core.table_check(@currently_displayed_table_name)\n-        if save_result.nil? and check_result.empty?\n-          result = \"All parameters are within their constraints.\"\n-        elsif save_result.nil?\n-          result = check_result\n-        elsif check_result.nil?\n-          result = save_result\n-        else\n-          result = save_result << check_result\n-        end\n-\n-        Qt::MessageBox.information(self, \"Table Check\", result)\n-      rescue => err\n-        ExceptionDialog.new(self, err, \"Table Check Errors\", false)\n+    # Menu option that opens a binary file (and it's associated definition\n+    # file) for display in the GUI.\n+    #\n+    # @param bin_path [String] Path to the binary file or a directory\n+    #   containing binary files\n+    # @param def_path [String] Path to the definition file. If nil, the\n+    #   definition file will be looked up automatically.\n+    # @param user_select_definition [Boolean] If true, the user will be\n+    #   required to select the definition file. It will not be automatically\n+    #   looked up.\n+    def file_open(bin_path, def_path = nil, user_select_definition = false)\n+      return if abort_on_modified()\n+\n+      if File.directory?(bin_path)\n+        bin_path = Qt::FileDialog.getOpenFileName(self, \"Open Binary\", bin_path,\n+                                                  \"Binary File (*.bin *.dat);;All Files (*)\")\n+        return unless bin_path\n       end\n-    end\n \n-    # Menu option to set all the table items to their default values\n-    def table_default\n-      begin\n-        @core.table_default(@currently_displayed_table_name)\n-      rescue => err\n-        ExceptionDialog.new(self, err, \"Table Default Errors\", false)\n+      unless def_path\n+        def_path = def_path_from_bin_path(bin_path)\n+        def_path = get_best_def_path(def_path, bin_path) unless user_select_definition\n+      end\n+      if !def_path || !File.file?(def_path)\n+        def_path = Qt::FileDialog.getOpenFileName(self, \"Open Definition File\", def_path,\n+                                                  \"Definition File (*.txt);;All Files (*)\")\n       end\n+      return unless def_path\n+\n+      Qt::Application.setOverrideCursor(Qt::Cursor.new(Qt::WaitCursor))\n       begin\n-        display_gui_data(@currently_displayed_table_name)\n-      rescue => err\n-        ExceptionDialog.new(self, err, \"Table Default Errors\", false)\n+        @core.file_open(bin_path, def_path)\n+      rescue TableManagerCore::MismatchError => err\n+        # Mismatch errors are recoverable so just warn the user\n+        Qt::MessageBox.information(self, \"Table Open Error\", err.message)\n       end\n+      @def_path = File.dirname(def_path)\n+      @bin_path = File.dirname(bin_path)\n+      display_all_gui_data()\n+      @table_bin_label.text = bin_path\n+      @table_def_label.text = def_path\n+      Qt::Application.restoreOverrideCursor()\n+    rescue TableManagerCore::CoreError => err\n+      Qt::Application.restoreOverrideCursor()\n+      Qt::MessageBox.warning(self, \"File Open Errors\", err.message)\n+    rescue => err\n+      Qt::Application.restoreOverrideCursor()\n+      ExceptionDialog.new(self, err, \"File Open Errors\", false)\n     end\n \n-    # Menu option to create a text file report of all the table data\n-    def file_report\n-      begin\n-        @ordered_gui_table_names.each do |name|\n-          save_gui_data(name)\n-        end\n+    # Menu option to require the user to specify both the binary and the\n+    # definition file to parse it\n+    def file_open_both\n+      file_open(@bin_path, nil, true)\n+    end\n \n-        @core.file_report\n-        statusBar.showMessage(tr(\"File Report Created Successfully\"))\n-      rescue => err\n-        ExceptionDialog.new(self, err, \"File Report Errors\", false)\n-      end\n+    # Menu option to close the open table\n+    def file_close\n+      return if abort_on_modified()\n+      @core.reset\n+      @table_bin_label.text = ''\n+      @table_def_label.text = ''\n+      reset_gui()\n+    rescue TableManagerCore::CoreError => err\n+      Qt::MessageBox.warning(self, \"File Close Errors\", err.message)\n+    rescue => err\n+      ExceptionDialog.new(self, err, \"File Close Errors\", false)\n     end\n \n-    # Saves the binary data to a file.\n+    # Menu option to save the binary data to a file.\n     # It first commits the GUI data to the internal data structures and checks\n     # for errors. If none are found, it saves the data to the table binary file.\n     def file_save(save_as = false)\n-      begin\n-        @ordered_gui_table_names.each do |name|\n-          save_gui_data(name)\n-        end\n-\n-        filename = @table_bin_label.text\n-        if save_as\n-          filename = Qt::FileDialog.getSaveFileName(self,\n-                                                  \"File Save\",\n-                                                  @table_bin_label.text,\n+      return unless file_check(false)\n+      filename = @table_bin_label.text\n+      if save_as\n+        filename = Qt::FileDialog.getSaveFileName(self, \"File Save\", @table_bin_label.text,\n                                                   \"Binary File (*.bin *.dat);;All Files (*)\")\n-\n-          # Check for an empty string which indicates the user clicked \"Cancel\" on the dialog\n-          return if filename.to_s.empty?\n-          @table_bin_label.text = filename\n-        end\n-\n-        begin\n-          @core.file_save(filename)\n-        rescue => error\n-          Qt::MessageBox.information(self, \"File Save Errors\", error.message)\n-          return\n-        end\n-\n-        @ordered_gui_table_names.each do |name|\n-          display_gui_data(name)\n-        end\n-\n-        statusBar.showMessage(tr(\"File Saved Successfully\"))\n-      rescue => err\n-        ExceptionDialog.new(self, err, \"File Save Errors\", false)\n+        return unless filename\n+        @table_bin_label.text = filename\n       end\n-    end\n \n-    # Menu option to display a dialog containing a hex dump of all table values\n-    def display_hex(type)\n-      begin\n-        dialog = TextDialog.new(self)\n-        if type == :file\n-          str = @core.file_hex()\n-          title = File.basename(@table_bin_label.text)\n-        else\n-          str = @core.table_hex(@currently_displayed_table_name)\n-          title = @currently_displayed_table_name\n-        end\n-        dialog.set_title_and_text(\"#{title} Hex Dump\", str)\n-        dialog.set_size(650, 400)\n-        dialog.exec\n-        dialog.dispose\n-      rescue => err\n-        ExceptionDialog.new(self, err, \"Display Hex Errors\", false)\n-      end\n-    end\n-\n-    # Menu option to save the currently displayed table to an existing table binary file\n-    # containing that table.\n-    def table_commit\n-      begin\n-        save_gui_data(@currently_displayed_table_name)\n+      @core.file_save(filename)\n+      @bin_path = File.dirname(filename)\n \n-        # Ask for the file to save the current table to\n-        bin_file, def_file = get_binary_and_definition_file_paths()\n-        if bin_file.nil? or def_file.nil? then return 1 end\n-\n-        @core.table_commit(@currently_displayed_table_name, bin_file, def_file)\n-\n-        # Update the labels\n-        @table_bin_label.text = bin_file\n-        @table_def_label.text = def_file\n-\n-        # Display the new table\n-        delete_tabs()\n-        @core.table_def.get_all_tables.each do |table|\n-          create_table_tab(table)\n-          display_gui_data(table.name)\n-        end\n-        @currently_displayed_table_name = @ordered_gui_table_names[0]\n-        @currently_displayed_table_name ||= '' # ensure it's not nil\n-      rescue => err\n-        ExceptionDialog.new(self, err, \"Table Commit Errors\", false)\n-      end\n-    end\n-\n-    # Menu option to save the currently displayed table as a stand alone binary file\n-    def table_save\n-      begin\n-        save_gui_data(@currently_displayed_table_name)\n-\n-        filename = Qt::FileDialog.getSaveFileName(self,\n-                                                \"File Save\",\n-                                                File.join(@bin_path, \"#{@currently_displayed_table_name.gsub(/\\s/,'')}.dat\"),\n-                                                \"Binary File (*.bin *.dat);;All Files (*)\")\n-        # Check for a 0 length string which indicates the user clicked \"Cancel\" on the dialog\n-        if filename.to_s.strip.length != 0\n-          @bin_path = File.dirname(filename)\n-          @core.table_save(@currently_displayed_table_name, filename)\n-        end\n-      rescue => err\n-        ExceptionDialog.new(self, err, \"Table Save Errors\", false)\n-      end\n+      display_all_gui_data()\n+      @table_bin_label.text = filename\n+      statusBar.showMessage(tr(\"File Saved Successfully\"))\n+    rescue TableManagerCore::CoreError, SaveError => err\n+      Qt::MessageBox.warning(self, \"File Save Errors\", err.message)\n+    rescue => err\n+      ExceptionDialog.new(self, err, \"File Save Errors\", false)\n     end\n \n-    # Menu option to update the definition file defaults with the currently\n-    # displayed table values\n-    def table_update\n-      begin\n-        save_gui_data(@currently_displayed_table_name)\n-\n-        result = Qt::MessageBox.question(self, \"Update Table Definition File\",\n-          \"Are you sure you want to update the table definition file. This action is irreversable!\",\n-          Qt::MessageBox::Yes | Qt::MessageBox::No, Qt::MessageBox::Yes)\n-        if result == Qt::MessageBox::Yes\n-          @core.table_update_def(@currently_displayed_table_name)\n-        end # end if result == MBOX_CLICKED_YES\n-      rescue => err\n-        ExceptionDialog.new(self, err, \"Table Update Errors\", false)\n-      end\n+    # Menu option to check every table's values against their allowable ranges\n+    #\n+    # @param success_dialog [Boolean] Whether to display a dialog indicating\n+    #   success. If false simply return true.\n+    # @return [Boolean] Whether the file check was successful\n+    def file_check(success_dialog = true)\n+      return false if abort_on_no_current_table()\n+      save_all_gui_data()\n+      Qt::MessageBox.information(self, \"File Check\", @core.file_check()) if success_dialog\n+      true\n+    rescue TableManagerCore::CoreError, SaveError => err\n+      Qt::MessageBox.warning(self, \"File Check Errors\", err.message)\n+      false\n+    rescue => err\n+      ExceptionDialog.new(self, err, \"Unknown File Check Errors\", false)\n+      false\n     end\n \n-    # Menu option that opens a dialog to allows the user to select a table binary\n-    # file named XXX.dat. The associated table definition file (XXX_def.txt)\n-    # is then opened and parsed to determine how to display the binary file in the gui.\n-    def file_open(bin_file = nil, def_file = nil)\n-      begin\n-        unless bin_file and def_file\n-          bin_file, def_file = get_binary_and_definition_file_paths()\n-        end\n-\n-        # Do nothing if the binary or definition files are not found\n-        if bin_file.nil? or def_file.nil? then return end\n-\n-        # Update the labels\n-        @table_bin_label.text = bin_file\n-        @table_def_label.text = def_file\n-\n-        # open the file\n-        begin\n-          @core.file_open(def_file, bin_file)\n-        rescue => err\n-          if err.message.include?(\"Binary\")\n-            Qt::MessageBox.information(self, \"Table Open Error\", err.message)\n-          else\n-            ExceptionDialog.new(self, err, \"Table Open Errors\", false)\n-          end\n-        end\n-\n-        Qt::Application.setOverrideCursor(Qt::Cursor.new(Qt::WaitCursor))\n-\n-        # display the file\n-        delete_tabs()\n-        @core.table_def.get_all_tables.each do |table|\n-          create_table_tab(table)\n-          display_gui_data(table.name)\n-        end\n-        @currently_displayed_table_name = @ordered_gui_table_names[0]\n-        @currently_displayed_table_name ||= '' # ensure it's not nil\n+    # Menu option to create a text file report of all the table data\n+    def file_report\n+      return unless file_check(false)\n+      report_path = @core.file_report(@table_bin_label.text, @table_def_label.text)\n \n-        Qt::Application.restoreOverrideCursor()\n-      rescue => err\n-        ExceptionDialog.new(self, err, \"File Open Errors\", false)\n+      dialog = Qt::Dialog.new(self, Qt::WindowTitleHint | Qt::WindowSystemMenuHint)\n+      dialog.setWindowTitle(\"File Report\")\n+      dialog_layout = Qt::VBoxLayout.new\n+      dialog_layout.addWidget(Qt::Label.new(\"Report file created: #{report_path}\"))\n+      button_layout = Qt::HBoxLayout.new\n+      ok_button = Qt::PushButton.new('&Ok')\n+      ok_button.connect(SIGNAL('clicked()')) { dialog.accept }\n+      ok_button.setEnabled(true)\n+      button_layout.addWidget(ok_button)\n+      button_layout.addStretch(1)\n+      open_button = Qt::PushButton.new('Open in &Editor')\n+      open_button.connect(SIGNAL('clicked()')) { Cosmos.open_in_text_editor(report_path) }\n+      button_layout.addWidget(open_button)\n+      if Kernel.is_windows?\n+        open_excel_button = Qt::PushButton.new('Open in E&xcel')","path":"lib/cosmos/tools/table_manager/table_manager.rb","position":741,"original_position":741,"commit_id":"6f34bb9a655930ed7fab91b1e9e65139e55df213","original_commit_id":"6f34bb9a655930ed7fab91b1e9e65139e55df213","user":{"login":"jmthomas","id":176403,"avatar_url":"https://avatars.githubusercontent.com/u/176403?v=3","gravatar_id":"","url":"https://api.github.com/users/jmthomas","html_url":"https://github.com/jmthomas","followers_url":"https://api.github.com/users/jmthomas/followers","following_url":"https://api.github.com/users/jmthomas/following{/other_user}","gists_url":"https://api.github.com/users/jmthomas/gists{/gist_id}","starred_url":"https://api.github.com/users/jmthomas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jmthomas/subscriptions","organizations_url":"https://api.github.com/users/jmthomas/orgs","repos_url":"https://api.github.com/users/jmthomas/repos","events_url":"https://api.github.com/users/jmthomas/events{/privacy}","received_events_url":"https://api.github.com/users/jmthomas/received_events","type":"User","site_admin":false},"body":"Report files are now csv files to be better compatible with Excel","created_at":"2017-01-03T23:36:41Z","updated_at":"2017-01-03T23:46:12Z","html_url":"https://github.com/BallAerospace/COSMOS/pull/376#discussion_r94506551","pull_request_url":"https://api.github.com/repos/BallAerospace/COSMOS/pulls/376","_links":{"self":{"href":"https://api.github.com/repos/BallAerospace/COSMOS/pulls/comments/94506551"},"html":{"href":"https://github.com/BallAerospace/COSMOS/pull/376#discussion_r94506551"},"pull_request":{"href":"https://api.github.com/repos/BallAerospace/COSMOS/pulls/376"}}},"pull_request":{"url":"https://api.github.com/repos/BallAerospace/COSMOS/pulls/376","id":100039121,"html_url":"https://github.com/BallAerospace/COSMOS/pull/376","diff_url":"https://github.com/BallAerospace/COSMOS/pull/376.diff","patch_url":"https://github.com/BallAerospace/COSMOS/pull/376.patch","issue_url":"https://api.github.com/repos/BallAerospace/COSMOS/issues/376","number":376,"state":"open","locked":false,"title":"Tblmgr refactor","user":{"login":"jmthomas","id":176403,"avatar_url":"https://avatars.githubusercontent.com/u/176403?v=3","gravatar_id":"","url":"https://api.github.com/users/jmthomas","html_url":"https://github.com/jmthomas","followers_url":"https://api.github.com/users/jmthomas/followers","following_url":"https://api.github.com/users/jmthomas/following{/other_user}","gists_url":"https://api.github.com/users/jmthomas/gists{/gist_id}","starred_url":"https://api.github.com/users/jmthomas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jmthomas/subscriptions","organizations_url":"https://api.github.com/users/jmthomas/orgs","repos_url":"https://api.github.com/users/jmthomas/repos","events_url":"https://api.github.com/users/jmthomas/events{/privacy}","received_events_url":"https://api.github.com/users/jmthomas/received_events","type":"User","site_admin":false},"body":"This is pretty massive and it does change the configuration files. I created a command line option --convert to convert old files to the new format as best I could.","created_at":"2017-01-03T23:24:58Z","updated_at":"2017-01-03T23:46:12Z","closed_at":null,"merged_at":null,"merge_commit_sha":null,"assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/BallAerospace/COSMOS/pulls/376/commits","review_comments_url":"https://api.github.com/repos/BallAerospace/COSMOS/pulls/376/comments","review_comment_url":"https://api.github.com/repos/BallAerospace/COSMOS/pulls/comments{/number}","comments_url":"https://api.github.com/repos/BallAerospace/COSMOS/issues/376/comments","statuses_url":"https://api.github.com/repos/BallAerospace/COSMOS/statuses/6f34bb9a655930ed7fab91b1e9e65139e55df213","head":{"label":"BallAerospace:tblmgr_refactor","ref":"tblmgr_refactor","sha":"6f34bb9a655930ed7fab91b1e9e65139e55df213","user":{"login":"BallAerospace","id":8517471,"avatar_url":"https://avatars.githubusercontent.com/u/8517471?v=3","gravatar_id":"","url":"https://api.github.com/users/BallAerospace","html_url":"https://github.com/BallAerospace","followers_url":"https://api.github.com/users/BallAerospace/followers","following_url":"https://api.github.com/users/BallAerospace/following{/other_user}","gists_url":"https://api.github.com/users/BallAerospace/gists{/gist_id}","starred_url":"https://api.github.com/users/BallAerospace/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/BallAerospace/subscriptions","organizations_url":"https://api.github.com/users/BallAerospace/orgs","repos_url":"https://api.github.com/users/BallAerospace/repos","events_url":"https://api.github.com/users/BallAerospace/events{/privacy}","received_events_url":"https://api.github.com/users/BallAerospace/received_events","type":"Organization","site_admin":false},"repo":{"id":28149027,"name":"COSMOS","full_name":"BallAerospace/COSMOS","owner":{"login":"BallAerospace","id":8517471,"avatar_url":"https://avatars.githubusercontent.com/u/8517471?v=3","gravatar_id":"","url":"https://api.github.com/users/BallAerospace","html_url":"https://github.com/BallAerospace","followers_url":"https://api.github.com/users/BallAerospace/followers","following_url":"https://api.github.com/users/BallAerospace/following{/other_user}","gists_url":"https://api.github.com/users/BallAerospace/gists{/gist_id}","starred_url":"https://api.github.com/users/BallAerospace/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/BallAerospace/subscriptions","organizations_url":"https://api.github.com/users/BallAerospace/orgs","repos_url":"https://api.github.com/users/BallAerospace/repos","events_url":"https://api.github.com/users/BallAerospace/events{/privacy}","received_events_url":"https://api.github.com/users/BallAerospace/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/BallAerospace/COSMOS","description":"Ball Aerospace COSMOS","fork":false,"url":"https://api.github.com/repos/BallAerospace/COSMOS","forks_url":"https://api.github.com/repos/BallAerospace/COSMOS/forks","keys_url":"https://api.github.com/repos/BallAerospace/COSMOS/keys{/key_id}","collaborators_url":"https://api.github.com/repos/BallAerospace/COSMOS/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/BallAerospace/COSMOS/teams","hooks_url":"https://api.github.com/repos/BallAerospace/COSMOS/hooks","issue_events_url":"https://api.github.com/repos/BallAerospace/COSMOS/issues/events{/number}","events_url":"https://api.github.com/repos/BallAerospace/COSMOS/events","assignees_url":"https://api.github.com/repos/BallAerospace/COSMOS/assignees{/user}","branches_url":"https://api.github.com/repos/BallAerospace/COSMOS/branches{/branch}","tags_url":"https://api.github.com/repos/BallAerospace/COSMOS/tags","blobs_url":"https://api.github.com/repos/BallAerospace/COSMOS/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/BallAerospace/COSMOS/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/BallAerospace/COSMOS/git/refs{/sha}","trees_url":"https://api.github.com/repos/BallAerospace/COSMOS/git/trees{/sha}","statuses_url":"https://api.github.com/repos/BallAerospace/COSMOS/statuses/{sha}","languages_url":"https://api.github.com/repos/BallAerospace/COSMOS/languages","stargazers_url":"https://api.github.com/repos/BallAerospace/COSMOS/stargazers","contributors_url":"https://api.github.com/repos/BallAerospace/COSMOS/contributors","subscribers_url":"https://api.github.com/repos/BallAerospace/COSMOS/subscribers","subscription_url":"https://api.github.com/repos/BallAerospace/COSMOS/subscription","commits_url":"https://api.github.com/repos/BallAerospace/COSMOS/commits{/sha}","git_commits_url":"https://api.github.com/repos/BallAerospace/COSMOS/git/commits{/sha}","comments_url":"https://api.github.com/repos/BallAerospace/COSMOS/comments{/number}","issue_comment_url":"https://api.github.com/repos/BallAerospace/COSMOS/issues/comments{/number}","contents_url":"https://api.github.com/repos/BallAerospace/COSMOS/contents/{+path}","compare_url":"https://api.github.com/repos/BallAerospace/COSMOS/compare/{base}...{head}","merges_url":"https://api.github.com/repos/BallAerospace/COSMOS/merges","archive_url":"https://api.github.com/repos/BallAerospace/COSMOS/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/BallAerospace/COSMOS/downloads","issues_url":"https://api.github.com/repos/BallAerospace/COSMOS/issues{/number}","pulls_url":"https://api.github.com/repos/BallAerospace/COSMOS/pulls{/number}","milestones_url":"https://api.github.com/repos/BallAerospace/COSMOS/milestones{/number}","notifications_url":"https://api.github.com/repos/BallAerospace/COSMOS/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/BallAerospace/COSMOS/labels{/name}","releases_url":"https://api.github.com/repos/BallAerospace/COSMOS/releases{/id}","deployments_url":"https://api.github.com/repos/BallAerospace/COSMOS/deployments","created_at":"2014-12-17T18:06:25Z","updated_at":"2016-12-22T20:18:16Z","pushed_at":"2017-01-03T23:29:43Z","git_url":"git://github.com/BallAerospace/COSMOS.git","ssh_url":"git@github.com:BallAerospace/COSMOS.git","clone_url":"https://github.com/BallAerospace/COSMOS.git","svn_url":"https://github.com/BallAerospace/COSMOS","homepage":"http://cosmosrb.com","size":56949,"stargazers_count":49,"watchers_count":49,"language":"Ruby","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":22,"mirror_url":null,"open_issues_count":30,"forks":22,"open_issues":30,"watchers":49,"default_branch":"master"}},"base":{"label":"BallAerospace:master","ref":"master","sha":"5f496419cbba4119c58a1ac76a3c097f626dc586","user":{"login":"BallAerospace","id":8517471,"avatar_url":"https://avatars.githubusercontent.com/u/8517471?v=3","gravatar_id":"","url":"https://api.github.com/users/BallAerospace","html_url":"https://github.com/BallAerospace","followers_url":"https://api.github.com/users/BallAerospace/followers","following_url":"https://api.github.com/users/BallAerospace/following{/other_user}","gists_url":"https://api.github.com/users/BallAerospace/gists{/gist_id}","starred_url":"https://api.github.com/users/BallAerospace/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/BallAerospace/subscriptions","organizations_url":"https://api.github.com/users/BallAerospace/orgs","repos_url":"https://api.github.com/users/BallAerospace/repos","events_url":"https://api.github.com/users/BallAerospace/events{/privacy}","received_events_url":"https://api.github.com/users/BallAerospace/received_events","type":"Organization","site_admin":false},"repo":{"id":28149027,"name":"COSMOS","full_name":"BallAerospace/COSMOS","owner":{"login":"BallAerospace","id":8517471,"avatar_url":"https://avatars.githubusercontent.com/u/8517471?v=3","gravatar_id":"","url":"https://api.github.com/users/BallAerospace","html_url":"https://github.com/BallAerospace","followers_url":"https://api.github.com/users/BallAerospace/followers","following_url":"https://api.github.com/users/BallAerospace/following{/other_user}","gists_url":"https://api.github.com/users/BallAerospace/gists{/gist_id}","starred_url":"https://api.github.com/users/BallAerospace/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/BallAerospace/subscriptions","organizations_url":"https://api.github.com/users/BallAerospace/orgs","repos_url":"https://api.github.com/users/BallAerospace/repos","events_url":"https://api.github.com/users/BallAerospace/events{/privacy}","received_events_url":"https://api.github.com/users/BallAerospace/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/BallAerospace/COSMOS","description":"Ball Aerospace COSMOS","fork":false,"url":"https://api.github.com/repos/BallAerospace/COSMOS","forks_url":"https://api.github.com/repos/BallAerospace/COSMOS/forks","keys_url":"https://api.github.com/repos/BallAerospace/COSMOS/keys{/key_id}","collaborators_url":"https://api.github.com/repos/BallAerospace/COSMOS/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/BallAerospace/COSMOS/teams","hooks_url":"https://api.github.com/repos/BallAerospace/COSMOS/hooks","issue_events_url":"https://api.github.com/repos/BallAerospace/COSMOS/issues/events{/number}","events_url":"https://api.github.com/repos/BallAerospace/COSMOS/events","assignees_url":"https://api.github.com/repos/BallAerospace/COSMOS/assignees{/user}","branches_url":"https://api.github.com/repos/BallAerospace/COSMOS/branches{/branch}","tags_url":"https://api.github.com/repos/BallAerospace/COSMOS/tags","blobs_url":"https://api.github.com/repos/BallAerospace/COSMOS/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/BallAerospace/COSMOS/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/BallAerospace/COSMOS/git/refs{/sha}","trees_url":"https://api.github.com/repos/BallAerospace/COSMOS/git/trees{/sha}","statuses_url":"https://api.github.com/repos/BallAerospace/COSMOS/statuses/{sha}","languages_url":"https://api.github.com/repos/BallAerospace/COSMOS/languages","stargazers_url":"https://api.github.com/repos/BallAerospace/COSMOS/stargazers","contributors_url":"https://api.github.com/repos/BallAerospace/COSMOS/contributors","subscribers_url":"https://api.github.com/repos/BallAerospace/COSMOS/subscribers","subscription_url":"https://api.github.com/repos/BallAerospace/COSMOS/subscription","commits_url":"https://api.github.com/repos/BallAerospace/COSMOS/commits{/sha}","git_commits_url":"https://api.github.com/repos/BallAerospace/COSMOS/git/commits{/sha}","comments_url":"https://api.github.com/repos/BallAerospace/COSMOS/comments{/number}","issue_comment_url":"https://api.github.com/repos/BallAerospace/COSMOS/issues/comments{/number}","contents_url":"https://api.github.com/repos/BallAerospace/COSMOS/contents/{+path}","compare_url":"https://api.github.com/repos/BallAerospace/COSMOS/compare/{base}...{head}","merges_url":"https://api.github.com/repos/BallAerospace/COSMOS/merges","archive_url":"https://api.github.com/repos/BallAerospace/COSMOS/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/BallAerospace/COSMOS/downloads","issues_url":"https://api.github.com/repos/BallAerospace/COSMOS/issues{/number}","pulls_url":"https://api.github.com/repos/BallAerospace/COSMOS/pulls{/number}","milestones_url":"https://api.github.com/repos/BallAerospace/COSMOS/milestones{/number}","notifications_url":"https://api.github.com/repos/BallAerospace/COSMOS/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/BallAerospace/COSMOS/labels{/name}","releases_url":"https://api.github.com/repos/BallAerospace/COSMOS/releases{/id}","deployments_url":"https://api.github.com/repos/BallAerospace/COSMOS/deployments","created_at":"2014-12-17T18:06:25Z","updated_at":"2016-12-22T20:18:16Z","pushed_at":"2017-01-03T23:29:43Z","git_url":"git://github.com/BallAerospace/COSMOS.git","ssh_url":"git@github.com:BallAerospace/COSMOS.git","clone_url":"https://github.com/BallAerospace/COSMOS.git","svn_url":"https://github.com/BallAerospace/COSMOS","homepage":"http://cosmosrb.com","size":56949,"stargazers_count":49,"watchers_count":49,"language":"Ruby","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":22,"mirror_url":null,"open_issues_count":30,"forks":22,"open_issues":30,"watchers":49,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/BallAerospace/COSMOS/pulls/376"},"html":{"href":"https://github.com/BallAerospace/COSMOS/pull/376"},"issue":{"href":"https://api.github.com/repos/BallAerospace/COSMOS/issues/376"},"comments":{"href":"https://api.github.com/repos/BallAerospace/COSMOS/issues/376/comments"},"review_comments":{"href":"https://api.github.com/repos/BallAerospace/COSMOS/pulls/376/comments"},"review_comment":{"href":"https://api.github.com/repos/BallAerospace/COSMOS/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/BallAerospace/COSMOS/pulls/376/commits"},"statuses":{"href":"https://api.github.com/repos/BallAerospace/COSMOS/statuses/6f34bb9a655930ed7fab91b1e9e65139e55df213"}}}}
{"actor":{"display_login":"jmthomas"}}