编译模板
@param 		string 		$tempFile 	 	模板文件路径
@param		string		$compileFile	编译文件路径
431999
private function complieTemplate($tempFile, $compileFile) {

        //根据缓存情况编译模板
        if ( !file_exists($compileFile)
            || ($this->cache == 1 && filemtime($compileFile) < filemtime($tempFile))
            || $this->cache == 0 ) {

            //获取模板文件
            $content = @file_get_contents($tempFile);
            if ( $content == FALSE ) {
                if ( APP_DEBUG ) {
                    E("加载模板文件 {".$tempFile."} 失败！请在相应的目录建立模板文件。");
                }
            }
            //替换模板
            $content = preg_replace(array_keys(self::$tempRules), self::$tempRules, $content);
            //生成编译目录
            if ( !file_exists(dirname($compileFile)) ) {
                FileUtils::makeFileDirs(dirname($compileFile));
            }

            //生成php文件
            if ( !file_put_contents($compileFile, $content, LOCK_EX) ) {
                if ( APP_DEBUG ) {
                    E("生成编译文件 {$compileFile} 失败。");
                }
            }
        }

	}
744843
public function renderHtml(string $latteFile, array $data, string $tempFolderLatte = '/tmp/latte'): string
    {
        $latte = new Engine();
        $latte->setTempDirectory($tempFolderLatte);
        return $latte->renderToString($latteFile, $data);
    }
197252
function compileTemplateFile( $file, $returnResourceData = false )
    {
        $this->resetErrorLog();

        if ( !file_exists( $file ) )
            return false;
        $resourceHandler = $this->resourceFor( $file, $resourceName, $templateName );
        if ( !$resourceHandler )
            return false;
        $resourceData = $this->resourceData( $resourceHandler, $file, $resourceName, $templateName );
        $resourceData['key-data'] = "file:" . $file;
        $key = md5( $resourceData['key-data'] );
        $extraParameters = array();
        $resourceHandler->handleResource( $this, $resourceData, eZTemplate::RESOURCE_FETCH, $extraParameters );

        $isCompiled = false;
        if ( isset( $resourceData['compiled-template'] ) )
            $isCompiled = $resourceData['compiled-template'];

        if ( !$isCompiled )
        {
            $root =& $resourceData['root-node'];
            $root = array( eZTemplate::NODE_ROOT, false );
            $templateText = $resourceData["text"];
            $rootNamespace = '';
            $this->parse( $templateText, $root, $rootNamespace, $resourceData );
            if ( eZTemplate::isDebugEnabled() )
            {
                $this->appendDebugNodes( $root, $resourceData );
            }

            $result = eZTemplateCompiler::compileTemplate( $this, $key, $resourceData );
        }
        else
        {
            $result = true;
        }

        if ( $returnResourceData )
        {
            $resourceData['result'] = $result;
            return $resourceData;
        }
        return $result;
    }
1012601
public void setTempdir(final File tempdir) {
        this.tempDir = tempdir.getAbsoluteFile();
        attrs.put(ANT_INVOKER_PARAM_TEMPDIR, tempdir.getAbsolutePath());
    }
332062
private function handleTempFile($action, TempFile $tempFile)
    {
        $volume = $this->volumeManager->getByFolderId($tempFile->getFolderId());
        $folder = $volume->findFolder($tempFile->getFolderId());
        $file = null;

        switch ($action) {
            case self::ACTION_SAVE:
                $file = $volume->createFile($folder, $tempFile, array(), $tempFile->getUserId());
                break;

            case self::ACTION_REPLACE:
                $file = $volume->findFile($tempFile->getFileId());
                $volume->replaceFile($file, $tempFile, array(), $tempFile->getUserId());
                break;

            case self::ACTION_KEEP_BOTH:
                $tempFile->setAlternativeName($this->createAlternateFilename($tempFile));
                $file = $volume->createFile($folder, $tempFile, array(), $tempFile->getUserId());
                break;

            case self::ACTION_SAVE_VERSION:
                $file = $volume->findFile($tempFile->getFileId());
                $fileVersion = $volume->createFileVersion($file, $tempFile, array(), $tempFile->getUserId());
                $volume->activateFileVersion($file, $fileVersion, $tempFile->getUserId());
                break;

            case self::ACTION_DISCARD:
            default:
                break;
        }

        $this->tempStorage->remove($tempFile);

        return $file;
    }
