docs: function(sortedInputEvents) {
        var protoIRs = [];
        var currentPIR = undefined;
        var sawFirstMove = false;
        forEventTypesIn(sortedInputEvents, TOUCH_TYPE_NAMES, function(event) {
          switch (event.typeName) {
            case INPUT_TYPE.TOUCH_START:
              if (currentPIR) {
                // NB: currentPIR will probably be merged with something from
                // handlePinchEvents(). Multiple TouchStart events without an
                // intervening TouchEnd logically implies that multiple fingers
                // are on the screen, so this is probably a pinch gesture.
                currentPIR.pushEvent(event);
              } else {
                currentPIR = new ProtoIR(ProtoIR.RESPONSE_TYPE, TOUCH_IR_NAME);
                currentPIR.pushEvent(event);
                protoIRs.push(currentPIR);
                sawFirstMove = false;
              }
              break;
  
            case INPUT_TYPE.TOUCH_MOVE:
              if (!currentPIR) {
                currentPIR = new ProtoIR(ProtoIR.ANIMATION_TYPE, TOUCH_IR_NAME);
                currentPIR.pushEvent(event);
                protoIRs.push(currentPIR);
                break;
              }
  
              // Like Scrolls and Pinches, the Response is defined to be the
              // TouchStart plus the first TouchMove, then the rest of the
              // TouchMoves constitute an Animation.
              if ((sawFirstMove &&
                  (currentPIR.irType === ProtoIR.RESPONSE_TYPE)) ||
                  !currentPIR.isNear(event, INPUT_MERGE_THRESHOLD_MS)) {
                // If there's already a touchmove in the currentPIR or it's not
                // near event, then finish it and start a new animation.
                var prevEnd = currentPIR.end;
                currentPIR = new ProtoIR(ProtoIR.ANIMATION_TYPE, TOUCH_IR_NAME);
                currentPIR.pushEvent(event);
                // It's possible for there to be a gap between TouchMoves, but
                // that doesn't mean that there should be an Idle IR there.
                currentPIR.start = prevEnd;
                protoIRs.push(currentPIR);
              } else {
                currentPIR.pushEvent(event);
                sawFirstMove = true;
              }
              break;
  
            case INPUT_TYPE.TOUCH_END:
              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 {
                var pir = new ProtoIR(ProtoIR.IGNORED_TYPE);
                pir.pushEvent(event);
                protoIRs.push(pir);
              }
              currentPIR = undefined;
              break;
          }
        });
        return protoIRs;
      }