nodes: 0, module; 1, function_definition; 2, function_name:do_json_count_values; 3, parameters; 4, block; 5, identifier:self; 6, identifier:params; 7, expression_statement; 8, try_statement; 9, expression_statement; 10, expression_statement; 11, for_statement; 12, expression_statement; 13, expression_statement; 14, comment:# what slice do we want?; 15, if_statement; 16, if_statement; 17, for_statement; 18, comment:# if no results were found we call it a failure (i.e.: exit(1) from --run-once); 19, if_statement; 20, comment:"""
  \x1b[1mNAME\x1b[0m
          json_count_values - Gets the frequency of the values associated with the given keys
  
  \x1b[1mSYNOPSIS\x1b[0m
          json_count_values <path> <keys> [top] [minfreq] [reverse] [report_errors] [print_path]
  
  \x1b[1mOPTIONS\x1b[0m
          * top: number of results to show (0 is all) (default: 0)
          * minfreq: minimum frequency to be displayed (default: 1)
          * reverse: sort in descending order (default: true)
          * report_errors: report bad znodes (default: false)
          * print_path: print the path if there are results (default: false)
  
  \x1b[1mEXAMPLES\x1b[0m
          > json_count_values /configs/primary_service endpoint.host
          10.20.0.2  3
          10.20.0.4  3
          10.20.0.5  3
          10.20.0.6  1
          10.20.0.7  1
          ...
  
          """; 21, block; 22, except_clause; 23, assignment; 24, assignment; 25, pattern_list; 26, call; 27, block; 28, assignment; 29, assignment; 30, comparison_operator:params.top == 0; 31, block; 32, elif_clause; 33, else_clause; 34, boolean_operator; 35, block; 36, identifier:i; 37, call; 38, block; 39, comparison_operator:len(results) == 0; 40, block; 41, expression_statement; 42, as_pattern; 43, block; 44, identifier:path_map; 45, call; 46, identifier:values; 47, call; 48, identifier:path; 49, identifier:data; 50, attribute; 51, argument_list; 52, try_statement; 53, identifier:results; 54, call; 55, identifier:results; 56, list_comprehension; 57, attribute; 58, integer:0; 59, expression_statement; 60, comparison_operator:params.top > 0; 61, block; 62, block; 63, comparison_operator:len(results) > 0; 64, attribute; 65, expression_statement; 66, identifier:range; 67, argument_list; 68, expression_statement; 69, expression_statement; 70, call; 71, integer:0; 72, return_statement; 73, call; 74, attribute; 75, as_pattern_target; 76, expression_statement; 77, return_statement; 78, identifier:PathMap; 79, argument_list; 80, identifier:defaultdict; 81, argument_list; 82, identifier:path_map; 83, identifier:get; 84, block; 85, except_clause; 86, except_clause; 87, identifier:sorted; 88, argument_list; 89, identifier:r; 90, for_in_clause; 91, if_clause; 92, identifier:params; 93, identifier:top; 94, assignment; 95, attribute; 96, integer:0; 97, expression_statement; 98, expression_statement; 99, expression_statement; 100, call; 101, integer:0; 102, identifier:params; 103, identifier:print_path; 104, call; 105, identifier:start; 106, identifier:end; 107, assignment; 108, call; 109, identifier:len; 110, argument_list; 111, False; 112, attribute; 113, argument_list; 114, identifier:Keys; 115, identifier:Bad; 116, identifier:ex; 117, call; 118, attribute; 119, attribute; 120, identifier:int; 121, expression_statement; 122, expression_statement; 123, as_pattern; 124, block; 125, as_pattern; 126, block; 127, call; 128, keyword_argument; 129, keyword_argument; 130, identifier:r; 131, identifier:results; 132, comparison_operator:r[1] >= params.minfreq; 133, pattern_list; 134, expression_list; 135, identifier:params; 136, identifier:top; 137, assignment; 138, assignment; 139, assignment; 140, identifier:len; 141, argument_list; 142, attribute; 143, argument_list; 144, pattern_list; 145, subscript; 146, attribute; 147, argument_list; 148, identifier:results; 149, identifier:Keys; 150, identifier:validate; 151, attribute; 152, attribute; 153, argument_list; 154, identifier:self; 155, identifier:_zk; 156, identifier:params; 157, identifier:path; 158, assignment; 159, augmented_assignment; 160, identifier:BadJSON; 161, as_pattern_target; 162, if_statement; 163, attribute; 164, as_pattern_target; 165, if_statement; 166, attribute; 167, argument_list; 168, identifier:key; 169, lambda; 170, identifier:reverse; 171, attribute; 172, subscript; 173, attribute; 174, identifier:start; 175, identifier:end; 176, integer:0; 177, call; 178, pattern_list; 179, expression_list; 180, identifier:start; 181, conditional_expression:len(results) + params.top if abs(params.top) < len(results) else 0; 182, identifier:end; 183, call; 184, identifier:results; 185, identifier:self; 186, identifier:show_output; 187, attribute; 188, identifier:value; 189, identifier:frequency; 190, identifier:results; 191, identifier:i; 192, identifier:self; 193, identifier:show_output; 194, string:"%s = %d"; 195, identifier:value; 196, identifier:frequency; 197, identifier:params; 198, identifier:keys; 199, identifier:self; 200, identifier:show_output; 201, call; 202, identifier:value; 203, call; 204, subscript; 205, integer:1; 206, identifier:ex; 207, attribute; 208, block; 209, identifier:Keys; 210, identifier:Missing; 211, identifier:ex; 212, attribute; 213, block; 214, identifier:values; 215, identifier:items; 216, lambda_parameters; 217, subscript; 218, identifier:params; 219, identifier:reverse; 220, identifier:r; 221, integer:1; 222, identifier:params; 223, identifier:minfreq; 224, identifier:len; 225, argument_list; 226, identifier:start; 227, identifier:end; 228, integer:0; 229, conditional_expression:params.top if params.top < len(results) else len(results); 230, binary_operator:len(results) + params.top; 231, comparison_operator:abs(params.top) < len(results); 232, integer:0; 233, identifier:len; 234, argument_list; 235, identifier:params; 236, identifier:path; 237, identifier:str; 238, argument_list; 239, attribute; 240, argument_list; 241, identifier:values; 242, identifier:value; 243, identifier:params; 244, identifier:report_errors; 245, expression_statement; 246, identifier:params; 247, identifier:report_errors; 248, expression_statement; 249, identifier:item; 250, identifier:item; 251, integer:1; 252, identifier:results; 253, attribute; 254, comparison_operator:params.top < len(results); 255, call; 256, call; 257, attribute; 258, call; 259, call; 260, identifier:results; 261, identifier:ex; 262, identifier:Keys; 263, identifier:value; 264, call; 265, attribute; 266, call; 267, call; 268, identifier:params; 269, identifier:top; 270, attribute; 271, call; 272, identifier:len; 273, argument_list; 274, identifier:len; 275, argument_list; 276, identifier:params; 277, identifier:top; 278, identifier:abs; 279, argument_list; 280, identifier:len; 281, argument_list; 282, identifier:json_deserialize; 283, argument_list; 284, identifier:params; 285, identifier:keys; 286, attribute; 287, argument_list; 288, attribute; 289, argument_list; 290, identifier:params; 291, identifier:top; 292, identifier:len; 293, argument_list; 294, identifier:results; 295, identifier:results; 296, attribute; 297, identifier:results; 298, identifier:data; 299, identifier:self; 300, identifier:show_output; 301, string:"Path %s has bad JSON."; 302, identifier:path; 303, identifier:self; 304, identifier:show_output; 305, string:"Path %s is missing key %s."; 306, identifier:path; 307, identifier:ex; 308, identifier:results; 309, identifier:params; 310, identifier:top
code: def do_json_count_values(self, params):
          """
  \x1b[1mNAME\x1b[0m
          json_count_values - Gets the frequency of the values associated with the given keys
  
  \x1b[1mSYNOPSIS\x1b[0m
          json_count_values <path> <keys> [top] [minfreq] [reverse] [report_errors] [print_path]
  
  \x1b[1mOPTIONS\x1b[0m
          * top: number of results to show (0 is all) (default: 0)
          * minfreq: minimum frequency to be displayed (default: 1)
          * reverse: sort in descending order (default: true)
          * report_errors: report bad znodes (default: false)
          * print_path: print the path if there are results (default: false)
  
  \x1b[1mEXAMPLES\x1b[0m
          > json_count_values /configs/primary_service endpoint.host
          10.20.0.2  3
          10.20.0.4  3
          10.20.0.5  3
          10.20.0.6  1
          10.20.0.7  1
          ...
  
          """
          try:
              Keys.validate(params.keys)
          except Keys.Bad as ex:
              self.show_output(str(ex))
              return
  
          path_map = PathMap(self._zk, params.path)
  
          values = defaultdict(int)
          for path, data in path_map.get():
              try:
                  value = Keys.value(json_deserialize(data), params.keys)
                  values[value] += 1
              except BadJSON as ex:
                  if params.report_errors:
                      self.show_output("Path %s has bad JSON.", path)
              except Keys.Missing as ex:
                  if params.report_errors:
                      self.show_output("Path %s is missing key %s.", path, ex)
  
          results = sorted(values.items(), key=lambda item: item[1], reverse=params.reverse)
          results = [r for r in results if r[1] >= params.minfreq]
  
          # what slice do we want?
          if params.top == 0:
              start, end = 0, len(results)
          elif params.top > 0:
              start, end = 0, params.top if params.top < len(results) else len(results)
          else:
              start = len(results) + params.top if abs(params.top) < len(results) else 0
              end = len(results)
  
          if len(results) > 0 and params.print_path:
              self.show_output(params.path)
  
          for i in range(start, end):
              value, frequency = results[i]
              self.show_output("%s = %d", value, frequency)
  
          # if no results were found we call it a failure (i.e.: exit(1) from --run-once)
          if len(results) == 0:
              return False