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

TASK: TIK Register Machine

Write a function 'runTik(program)' that runs a program written in TIK, a small made-up language, and returns an array of the numbers it outputs.

Program text:
- Instructions are separated by newlines. Leading and trailing spaces on a line are ignored.
- Lines that are empty (or only spaces) and lines whose first non-space character is '#' are ignored and are not instructions.
- Within an instruction, tokens are separated by one or more spaces.

Machine:
- There are four registers named a, b, c and d. All start at 0.
- Every value stored in a register is reduced to the range 0..999 by taking it modulo 1000, always giving a non-negative result (for example -1 becomes 999 and 1003 becomes 3).
- An integer literal is an optional '-' followed by one or more digits ('+5' and '5.0' are not valid).
- An operand written as X below is either a register name or an integer literal. Its value is the register's value, or the literal reduced to 0..999 in the same way.

Instructions (R must be a register name, N must be an integer literal):
- set R X: R becomes the value of X.
- add R X: R becomes R plus the value of X.
- mul R X: R becomes R times the value of X.
- out X: appends the value of X to the output.
- jmp X N: if the value of X is not 0, the next instruction is the one N instructions away from this one (N may be negative; ignored lines are not counted). Otherwise execution continues with the next instruction.
Instruction names and register names are lowercase; anything else is invalid.

Running:
- Before running anything, check the whole program. If any line that is not ignored is not a valid instruction (unknown name, wrong number of operands, or an invalid register, literal or operand), throw an Error whose message is 'bad instruction at line K', where K is the 1-based line number of the first such line in the original text, counting ignored lines too. In that case nothing is run.
- Execution starts at the first instruction and stops normally when the next instruction position is before the first instruction or after the last one.
- A program may execute at most 10,000 instructions. If it has not stopped after executing 10,000 instructions, throw an Error with the message 'step limit'.

STARTER CODE (javascript):
function runTik(program) {
  // Write your code here
}

module.exports = { runTik };


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
function runTik(program) {
    var lines = program.split('\n');
    
    // First pass: validate all non-ignored lines
    var instructions = [];
    for (var i = 0; i < lines.length; i++) {
        var line = lines[i].trim();
        if (line === '' || line.charAt(0) === '#') {
            continue;
        }
        var tokens = line.split(/\s+/);
        if (tokens.length === 0) continue;
        
        var name = tokens[0];
        var valid = false;
        
        function isValidRegister(s) {
            return s === 'a' || s === 'b' || s === 'c' || s === 'd';
        }
        
        function isValidLiteral(s) {
            if (s === '') return false;
            if (s.charAt(0) === '-') {
                if (s.length < 2) return false;
                for (var j = 1; j < s.length; j++) {
                    if (s.charAt(j) < '0' || s.charAt(j) > '9') return false;
                }
                return true;
            }
            for (var j = 0; j < s.length; j++) {
                if (s.charAt(j) < '0' || s.charAt(j) > '9') return false;
            }
            return true;
        }
        
        function isValidOperand(s) {
            return isValidRegister(s) || isValidLiteral(s);
        }
        
        if (name === 'set') {
            if (tokens.length === 3 && isValidRegister(tokens[1]) && isValidOperand(tokens[2])) {
                valid = true;
            }
        } else if (name === 'add') {
            if (tokens.length === 3 && isValidRegister(tokens[1]) && isValidOperand(tokens[2])) {
                valid = true;
            }
        } else if (name === 'mul') {
            if (tokens.length === 3 && isValidRegister(tokens[1]) && isValidOperand(tokens[2])) {
                valid = true;
            }
        } else if (name === 'out') {
            if (tokens.length === 2 && isValidOperand(tokens[1])) {
                valid = true;
            }
        } else if (name === 'jmp') {
            if (tokens.length === 3 && isValidOperand(tokens[1]) && isValidLiteral(tokens[2])) {
                valid = true;
            }
        }
        
        if (!valid) {
            throw new Error('bad instruction at line ' + (i + 1));
        }
        
        instructions.push({ name: name, operands: tokens.slice(1), line: i + 1 });
    }
    
    // Execute
    var regs = { a: 0, b: 0, c: 0, d: 0 };
    var output = [];
    var pc = 0;
    var steps = 0;
    var totalInstructions = instructions.length;
    
    function getOperandValue(tok) {
        if (isValidRegister(tok)) {
            return regs[tok];
        }
        // must be a literal
        var val = parseInt(tok, 10);
        val = val % 1000;
        if (val < 0) val += 1000;
        return val;
    }
    
    function setReg(name, val) {
        val = val % 1000;
        if (val < 0) val += 1000;
        regs[name] = val;
    }
    
    while (pc >= 0 && pc < totalInstructions) {
        if (steps >= 10000) {
            throw new Error('step limit');
        }
        steps++;
        
        var inst = instructions[pc];
        var result = pc + 1; // default next
        
        if (inst.name === 'set') {
            var x = getOperandValue(inst.operands[1]);
            setReg(inst.operands[0], x);
        } else if (inst.name === 'add') {
            var x = getOperandValue(inst.operands[1]);
            var newVal = regs[inst.operands[0]] + x;
            setReg(inst.operands[0], newVal);
        } else if (inst.name === 'mul') {
            var x = getOperandValue(inst