1167359
public function setTempPath(FilePathInterface $tempPath): void
    {
        if (!$tempPath->isDirectory()) {
            throw new InvalidFilePathException('Temp path "' . $tempPath . '" is not a directory.');
        }

        try {
            $this->tempPath = $this->documentRoot->withFilePath($tempPath);
        } catch (FilePathLogicException $e) {
            throw new InvalidFilePathException($e->getMessage());
        }
    }
1358672
public final static void move(File fromFile, File toFile)
            throws IOException {
        // try the simple way first.
        if (fromFile.renameTo(toFile)) {
            return;
        }

        // copy to the temp file, then rename to the desired name.
        checkThatFileDoesntExist(toFile);
        File tempFile = createTempFile(toFile);
        checkThatFileDoesntExist(tempFile);
        copy(fromFile, tempFile);
        tempFile.renameTo(toFile);
        // delete the old one
        if (!fromFile.delete()) {
            throw new IOException("Failed to delete '" + fromFile.getParent()
                    + "'");
        }
    }
214695
func (fs *fakeFs) TempFile(dir, prefix string) (File, error) {
	file, err := fs.a.TempFile(dir, prefix)
	if err != nil {
		return nil, err
	}
	return &fakeFile{file}, nil
}
702690
private function compiler(&$content, $cacheFile)
    {
        // 判断是否启用布局
        if ($this->config['layout_on']) {
            if (false !== strpos($content, '{__NOLAYOUT__}')) {
                // 可以单独定义不使用布局
                $content = str_replace('{__NOLAYOUT__}', '', $content);
            } else {
                // 读取布局模板
                $layoutFile = $this->parseTemplateFile($this->config['layout_name']);

                if ($layoutFile) {
                    // 替换布局的主体内容
                    $content = str_replace($this->config['layout_item'], $content, file_get_contents($layoutFile));
                }
            }
        } else {
            $content = str_replace('{__NOLAYOUT__}', '', $content);
        }

        // 模板解析
        $this->parse($content);

        if ($this->config['strip_space']) {
            /* 去除html空格与换行 */
            $find    = ['~>\s+<~', '~>(\s+\n|\r)~'];
            $replace = ['><', '>'];
            $content = preg_replace($find, $replace, $content);
        }

        // 优化生成的php代码
        $content = preg_replace('/\?>\s*<\?php\s(?!echo\b)/s', '', $content);

        // 模板过滤输出
        $replace = $this->config['tpl_replace_string'];
        $content = str_replace(array_keys($replace), array_values($replace), $content);

        // 添加安全代码及模板引用记录
        $content = '<?php /*' . serialize($this->includeFile) . '*/ ?>' . "\n" . $content;
        // 编译存储
        $this->storage->write($cacheFile, $content);

        $this->includeFile = [];

        return;
    }
636576
public function compile($templatePath, array $data, TemplateCompiler $compiler)
    {
        return $compiler->compile($this->file->get($templatePath), $data);
    }
1221501
public function saveUploadFile($tempFile, $uploadPath)
    {
        $uploadPath = $this->getRealPath($uploadPath);
        if (!is_dir(dirname($uploadPath))) {
            @mkdir(dirname($uploadPath), 0755, true);
        }
        return move_uploaded_file($tempFile, $uploadPath);
    }
