===== ISTEM =====
Solve the following programming task.

TASK: Text Editor with Undo and Redo

Write a class 'Editor' that holds a text document (initially an empty string) and a cursor position (initially 0), with these methods:
- type(text): inserts text at the cursor and moves the cursor to the end of the inserted text.
- moveTo(pos): moves the cursor to pos, clamped to the range 0 to the current text length.
- backspace(n): deletes up to n characters immediately before the cursor (fewer if the cursor is closer than n to the start) and moves the cursor back by the number of characters deleted.
- undo(): reverts the most recent undo step. Does nothing if there is none.
- redo(): re-applies the most recently undone step. Does nothing if there is none.
- getText(): returns the current text.
- getCursor(): returns the current cursor position.

Undo steps:
- Every call to type, and every call to backspace that deletes at least one character, is an edit. An edit normally creates a new undo step.
- Exception: a type call is added to the previous undo step, instead of creating a new one, if the method called immediately before it (not counting getText and getCursor) was also type.
- A backspace that deletes nothing (cursor already at 0) changes nothing and creates no undo step.
- Undoing a step restores the text and the cursor to exactly what they were before the step. Redoing a step restores them to exactly what they were at the end of the step.
- Every edit clears the redo history. moveTo, undo and redo never clear it.

STARTER CODE (javascript):
class Editor {
  // Write your code here
}

module.exports = { Editor };


RULES:
- Keep the function name and signature EXACTLY as given.
- Return working code only. No explanations.
- Put the code in a single ``` block.
- Try to solve it first. If you genuinely cannot, write only this single
  line instead of producing faulty code: CANNOT_SOLVE

===== HAM YANIT =====
```javascript
class Editor {
  constructor() {
    this.text = '';
    this.cursor = 0;
    this.undoStack = [];
    this.redoStack = [];
    this.lastWasType = false;
  }

  type(textStr) {
    if (textStr === '') {
      this.lastWasType = true;
      return;
    }
    
    // Determine if we should merge with previous step
    if (this.lastWasType && this.undoStack.length > 0) {
      // Merge into previous step
      const prev = this.undoStack[this.undoStack.length - 1];
      // The current state before this type is the "before" of the merged step
      // But we need to update the undo step's after state to reflect after both types
      // Actually, the undo step stores: before (text, cursor) and after (text, cursor)
      // When we merge, the "after" of the previous step should become the current state after inserting textStr
      
      const newText = this.text.substring(0, this.cursor) + textStr + this.text.substring(this.cursor);
      const newCursor = this.cursor + textStr.length;
      
      // Update the last undo step's after state
      prev.afterText = newText;
      prev.afterCursor = newCursor;
      
      this.text = newText;
      this.cursor = newCursor;
      this.lastWasType = true;
    } else {
      // Create a new undo step
      const beforeText = this.text;
      const beforeCursor = this.cursor;
      
      const newText = this.text.substring(0, this.cursor) + textStr + this.text.substring(this.cursor);
      const newCursor = this.cursor + textStr.length;
      
      this.text = newText;
      this.cursor = newCursor;
      
      this.undoStack.push({
        beforeText: beforeText,
        beforeCursor: beforeCursor,
        afterText: newText,
        afterCursor: newCursor
      });
      
      this.redoStack = [];
      this.lastWasType = true;
    }
  }

  moveTo(pos) {
    const clamped = Math.max(0, Math.min(pos, this.text.length));
    this.cursor = clamped;
    this.lastWasType = false;
  }

  backspace(n) {
    if (n <= 0) {
      this.lastWasType = false;
      return;
    }
    
    const deleteCount = Math.min(n, this.cursor);
    if (deleteCount === 0) {
      this.lastWasType = false;
      return;
    }
    
    const beforeText = this.text;
    const beforeCursor = this.cursor;
    
    const newText = this.text.substring(0, this.cursor - deleteCount) + this.text.substring(this.cursor);
    const newCursor = this.cursor - deleteCount;
    
    this.text = newText;
    this.cursor = newCursor;
    
    this.undoStack.push({
      beforeText: beforeText,
      beforeCursor: beforeCursor,
      afterText: newText,
      afterCursor: newCursor
    });
    
    this.redoStack = [];
    this.lastWasType = false;
  }

  undo() {
    if (this.undoStack.length === 0) {
      return;
    }
    
    const step = this.undoStack.pop();
    
    // Save current state for redo
    this.redoStack.push({
      beforeText: this.text,
      beforeCursor: this.cursor,
      afterText: step.afterText,
      afterCursor: step.afterCursor
    });
    
    this.text = step.beforeText;
    this.cursor = step.beforeCursor;
    this.lastWasType = false;
  }

  redo() {
    if (this.redoStack.length === 0) {
      return;
    }
    
    const step = this.redoStack.pop();
    
    // Push back to undo stack
    this.undoStack.push({
      beforeText: step.beforeText,
      beforeCursor: step.beforeCursor,
      afterText: step.afterText,
      afterCursor: step.afterCursor
    });
    
    this.text = step.afterText;
    this.cursor = step.afterCursor;
    this.lastWasType = false;
  }

  getText() {
    return this.text;
  }

  getCursor() {
    return this.cursor;
  }
}

module.exports = { Editor };
```