function extract(ast, text, scopes, srcScope, destScope, start, end, isExpression) {
        var retObj               = analyzeCode(text, scopes, srcScope, destScope, start, end),
            passParams           = retObj.passParams,
            retParams            = retObj.retParams,
            thisPointerUsed      = retObj.thisPointerUsed,
            returnStatementUsed  = retObj.returnStatementUsed,
            variableDeclarations = retObj.variableDeclarations,
            doc                  = session.editor.document,
            fnBody               = text,
            fnName               = RefactoringUtils.getUniqueIdentifierName(scopes, "extracted"),
            fnDeclaration,
            fnCall;

        function appendVarDeclaration(identifier) {
            if (variableDeclarations.hasOwnProperty(identifier)) {
                 return variableDeclarations[identifier] + " " + identifier;
            }
            else {
                 return identifier;
            }
        }

        if (destScope.isClass) {
            fnCall = StringUtils.format(template.functionCall.class, fnName, passParams.join(", "));
        } else if (thisPointerUsed) {
            passParams.unshift("this");
            fnCall = StringUtils.format(template.functionCall.thisPointer, fnName, passParams.join(", "));
            passParams.shift();
        } else {
            fnCall = StringUtils.format(template.functionCall.normal, fnName, passParams.join(", "));
        }

        // Append return to the fnCall, if the extracted text contains return statement
        // Ideally in this case retParams should be empty.
        if (returnStatementUsed) {
            fnCall = "return " + fnCall;
        }

        if (isExpression) {
            fnBody = StringUtils.format(template.returnStatement.single, fnBody);
        } else {

            var retParamsStr = "";
            if (retParams.length > 1) {
                retParamsStr = StringUtils.format(template.returnStatement.multiple, retParams.join(", "));
                fnCall = "var ret = " + fnCall + ";\n";
                fnCall += retParams.map(function (param) {
                    return StringUtils.format(template.assignment, appendVarDeclaration(param),  "ret." + param);
                }).join("\n");
            } else if (retParams.length === 1) {
                retParamsStr = StringUtils.format(template.returnStatement.single, retParams.join(", "));
                fnCall = StringUtils.format(template.assignment, appendVarDeclaration(retParams[0]), fnCall);
            } else {
                fnCall += ";";
            }

            fnBody = fnBody + "\n" + retParamsStr;
        }

        if (destScope.isClass) {
            fnDeclaration = StringUtils.format(template.functionDeclaration.class, fnName, passParams.join(", "), fnBody);
        } else {
            fnDeclaration = StringUtils.format(template.functionDeclaration.normal, fnName, passParams.join(", "), fnBody);
        }

        start = session.editor.posFromIndex(start);
        end   = session.editor.posFromIndex(end);

        // Get the insertion pos for function declaration
        var insertPos = _.clone(start);
        var fnScopes = scopes.filter(RefactoringUtils.isFnScope);

        for (var i = 0; i < fnScopes.length; ++i) {
            if (fnScopes[i].id === destScope.id) {
                if (fnScopes[i - 1]) {
                     insertPos = session.editor.posFromIndex(fnScopes[i - 1].originNode.start);
                     // If the origin node of the destination scope is a function expression or a arrow function expression,
                     // get the surrounding statement to get the position
                     if (fnScopes[i - 1].originNode.type === "FunctionExpression" || fnScopes[i - 1].originNode.type === "ArrowFunctionExpression") {
                         var surroundStatement = RefactoringUtils.findSurroundASTNode(ast, { start: session.editor.indexFromPos(insertPos)}, ["Statement"]);
                         insertPos = session.editor.posFromIndex(surroundStatement.start);
                     }
                }
                break;
            }
        }

        insertPos.ch = 0;

        // Replace and multi-select and indent
        doc.batchOperation(function() {
            // Replace
            doc.replaceRange(fnCall, start, end);
            doc.replaceRange(fnDeclaration, insertPos);

            // Set selections
            start = doc.adjustPosForChange(start, fnDeclaration.split("\n"), insertPos, insertPos);
            end   = doc.adjustPosForChange(end, fnDeclaration.split("\n"), insertPos, insertPos);

            session.editor.setSelections([
                {
                    start: session.editor.posFromIndex(session.editor.indexFromPos(start) + fnCall.indexOf(fnName)),
                    end:   session.editor.posFromIndex(session.editor.indexFromPos(start) + fnCall.indexOf(fnName) + fnName.length)
                },
                {
                    start: session.editor.posFromIndex(session.editor.indexFromPos(insertPos) + fnDeclaration.indexOf(fnName)),
                    end:   session.editor.posFromIndex(session.editor.indexFromPos(insertPos) + fnDeclaration.indexOf(fnName) + fnName.length)
                }
            ]);

            // indent
            for (var i = start.line; i < start.line + RefactoringUtils.numLines(fnCall); ++i) {
                session.editor._codeMirror.indentLine(i, "smart");
            }
            for (var i = insertPos.line; i < insertPos.line + RefactoringUtils.numLines(fnDeclaration); ++i) {
                session.editor._codeMirror.indentLine(i, "smart");
            }
        });
    }
Does the actual extraction. i.e Replacing the text, Creating a function
and multi select function names