1115064
protected function _write($templ = '', $base_path = '')
    {
        $output = trim($templ);

        if (empty($output)) {
            $output   = html::doctype('html5') . "\n" . $this->default_template;
            $is_empty = true;
        }

        // set default page title
        if (empty($this->pagetitle)) {
            $this->pagetitle = 'Roundcube Mail';
        }

        // declare page language
        if (!empty($_SESSION['language'])) {
            $lang = substr($_SESSION['language'], 0, 2);
            $output = preg_replace('/<html/', '<html lang="' . html::quote($lang) . '"', $output, 1);
            if (!headers_sent()) {
                header('Content-Language: ' . $lang);
            }
        }

        // replace specialchars in content
        $page_title  = html::quote($this->pagetitle);
        $page_header = '';
        $page_footer = '';

        // include meta tag with charset
        if (!empty($this->charset)) {
            if (!headers_sent()) {
                header('Content-Type: text/html; charset=' . $this->charset);
            }
            $page_header = '<meta http-equiv="content-type"';
            $page_header.= ' content="text/html; charset=';
            $page_header.= $this->charset . '" />'."\n";
        }

        // definition of the code to be placed in the document header and footer
        if (is_array($this->script_files['head'])) {
            foreach ($this->script_files['head'] as $file) {
                $page_header .= html::script($file);
            }
        }

        $head_script = $this->scripts['head_top'] . $this->scripts['head'];
        if (!empty($head_script)) {
            $page_header .= html::script(array(), $head_script);
        }

        if (!empty($this->header)) {
            $page_header .= $this->header;
        }

        // put docready commands into page footer
        if (!empty($this->scripts['docready'])) {
            $this->add_script('$(document).ready(function(){ ' . $this->scripts['docready'] . "\n});", 'foot');
        }

        if (is_array($this->script_files['foot'])) {
            foreach ($this->script_files['foot'] as $file) {
                $page_footer .= html::script($file);
            }
        }

        if (!empty($this->footer)) {
            $page_footer .= $this->footer . "\n";
        }

        if (!empty($this->scripts['foot'])) {
            $page_footer .= html::script(array(), $this->scripts['foot']);
        }

        // find page header
        if ($hpos = stripos($output, '</head>')) {
            $page_header .= "\n";
        }
        else {
            if (!is_numeric($hpos)) {
                $hpos = stripos($output, '<body');
            }
            if (!is_numeric($hpos) && ($hpos = stripos($output, '<html'))) {
                while ($output[$hpos] != '>') {
                    $hpos++;
                }
                $hpos++;
            }
            $page_header = "<head>\n<title>$page_title</title>\n$page_header\n</head>\n";
        }

        // add page hader
        if ($hpos) {
            $output = substr_replace($output, $page_header, $hpos, 0);
        }
        else {
            $output = $page_header . $output;
        }

        // add page footer
        if (($fpos = strripos($output, '</body>')) || ($fpos = strripos($output, '</html>'))) {
            $output = substr_replace($output, $page_footer."\n", $fpos, 0);
        }
        else {
            $output .= "\n".$page_footer;
        }

        // add css files in head, before scripts, for speed up with parallel downloads
        if (!empty($this->css_files) && !$is_empty
            && (($pos = stripos($output, '<script ')) || ($pos = stripos($output, '</head>')))
        ) {
            $css = '';
            foreach ($this->css_files as $file) {
                $css .= html::tag('link', array('rel' => 'stylesheet',
                    'type' => 'text/css', 'href' => $file, 'nl' => true));
            }
            $output = substr_replace($output, $css, $pos, 0);
        }

        $output = $this->parse_with_globals($this->fix_paths($output));

        if ($this->assets_path) {
            $output = $this->fix_assets_paths($output);
        }

        $output = $this->postrender($output);

        // trigger hook with final HTML content to be sent
        $hook = $this->app->plugins->exec_hook("send_page", array('content' => $output));
        if (!$hook['abort']) {
            if ($this->charset != RCUBE_CHARSET) {
                echo rcube_charset::convert($hook['content'], RCUBE_CHARSET, $this->charset);
            }
            else {
                echo $hook['content'];
            }
        }
    }
