2022-08-04 06:59:33 +00:00
<!DOCTYPE HTML>
< html lang = "zh" class = "sidebar-visible no-js light" >
< head >
<!-- Book generated using mdBook -->
< meta charset = "UTF-8" >
< title > 文本和HTML模板 - Go语言圣经< / title >
<!-- Custom HTML head -->
< meta content = "text/html; charset=utf-8" http-equiv = "Content-Type" >
< meta name = "description" content = "<The Go Programming Language>中文版" >
< meta name = "viewport" content = "width=device-width, initial-scale=1" >
< meta name = "theme-color" content = "#ffffff" / >
< link rel = "icon" href = "../favicon.svg" >
< link rel = "shortcut icon" href = "../favicon.png" >
< link rel = "stylesheet" href = "../css/variables.css" >
< link rel = "stylesheet" href = "../css/general.css" >
< link rel = "stylesheet" href = "../css/chrome.css" >
< link rel = "stylesheet" href = "../css/print.css" media = "print" >
<!-- Fonts -->
< link rel = "stylesheet" href = "../FontAwesome/css/font-awesome.css" >
< link rel = "stylesheet" href = "../fonts/fonts.css" >
<!-- Highlight.js Stylesheets -->
< link rel = "stylesheet" href = "../highlight.css" >
< link rel = "stylesheet" href = "../tomorrow-night.css" >
< link rel = "stylesheet" href = "../ayu-highlight.css" >
<!-- Custom theme stylesheets -->
< link rel = "stylesheet" href = "../style.css" >
< / head >
< body >
<!-- Provide site root to javascript -->
< script type = "text/javascript" >
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
< / script >
<!-- Work around some values being stored in localStorage wrapped in quotes -->
< script type = "text/javascript" >
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') & & theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') & & sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
< / script >
<!-- Set the theme before any content is loaded, prevents flash -->
< script type = "text/javascript" >
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('no-js')
html.classList.remove('light')
html.classList.add(theme);
html.classList.add('js');
< / script >
<!-- Hide / unhide sidebar before it is displayed -->
< script type = "text/javascript" >
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
< / script >
< nav id = "sidebar" class = "sidebar" aria-label = "Table of contents" >
< div class = "sidebar-scrollbox" >
< ol class = "chapter" > < li class = "chapter-item expanded affix " > < a href = "../index.html" > Go语言圣经< / a > < / li > < li class = "chapter-item expanded affix " > < a href = "../preface.html" > 前言< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch1/ch1.html" > < strong aria-hidden = "true" > 1.< / strong > 入门< / a > < / li > < li > < ol class = "section" > < li class = "chapter-item expanded " > < a href = "../ch1/ch1-01.html" > < strong aria-hidden = "true" > 1.1.< / strong > Hello, World< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch1/ch1-02.html" > < strong aria-hidden = "true" > 1.2.< / strong > 命令行参数< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch1/ch1-03.html" > < strong aria-hidden = "true" > 1.3.< / strong > 查找重复的行< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch1/ch1-04.html" > < strong aria-hidden = "true" > 1.4.< / strong > GIF动画< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch1/ch1-05.html" > < strong aria-hidden = "true" > 1.5.< / strong > 获取URL< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch1/ch1-06.html" > < strong aria-hidden = "true" > 1.6.< / strong > 并发获取多个URL< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch1/ch1-07.html" > < strong aria-hidden = "true" > 1.7.< / strong > Web服务< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch1/ch1-08.html" > < strong aria-hidden = "true" > 1.8.< / strong > 本章要点< / a > < / li > < / ol > < / li > < li class = "chapter-item expanded " > < a href = "../ch2/ch2.html" > < strong aria-hidden = "true" > 2.< / strong > 程序结构< / a > < / li > < li > < ol class = "section" > < li class = "chapter-item expanded " > < a href = "../ch2/ch2-01.html" > < strong aria-hidden = "true" > 2.1.< / strong > 命名< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch2/ch2-02.html" > < strong aria-hidden = "true" > 2.2.< / strong > 声明< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch2/ch2-03.html" > < strong aria-hidden = "true" > 2.3.< / strong > 变量< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch2/ch2-04.html" > < strong aria-hidden = "true" > 2.4.< / strong > 赋值< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch2/ch2-05.html" > < strong aria-hidden = "true" > 2.5.< / strong > 类型< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch2/ch2-06.html" > < strong aria-hidden = "true" > 2.6.< / strong > 包和文件< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch2/ch2-07.html" > < strong aria-hidden = "true" > 2.7.< / strong > 作用域< / a > < / li > < / ol > < / li > < li class = "chapter-item expanded " > < a href = "../ch3/ch3.html" > < strong aria-hidden = "true" > 3.< / strong > 基础数据类型< / a > < / li > < li > < ol class = "section" > < li class = "chapter-item expanded " > < a href = "../ch3/ch3-01.html" > < strong aria-hidden = "true" > 3.1.< / strong > 整型< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch3/ch3-02.html" > < strong aria-hidden = "true" > 3.2.< / strong > 浮点数< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch3/ch3-03.html" > < strong aria-hidden = "true" > 3.3.< / strong > 复数< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch3/ch3-04.html" > < strong aria-hidden = "true" > 3.4.< / strong > 布尔型< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch3/ch3-05.html" > < strong aria-hidden = "true" > 3.5.< / strong > 字符串< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch3/ch3-06.html" > < strong aria-hidden = "true" > 3.6.< / strong > 常量< / a > < / li > < / ol > < / li > < li class = "chapter-item expanded " > < a href = "../ch4/ch4.html" > < strong aria-hidden = "true" > 4.< / strong > 复合数据类型< / a > < / li > < li > < ol class = "section" > < li class = "chapter-item expanded " > < a href = "../ch4/ch4-01.html" > < strong aria-hidden = "true" > 4.1.< / strong > 数组< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch4/ch4-02.html" > < strong aria-hidden = "true" > 4.2.< / strong > Slice< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch4/ch4-03.html" > < strong aria-hidden = "true" > 4.3.< / strong > Map< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch4/ch4-04.html" > < strong aria-hidden = "true" > 4.4.< / strong > 结构体< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch4/ch4-05.html" > < strong aria-hidden = "true" > 4.5.< / strong > JSON< / a > < / li > < li class = "chapter-item expanded " > < a href = "../ch4/ch4-06.html" class = "active" > < s
< div id = "sidebar-resize-handle" class = "sidebar-resize-handle" > < / div >
< / nav >
< div id = "page-wrapper" class = "page-wrapper" >
< div class = "page" >
< div id = "menu-bar-hover-placeholder" > < / div >
< div id = "menu-bar" class = "menu-bar sticky bordered" >
< div class = "left-buttons" >
< button id = "sidebar-toggle" class = "icon-button" type = "button" title = "Toggle Table of Contents" aria-label = "Toggle Table of Contents" aria-controls = "sidebar" >
< i class = "fa fa-bars" > < / i >
< / button >
< button id = "theme-toggle" class = "icon-button" type = "button" title = "Change theme" aria-label = "Change theme" aria-haspopup = "true" aria-expanded = "false" aria-controls = "theme-list" >
< i class = "fa fa-paint-brush" > < / i >
< / button >
< ul id = "theme-list" class = "theme-popup" aria-label = "Themes" role = "menu" >
< li role = "none" > < button role = "menuitem" class = "theme" id = "light" > Light (default)< / button > < / li >
< li role = "none" > < button role = "menuitem" class = "theme" id = "rust" > Rust< / button > < / li >
< li role = "none" > < button role = "menuitem" class = "theme" id = "coal" > Coal< / button > < / li >
< li role = "none" > < button role = "menuitem" class = "theme" id = "navy" > Navy< / button > < / li >
< li role = "none" > < button role = "menuitem" class = "theme" id = "ayu" > Ayu< / button > < / li >
< / ul >
< button id = "search-toggle" class = "icon-button" type = "button" title = "Search. (Shortkey: s)" aria-label = "Toggle Searchbar" aria-expanded = "false" aria-keyshortcuts = "S" aria-controls = "searchbar" >
< i class = "fa fa-search" > < / i >
< / button >
< / div >
< h1 class = "menu-title" > Go语言圣经< / h1 >
< div class = "right-buttons" >
< a href = "../print.html" title = "Print this book" aria-label = "Print this book" >
< i id = "print-button" class = "fa fa-print" > < / i >
< / a >
< a href = "https://github.com/gopl-zh/gopl-zh.github.com" title = "Git repository" aria-label = "Git repository" >
< i id = "git-repository-button" class = "fa fa-github" > < / i >
< / a >
< a href = "https://github.com/gopl-zh/gopl-zh.github.com/edit/master/./ch4/ch4-06.md" title = "Suggest an edit" aria-label = "Suggest an edit" >
< i id = "git-edit-button" class = "fa fa-edit" > < / i >
< / a >
< / div >
< / div >
< div id = "search-wrapper" class = "hidden" >
< form id = "searchbar-outer" class = "searchbar-outer" >
< input type = "search" id = "searchbar" name = "searchbar" placeholder = "Search this book ..." aria-controls = "searchresults-outer" aria-describedby = "searchresults-header" >
< / form >
< div id = "searchresults-outer" class = "searchresults-outer hidden" >
< div id = "searchresults-header" class = "searchresults-header" > < / div >
< ul id = "searchresults" >
< / ul >
< / div >
< / div >
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
< script type = "text/javascript" >
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
< / script >
< div id = "content" class = "content" >
<!-- Page table of contents -->
< div class = "sidetoc" > < nav class = "pagetoc" > < / nav > < / div >
< main >
<!-- 头部 -->
< ul dir = "auto" >
2022-08-24 10:48:15 +00:00
< li > < em > KusonStack一站式可编程配置技术栈(Go): < a href = "https://github.com/KusionStack/kusion" > https://github.com/KusionStack/kusion< / a > < / em > < / li >
< li > < em > KCL 配置编程语言(Rust): < a href = "https://github.com/KusionStack/KCLVM" > https://github.com/KusionStack/KCLVM< / a > < / em > < / li >
< li > < em > 凹语言™: < a href = "https://github.com/wa-lang/wa" > https://github.com/wa-lang/wa< / a > < / em > < / li >
2022-08-04 06:59:33 +00:00
< / ul >
< hr >
< h2 id = "46-文本和html模板" > < a class = "header" href = "#46-文本和html模板" > 4.6. 文本和HTML模板< / a > < / h2 >
< p > 前面的例子, 只是最简单的格式化, 使用Printf是完全足够的。但是有时候会需要复杂的打印格式, 这时候一般需要将格式化代码分离出来以便更安全地修改。这些功能是由text/template和html/template等模板包提供的, 它们提供了一个将变量值填充到一个文本或HTML格式的模板的机制。< / p >
< p > 一个模板是一个字符串或一个文件,里面包含了一个或多个由双花括号包含的< code > {{action}}< / code > 对象。大部分的字符串只是按字面值打印, 但是对于actions部分将触发其它的行为。每个actions都包含了一个用模板语言书写的表达式, 一个action虽然简短但是可以输出复杂的打印值, 模板语言包含通过选择结构体的成员、调用函数或方法、表达式控制流if-else语句和range循环语句, 还有其它实例化模板等诸多特性。下面是一个简单的模板字符串: < / p >
< p > < u > < i > gopl.io/ch4/issuesreport< / i > < / u > < / p >
< pre > < code class = "language-Go" > const templ = `{{.TotalCount}} issues:
{{range .Items}}----------------------------------------
Number: {{.Number}}
User: {{.User.Login}}
Title: {{.Title | printf " %.64s" }}
Age: {{.CreatedAt | daysAgo}} days
{{end}}`
< / code > < / pre >
< p > 这个模板先打印匹配到的issue总数, 然后打印每个issue的编号、创建用户、标题还有存在的时间。对于每一个action, 都有一个当前值的概念, 对应点操作符, 写作“.”。当前值“.”最初被初始化为调用模板时的参数, 在当前例子中对应github.IssuesSearchResult类型的变量。模板中< code > {{.TotalCount}}< / code > 对应action将展开为结构体中TotalCount成员以默认的方式打印的值。模板中< code > {{range .Items}}< / code > 和< code > {{end}}< / code > 对应一个循环action, 因此它们之间的内容可能会被展开多次, 循环每次迭代的当前值对应当前的Items元素的值。< / p >
< p > 在一个action中, < code > |< / code > 操作符表示将前一个表达式的结果作为后一个函数的输入, 类似于UNIX中管道的概念。在Title这一行的action中, 第二个操作是一个printf函数, 是一个基于fmt.Sprintf实现的内置函数, 所有模板都可以直接使用。对于Age部分, 第二个动作是一个叫daysAgo的函数, 通过time.Since函数将CreatedAt成员转换为过去的时间长度: < / p >
< pre > < code class = "language-Go" > func daysAgo(t time.Time) int {
return int(time.Since(t).Hours() / 24)
}
< / code > < / pre >
< p > 需要注意的是CreatedAt的参数类型是time.Time, 并不是字符串。以同样的方式, 我们可以通过定义一些方法来控制字符串的格式化( §2.5) , 一个类型同样可以定制自己的JSON编码和解码行为。time.Time类型对应的JSON值是一个标准时间格式的字符串。< / p >
< p > 生成模板的输出需要两个处理步骤。第一步是要分析模板并转为内部表示, 然后基于指定的输入执行模板。分析模板部分一般只需要执行一次。下面的代码创建并分析上面定义的模板templ。注意方法调用链的顺序: template.New先创建并返回一个模板; Funcs方法将daysAgo等自定义函数注册到模板中, 并返回模板; 最后调用Parse函数分析模板。< / p >
< pre > < code class = "language-Go" > report, err := template.New(" report" ).
Funcs(template.FuncMap{" daysAgo" : daysAgo}).
Parse(templ)
if err != nil {
log.Fatal(err)
}
< / code > < / pre >
< p > 因为模板通常在编译时就测试好了, 如果模板解析失败将是一个致命的错误。template.Must辅助函数可以简化这个致命错误的处理: 它接受一个模板和一个error类型的参数, 检测error是否为nil( 如果不是nil则发出panic异常) , 然后返回传入的模板。我们将在5.9节再讨论这个话题。< / p >
< p > 一旦模板已经创建、注册了daysAgo函数、并通过分析和检测, 我们就可以使用github.IssuesSearchResult作为输入源、os.Stdout作为输出源来执行模板: < / p >
< pre > < code class = "language-Go" > var report = template.Must(template.New(" issuelist" ).
Funcs(template.FuncMap{" daysAgo" : daysAgo}).
Parse(templ))
func main() {
result, err := github.SearchIssues(os.Args[1:])
if err != nil {
log.Fatal(err)
}
if err := report.Execute(os.Stdout, result); err != nil {
log.Fatal(err)
}
}
< / code > < / pre >
< p > 程序输出一个纯文本报告:< / p >
< pre > < code > $ go build gopl.io/ch4/issuesreport
$ ./issuesreport repo:golang/go is:open json decoder
13 issues:
----------------------------------------
Number: 5680
User: eaigner
Title: encoding/json: set key converter on en/decoder
Age: 750 days
----------------------------------------
Number: 6050
User: gopherbot
Title: encoding/json: provide tokenizer
Age: 695 days
----------------------------------------
...
< / code > < / pre >
< p > 现在让我们转到html/template模板包。它使用和text/template包相同的API和模板语言, 但是增加了一个将字符串自动转义特性, 这可以避免输入字符串和HTML、JavaScript、CSS或URL语法产生冲突的问题。这个特性还可以避免一些长期存在的安全问题, 比如通过生成HTML注入攻击, 通过构造一个含有恶意代码的问题标题, 这些都可能让模板输出错误的输出, 从而让他们控制页面。< / p >
< p > 下面的模板以HTML格式输出issue列表。注意import语句的不同: < / p >
< p > < u > < i > gopl.io/ch4/issueshtml< / i > < / u > < / p >
< pre > < code class = "language-Go" > import " html/template"
var issueList = template.Must(template.New(" issuelist" ).Parse(`
< h1> {{.TotalCount}} issues< /h1>
< table>
< tr style='text-align: left'>
< th> #< /th>
< th> State< /th>
< th> User< /th>
< th> Title< /th>
< /tr>
{{range .Items}}
< tr>
< td> < a href='{{.HTMLURL}}'> {{.Number}}< /a> < /td>
< td> {{.State}}< /td>
< td> < a href='{{.User.HTMLURL}}'> {{.User.Login}}< /a> < /td>
< td> < a href='{{.HTMLURL}}'> {{.Title}}< /a> < /td>
< /tr>
{{end}}
< /table>
`))
< / code > < / pre >
< p > 下面的命令将在新的模板上执行一个稍微不同的查询:< / p >
< pre > < code > $ go build gopl.io/ch4/issueshtml
$ ./issueshtml repo:golang/go commenter:gopherbot json encoder > issues.html
< / code > < / pre >
< p > 图4.4显示了在web浏览器中的效果图。每个issue包含到Github对应页面的链接。< / p >
< p > < img src = "../images/ch4-04.png" alt = "" / > < / p >
< p > 图4.4中issue没有包含会对HTML格式产生冲突的特殊字符, 但是我们马上将看到标题中含有< code > & < / code > 和< code > < < / code > 字符的issue。下面的命令选择了两个这样的issue: < / p >
< pre > < code > $ ./issueshtml repo:golang/go 3133 10535 > issues2.html
< / code > < / pre >
< p > 图4.5显示了该查询的结果。注意, html/template包已经自动将特殊字符转义, 因此我们依然可以看到正确的字面值。如果我们使用text/template包的话, 这2个issue将会产生错误, 其中“& lt;”四个字符将会被当作小于字符“< ”处理,同时“< link> ”字符串将会被当作一个链接元素处理, 它们都会导致HTML文档结构的改变, 从而导致有未知的风险。< / p >
< p > 我们也可以通过对信任的HTML字符串使用template.HTML类型来抑制这种自动转义的行为。还有很多采用类型命名的字符串类型分别对应信任的JavaScript、CSS和URL。下面的程序演示了两个使用不同类型的相同字符串产生的不同结果: A是一个普通字符串, B是一个信任的template.HTML字符串类型。< / p >
< p > < img src = "../images/ch4-05.png" alt = "" / > < / p >
< p > < u > < i > gopl.io/ch4/autoescape< / i > < / u > < / p >
< pre > < code class = "language-Go" > func main() {
const templ = `< p> A: {{.A}}< /p> < p> B: {{.B}}< /p> `
t := template.Must(template.New(" escape" ).Parse(templ))
var data struct {
A string // untrusted plain text
B template.HTML // trusted HTML
}
data.A = " < b> Hello!< /b> "
data.B = " < b> Hello!< /b> "
if err := t.Execute(os.Stdout, data); err != nil {
log.Fatal(err)
}
}
< / code > < / pre >
< p > 图4.6显示了出现在浏览器中的模板输出。我们看到A的黑体标记被转义失效了, 但是B没有。< / p >
< p > < img src = "../images/ch4-06.png" alt = "" / > < / p >
< p > 我们这里只讲述了模板系统中最基本的特性。一如既往,如果想了解更多的信息,请自己查看包文档:< / p >
< pre > < code > $ go doc text/template
$ go doc html/template
< / code > < / pre >
< p > < strong > 练习 4.14: < / strong > 创建一个web服务器, 查询一次GitHub, 然后生成BUG报告、里程碑和对应的用户信息。< / p >
<!-- 公众号 -->
< hr >
< table >
< tr >
< td >
< img width = "222px" src = "https://chai2010.cn/advanced-go-programming-book/css.png" >
< / td >
< td >
< img width = "222px" src = "https://chai2010.cn/advanced-go-programming-book/cch.png" >
< / td >
< / tr >
< / table >
< div id = "giscus-container" > < / div >
< footer class = "page-footer" >
< span > © 2015-2016 | < a href = "https://github.com/gopl-zh" > Go语言圣经中文版< / a > , 仅学习交流使用< / span >
< / footer >
< / main >
< nav class = "nav-wrapper" aria-label = "Page navigation" >
<!-- Mobile navigation buttons -->
< a rel = "prev" href = "../ch4/ch4-05.html" class = "mobile-nav-chapters previous" title = "Previous chapter" aria-label = "Previous chapter" aria-keyshortcuts = "Left" >
< i class = "fa fa-angle-left" > < / i >
< / a >
< a rel = "next" href = "../ch5/ch5.html" class = "mobile-nav-chapters next" title = "Next chapter" aria-label = "Next chapter" aria-keyshortcuts = "Right" >
< i class = "fa fa-angle-right" > < / i >
< / a >
< div style = "clear: both" > < / div >
< / nav >
< / div >
< / div >
< nav class = "nav-wide-wrapper" aria-label = "Page navigation" >
< a rel = "prev" href = "../ch4/ch4-05.html" class = "nav-chapters previous" title = "Previous chapter" aria-label = "Previous chapter" aria-keyshortcuts = "Left" >
< i class = "fa fa-angle-left" > < / i >
< / a >
< a rel = "next" href = "../ch5/ch5.html" class = "nav-chapters next" title = "Next chapter" aria-label = "Next chapter" aria-keyshortcuts = "Right" >
< i class = "fa fa-angle-right" > < / i >
< / a >
< / nav >
< / div >
< script type = "text/javascript" >
window.playground_copyable = true;
< / script >
< script src = "../elasticlunr.min.js" type = "text/javascript" charset = "utf-8" > < / script >
< script src = "../mark.min.js" type = "text/javascript" charset = "utf-8" > < / script >
< script src = "../searcher.js" type = "text/javascript" charset = "utf-8" > < / script >
< script src = "../clipboard.min.js" type = "text/javascript" charset = "utf-8" > < / script >
< script src = "../highlight.js" type = "text/javascript" charset = "utf-8" > < / script >
< script src = "../book.js" type = "text/javascript" charset = "utf-8" > < / script >
< script type = "text/javascript" charset = "utf-8" >
var pagePath = "ch4/ch4-06.md"
< / script >
<!-- Custom JS scripts -->
< script type = "text/javascript" src = "../js/custom.js" > < / script >
< script type = "text/javascript" src = "../js/bigPicture.js" > < / script >
< / body >
< / html >