code: function(sortedInputEvents) {
        var protoIRs = [];
        var currentPIR = undefined;
        forEventTypesIn(sortedInputEvents, TAP_TYPE_NAMES, function(event) {
          switch (event.typeName) {
            case INPUT_TYPE.TAP_DOWN:
              currentPIR = new ProtoIR(ProtoIR.RESPONSE_TYPE, TAP_IR_NAME);
              currentPIR.pushEvent(event);
              protoIRs.push(currentPIR);
              break;
  
            case INPUT_TYPE.TAP:
              if (currentPIR) {
                currentPIR.pushEvent(event);
              } else {
                // Sometimes we get Tap events with no TapDown, sometimes we get
                // TapDown events. Handle both.
                currentPIR = new ProtoIR(ProtoIR.RESPONSE_TYPE, TAP_IR_NAME);
                currentPIR.pushEvent(event);
                protoIRs.push(currentPIR);
              }
              currentPIR = undefined;
              break;
  
            case INPUT_TYPE.TAP_CANCEL:
              if (!currentPIR) {
                var pir = new ProtoIR(ProtoIR.IGNORED_TYPE);
                pir.pushEvent(event);
                protoIRs.push(pir);
                break;
              }
  
              if (currentPIR.isNear(event, INPUT_MERGE_THRESHOLD_MS)) {
                currentPIR.pushEvent(event);
              } else {
                currentPIR = new ProtoIR(ProtoIR.RESPONSE_TYPE, TAP_IR_NAME);
                currentPIR.pushEvent(event);
                protoIRs.push(currentPIR);
              }
              currentPIR = undefined;
              break;
          }
        });
        return protoIRs;
      }
docs: Solitary Tap events are simple Responses:  RRR TTT  TapDowns are part of Responses.  RRRRRRR DDD TTT  TapCancels are part of Responses, which seems strange. They always go with scrolls, so they'll probably be merged with scroll Responses. TapCancels can take a significant amount of time and account for a significant amount of work, which should be grouped with the scroll IRs if possible.  RRRRRRR DDD CCC