49569
public function compileRange($exprRaw, CompilationContext $compilationContext)
    {
        if (!\count($exprRaw['parameters'])) {
            return false;
        }

        if (\count($exprRaw['parameters']) > 3) {
            return false;
        }

        $functionCall = new FunctionCall();
        $parameters = $functionCall->getResolvedParamsAsExpr($exprRaw['parameters'], $compilationContext, $exprRaw);

        if (2 != \count($parameters) && 3 != \count($parameters)) {
            throw new CompilerException('Wrong number of parameters', $this->statement['expr']);
        }

        if ('variable' != $parameters[0]->getType()) {
            if (!$parameters[0]->isIntCompatibleType()) {
                return false;
            }
        }

        if ('variable' != $parameters[1]->getType()) {
            if (!$parameters[1]->isIntCompatibleType()) {
                return false;
            }
        }

        $codePrinter = $compilationContext->codePrinter;
        $exprBuilder = BuilderFactory::getInstance();

        /*
         * Initialize 'key' variable
         */
        if (isset($this->statement['key'])) {
            /**
             * This variable is used to check if the loop is in its first iteration.
             */
            $keyVariable = $compilationContext->symbolTable->getTempVariableForWrite('long', $compilationContext, $this->statement);
            $keyVariable->increaseUses();
        }

        /**
         * This variable is used to check if the loop is in its first iteration.
         */
        $flagVariable = $compilationContext->symbolTable->getTempVariableForWrite('bool', $compilationContext, $this->statement);

        if ('variable' != $parameters[0]->getType()) {
            $tempVariable = $compilationContext->symbolTable->addTemp($parameters[0]->getType(), $compilationContext);
        } else {
            $rangeVariable = $compilationContext->symbolTable->getVariableForRead($parameters[0]->getCode(), $compilationContext, $this->statement['expr']);
            $tempVariable = $compilationContext->symbolTable->addTemp($rangeVariable->getType(), $compilationContext);
        }

        /*
         * Create a copy of the current value in the end of the range to avoid modify the range
         * inside the cycle
         */
        if ('variable' != $parameters[1]->getType()) {
            $upperBoundVariable = $compilationContext->symbolTable->getTempVariable($parameters[1]->getType(), $compilationContext);
        } else {
            $rangeVariable = $compilationContext->symbolTable->getVariableForRead($parameters[1]->getCode(), $compilationContext, $this->statement['expr']);
            $upperBoundVariable = $compilationContext->symbolTable->getTempVariable($rangeVariable->getType(), $compilationContext);
        }

        /**
         * Create an implicit 'let' operation to set the current value in the upper bound of the range.
         */
        $builderLet = $exprBuilder->statements()->let();
        $builderLet->setAssignments([$exprBuilder->operators()
            ->assignVariable($upperBoundVariable->getName(), $exprBuilder->literal($parameters[1]->getType(), $parameters[1]->getCode())
                ->setFile($this->statement['file'])
                ->setLine($this->statement['line'])
                ->setChar($this->statement['char']))
            ->setFile($this->statement['file'])
            ->setLine($this->statement['line'])
            ->setChar($this->statement['char']),
        ]);

        $statement = new LetStatement($builderLet->build());
        $statement->compile($compilationContext);

        if ($this->statement['reverse']) {
            /*
             * Create an implicit 'let' operation for the initialize expression
             */
            $builderLet->setAssignments([$exprBuilder->operators()
                ->assignVariable($tempVariable->getName(), $exprBuilder->variable($upperBoundVariable->getName())
                    ->setFile($this->statement['file'])
                    ->setLine($this->statement['line'])
                    ->setChar($this->statement['char']))
                ->setFile($this->statement['file'])
                ->setLine($this->statement['line'])
                ->setChar($this->statement['char']),
            ]);
            $statement = new LetStatement($builderLet->build());
        } else {
            /*
             * Create an implicit 'let' operation for the initialize expression
             */
            $builderLet->setAssignments([$exprBuilder->operators()
                ->assignVariable($tempVariable->getName(), $exprBuilder->literal($parameters[0]->getType(), $parameters[0]->getCode())
                    ->setFile($this->statement['file'])
                    ->setLine($this->statement['line'])
                    ->setChar($this->statement['char']))
                ->setFile($this->statement['file'])
                ->setLine($this->statement['line'])
                ->setChar($this->statement['char']),
            ]);
            $statement = new LetStatement($builderLet->build());
        }

        $statement->compile($compilationContext);

        /*
         * Initialize 'key' variable
         */
        if (isset($this->statement['key'])) {
            $codePrinter->output($keyVariable->getName().' = 0;');
        }
        $codePrinter->output($flagVariable->getName().' = 0;');

        if ($this->statement['reverse']) {
            $conditionExpr = [
                'type' => 'greater-equal',
                'left' => ['type' => 'variable', 'value' => $tempVariable->getName()],
                'right' => ['type' => $parameters[0]->getType(), 'value' => $parameters[0]->getCode()],
            ];
        } else {
            $conditionExpr = [
                'type' => 'less-equal',
                'left' => ['type' => 'variable', 'value' => $tempVariable->getName()],
                'right' => ['type' => 'variable', 'value' => $upperBoundVariable->getName()],
            ];
        }

        $expr = new EvalExpression();
        $condition = $expr->optimize($conditionExpr, $compilationContext);

        $codePrinter->output('if ('.$condition.') {');
        $codePrinter->increaseLevel();

        /*
         * Inside a cycle
         */
        ++$compilationContext->insideCycle;

        $codePrinter->output('while (1) {');
        $codePrinter->increaseLevel();

        $codePrinter->output('if ('.$flagVariable->getName().') {');

        $codePrinter->increaseLevel();

        if (isset($this->statement['key'])) {
            $codePrinter->output($keyVariable->getName().'++;');
        }

        if ($this->statement['reverse']) {
            if (!isset($parameters[2])) {
                $statement = new LetStatement([
                    'type' => 'let',
                    'assignments' => [
                        [
                            'assign-type' => 'decr',
                            'variable' => $tempVariable->getName(),
                            'file' => $this->statement['file'],
                            'line' => $this->statement['line'],
                            'char' => $this->statement['char'],
                        ],
                    ],
                ]);
            } else {
                $statement = new LetStatement([
                    'type' => 'let',
                    'assignments' => [
                        [
                            'assign-type' => 'variable',
                            'operator' => 'sub-assign',
                            'variable' => $tempVariable->getName(),
                            'expr' => [
                                'type' => $parameters[2]->getType(),
                                'value' => $parameters[2]->getCode(),
                                'file' => $this->statement['file'],
                                'line' => $this->statement['line'],
                                'char' => $this->statement['char'],
                            ],
                            'file' => $this->statement['file'],
                            'line' => $this->statement['line'],
                            'char' => $this->statement['char'],
                        ],
                    ],
                ]);
            }
        } else {
            if (!isset($parameters[2])) {
                $statement = new LetStatement([
                    'type' => 'let',
                    'assignments' => [
                        [
                            'assign-type' => 'incr',
                            'variable' => $tempVariable->getName(),
                            'file' => $this->statement['file'],
                            'line' => $this->statement['line'],
                            'char' => $this->statement['char'],
                        ],
                    ],
                ]);
            } else {
                $statement = new LetStatement([
                    'type' => 'let',
                    'assignments' => [
                        [
                            'assign-type' => 'variable',
                            'operator' => 'add-assign',
                            'variable' => $tempVariable->getName(),
                            'expr' => [
                                'type' => $parameters[2]->getType(),
                                'value' => $parameters[2]->getCode(),
                                'file' => $this->statement['file'],
                                'line' => $this->statement['line'],
                                'char' => $this->statement['char'],
                            ],
                            'file' => $this->statement['file'],
                            'line' => $this->statement['line'],
                            'char' => $this->statement['char'],
                        ],
                    ],
                ]);
            }
        }
        $statement->compile($compilationContext);

        /**
         * Multi-line conditions would need to be regenerated here.
         */
        $condition = $expr->optimize($conditionExpr, $compilationContext);
        $codePrinter->output('if (!('.$condition.')) {');
        $codePrinter->output("\t".'break;');
        $codePrinter->output('}');

        $codePrinter->decreaseLevel();

        $codePrinter->output('} else {');
        $codePrinter->output("\t".$flagVariable->getName().' = 1;');
        $codePrinter->output('}');

        /*
         * Initialize 'key' variable
         */
        if (isset($this->statement['key'])) {
            /*
             * Check for anonymous variables
             */
            if ('_' != $this->statement['key']) {
                $keyVariableName = $this->statement['key'];
            } else {
                $keyVariableName = $keyVariable->getName();
            }

            /**
             * Create an implicit 'let' operation, @TODO use a builder.
             */
            $statement = new LetStatement([
                'type' => 'let',
                'assignments' => [
                    [
                        'assign-type' => 'variable',
                        'variable' => $keyVariableName,
                        'operator' => 'assign',
                        'expr' => [
                            'type' => 'variable',
                            'value' => $keyVariable->getName(),
                            'file' => $this->statement['file'],
                            'line' => $this->statement['line'],
                            'char' => $this->statement['char'],
                        ],
                        'file' => $this->statement['file'],
                        'line' => $this->statement['line'],
                        'char' => $this->statement['char'],
                    ],
                ],
            ]);

            $statement->compile($compilationContext);
        }

        /*
         * Initialize 'value' variable
         */
        if (isset($this->statement['value'])) {
            /*
             * Check for anonymous variables
             */
            if ('_' != $this->statement['value']) {
                $valueVariable = $this->statement['value'];
            } else {
                $valueVariable = $tempVariable->getName();
            }

            /**
             * Create an implicit 'let' operation, @TODO use a builder.
             */
            $statement = new LetStatement([
                'type' => 'let',
                'assignments' => [
                    [
                        'assign-type' => 'variable',
                        'variable' => $valueVariable,
                        'operator' => 'assign',
                        'expr' => [
                            'type' => 'variable',
                            'value' => $tempVariable->getName(),
                            'file' => $this->statement['file'],
                            'line' => $this->statement['line'],
                            'char' => $this->statement['char'],
                        ],
                        'file' => $this->statement['file'],
                        'line' => $this->statement['line'],
                        'char' => $this->statement['char'],
                    ],
                ],
            ]);

            $statement->compile($compilationContext);
        }

        $codePrinter->decreaseLevel();

        /*
         * Compile statements in the 'for' block
         */
        if (isset($this->statement['statements'])) {
            $st = new StatementsBlock($this->statement['statements']);
            $st->isLoop(true);
            if (isset($this->statement['key'])) {
                $st->getMutateGatherer()->increaseMutations($this->statement['key']);
            }
            $st->getMutateGatherer()->increaseMutations($this->statement['value']);
            $st->compile($compilationContext);
        }

        /*
         * Restore the cycle counter
         */
        --$compilationContext->insideCycle;

        $codePrinter->output('}');

        $codePrinter->decreaseLevel();

        $codePrinter->output('}');
    }
