docs: public String build(final InternalKnowledgePackage pkg,
                          final FunctionDescr functionDescr,
                          final TypeResolver typeResolver,
                          final Map<String, LineMappings> lineMappings,
                          final List<KnowledgeBuilderResult> errors) {
  
          final Map<String, Object> vars = new HashMap<String, Object>();
  
          vars.put("package",
                   pkg.getName());
  
          vars.put("imports",
                   pkg.getImports().keySet());
  
          final List<String> staticImports = new LinkedList<String>();
          for (String staticImport : pkg.getStaticImports()) {
              if (!staticImport.endsWith(functionDescr.getName())) {
                  staticImports.add(staticImport);
              }
          }
  
          vars.put("staticImports",
                   staticImports);
  
          vars.put("className",
                   StringUtils.ucFirst(functionDescr.getName()));
  
          vars.put("methodName",
                   functionDescr.getName());
  
          vars.put("returnType",
                   functionDescr.getReturnType());
  
          vars.put("parameterTypes",
                   functionDescr.getParameterTypes());
  
          vars.put("parameterNames",
                   functionDescr.getParameterNames());
  
          vars.put("hashCode",
                   functionDescr.getText().hashCode());
  
          // Check that all the parameters are resolvable
          final List<String> names = functionDescr.getParameterNames();
          final List<String> types = functionDescr.getParameterTypes();
          for (int i = 0, size = names.size(); i < size; i++) {
              try {
                  typeResolver.resolveType(types.get(i));
              } catch (final ClassNotFoundException e) {
                  errors.add(new FunctionError(functionDescr,
                                               e,
                                               "Unable to resolve type " + types.get(i) + " while building function."));
                  break;
              }
          }
  
          vars.put("text",
                   functionDescr.getText());
  
          final String text = String.valueOf(TemplateRuntime.eval(template, null, new MapVariableResolverFactory(vars)));
  
          final BufferedReader reader = new BufferedReader(new StringReader(text));
          final String lineStartsWith = "    public static " + functionDescr.getReturnType() + " " + functionDescr.getName();
          try {
              String line;
              int offset = 0;
              while ((line = reader.readLine()) != null) {
                  offset++;
                  if (line.startsWith(lineStartsWith)) {
                      break;
                  }
              }
              functionDescr.setOffset(offset);
          } catch (final IOException e) {
              // won't ever happen, it's just reading over a string.
              throw new RuntimeException("Error determining start offset with function");
          }
  
          final String name = pkg.getName() + "." + StringUtils.ucFirst(functionDescr.getName());
          final LineMappings mapping = new LineMappings(name);
          mapping.setStartLine(functionDescr.getLine());
          mapping.setOffset(functionDescr.getOffset());
          lineMappings.put(name,
                           mapping);
  
          return text;
      }