536515
private function getTplContent($tplFile, $type)
    {
        if ($type === 0 && !is_null($this->layout)) {//主模板且存在模板布局
            $layoutCon = file_get_contents($this->layout);
            $tplCon = file_get_contents($tplFile);

            //获取子模板内容
            $presult = preg_match_all(
                '#' . $this->options['leftDelimiter'] . 'to\s+([a_zA-Z]+?)' . $this->options['rightDelimiter'] . '(.*?)' . $this->options['leftDelimiter'] . '\/to' . $this->options['rightDelimiter'] . '#is',
                $tplCon,
                $tmpl
            );
            $tplCon = null;
            if ($presult > 0) {
                array_shift($tmpl);
            }
            //保存子模板提取完的区块内容
            for ($i = 0; $i < $presult; $i++) {
                $this->layoutBlockData[$tmpl[0][$i]] = $tmpl[1][$i];
            }
            $presult = null;

            //将子模板内容替换到布局文件返回
            $layoutBlockData = &$this->layoutBlockData;
            $layoutCon = preg_replace_callback(
                '#' . $this->options['leftDelimiter'] . 'block\s+([a_zA-Z]+?)' . $this->options['rightDelimiter'] . '(.*?)' . $this->options['leftDelimiter'] . '\/block' . $this->options['rightDelimiter'] . '#is',
                function ($matches) use ($layoutBlockData) {
                    array_shift($matches);
                    if (isset($layoutBlockData[$matches[0]])) {
                        //替换{parent}标签并返回
                        return str_replace(
                            $this->options['rightDelimiter'] . 'parent' . $this->options['rightDelimiter'],
                            $matches[1],
                            $layoutBlockData[$matches[0]]
                        );
                    } else {
                        return '';
                    }
                },
                $layoutCon
            );
            unset($layoutBlockData);
            $this->layoutBlockData = [];
            return $layoutCon;//返回替换完的布局文件内容
        } else {
            return file_get_contents($tplFile);
        }
    }
531949
protected function beforeFilter($originalFile, $cacheFile)
    {
        if ('coffee' == pathinfo($originalFile, PATHINFO_EXTENSION)) {
            $coffeeScript = CoffeeScript\Compiler::compile(file_get_contents($originalFile), array('header' => false));
            file_put_contents($cacheFile, $coffeeScript);
        }
    }
339507
def debug(templ, *args):
    
    msg = templ % args if args else templ
    tmp = tempfile.gettempdir()
    with open(os.path.join(tmp, 'debug.txt'), 'a', encoding='utf8') as f:
        f.write(msg + '\n')
1261924
def tempfile(self, mode='wb', **args):
        ""
        tf = tempfile.NamedTemporaryFile(mode=mode)
        self.write(tf.name, mode=mode, **args)
        return tfn