深入理解Magento – 第七章 – 自定义Magento系统配置

深入理解Magento

作者:Alan Storm
翻译:Hailong Zhang

第七章 – 自定义Magento系统配置

Magento拥有十分强大的后台管理系统。作为一名开发人员,这套后台管理系统可以让你的用户简单直接的配置Magento系统或者你创建的模 块。和Magento的其他功能一样,你第一次使用这套管理系统的时候可能觉得很麻烦,但是一旦你上手了,你会发现它强大的功能是那么吸引人。那么让我们 开始吧。我们这一章的例子依然是基于Helloworld模块。

添加系统配置文件

首先我们要为模块添加一个系统配置文件。这个文件和“config.xml”是不搭界的
app/code/local/Zhlmmc/Helloworld/etc/system.xml
和全局配置(global config)相似,系统配置也是单独存储的。我们可以通过下面这段代码来获取系统配置文件
//header('Content-Type: text/xml');
header('Content-Type: text/plain');
echo $config = Mage::getConfig()
->loadModulesConfiguration('system.xml')
->getNode()
->asXML();
exit;
你可以把这段代码放到任何执行函数(Action Method)中。“loadModulesConfiguration”方法会搜索所有配置好的模块的“etc”文件夹,寻找以传入的参数为名字的文 件,在这个例子中是“system.xml”。Magento有很多不同的配置文件,比如api.xml, wsdl.xml, wsdl2.xml, convert.xml, compilation.xml, install.xml。你可以为你创建的模块创建这些配置文件。

添加一个标签页

我们首先在后台系统管理页面添加一个标签页(Tab)。标签页就是后台“System->Configuration”页面左侧的导航栏。默 认的标签页有General,Catalog,Customers,Sales,Services等等。我们来创建一个新的标签页叫做“Hello Config”。创建如下文件
Location: app/code/local/Zhlmmc/Helloworld/etc/system.xml




99999



我们来解释一下各个节点(Tag)的意思。【译者注:由于Tab和Tag中文翻译都是标签,所以这里我把Tag翻译成节点,以免混淆】 “”就是我们要添加的标签页的定义节点,“helloconfig”是节点的ID。你可以任意命名这个ID,但是 必须全局唯一,也就是不能和别人用同样的ID。这个ID是用来唯一标示你的标签页的。“module=helloworld”,意思是这个标签页属于哪个 模块。“

打开后台“System->Configuration”,你会看到如下错误
Fatal error: Class 'Mage_Helloworld_Helper_Data' not found in….

Magento Helper简介

正如许多其他的PHP MVC系统一样,Magento也有帮助类(Helper Classes)。这些类用来提供一些不适合放在模型,视图或者控制器中的功能。Magento的帮助类也是采用分组类名的机制。也就是说我们可以覆盖默 认的帮助类,同时我们需要在config.xml中指定帮助类的基类名。

Magento系统默认模块有一个默认的帮助类。正如我们上面的异常显示,我们的Helloworld模块并没有指定一个默认的帮助类。下面让我们来添加一个。修改config.xml
File: app/code/local/Zhlmmc/Helloworld/etc/config.xml
<!– … –>

<!– … –>


Zhlmmc_Helloworld_Helper


<!– … –>

<!– … –>
你现在应该对这类配置相当熟悉了。“”节点就是模块的名字,“”就是帮助类的基类名,命名方式如下
Packagename_Modulename_Helper
帮助类是通过全局对象Mage的静态方法“helper”来装载的。
Mage::helper('helloworld/foo')
根据我们的配置,上面这行代码将会装载以下类
app/code/local/Zhlmmc/Helper/Foo.php
class Zhlmmc_Helloworld_Helper_Foo
我们上面说过Magento默认每个模块有一个帮助类“data”
Mage::helper('helloworld');
Mage::helper('helloworld/data');
上面这两行代码是等价的,都会装载以下类
app/code/local/Zhlmmc/Helper/Data.php
class Zhlmmc_Helloworld_Helper_Data
下面我们来创建我们的帮助类
File: app/code/local/Zhlmmc/Helper/Data.php
class Zhlmmc_Helloworld_Helper_Data extends Mage_Core_Helper_Abstract
{
}
清空Magento缓存,重新装载页面,你会发现错误不见了,但是我们的标签页还是没有出来。如果你好奇帮助类究竟能干什么,建议你去看看“Mage_Core_Helper_Abstract”类。

添加新的段

好了,帮助类的介绍到此结束。下面我们来看看为什么我们的标签页不显示出来。在Magento中,每一个标签页都包含很多段(section)。举 个例子,“Advanced”标签页默认包含“Admin, System, Advanced, Developer”四个段。如果一个标签页不包含任何段,那么这个标签页不会被显示出来。下面我们在system.xml中添加 “

”节点
Location: app/code/local/Zhlmmc/Helloworld/etc/system.xml




99999





helloconfig
text
1000
1
1
1



这里有些节点你应该很熟悉,就不多解释了,来讲讲以前没见过的。

什么是

和前面的相似,这个节点是用来唯一标示你的段,“helloworld_options”就是段的ID,可以随意取名,只要不重复就好。

什么是

这个节点有点搞。“”在配置文件的其他部分有用(稍后会讲),放在这里其实没什么作用。但是核心模块在此处的配置文件都包含这个节点,所以我们也把它添加进去。

什么是,< show_in_website />,

这些节点的值是布尔类型的,0或者1。这些标签是用来控制在不同的环境下,当前段是否应该显示。

好了,我们已经配置好段了,清空缓存,再一次刷新页面,你应该看到“HELLO CONFIG”标签页显示出来了。

访问控制

如果你刚才点了我们创建的标签页下面的“Hello World Config Options”,你大概会很失望。什么都没有显示出来,连左边的导航栏都没有了。这是因为“Adminhtml”在权限控制列表(Access Control List, ACL)中找不到我们创建的段的权限信息。【译者注:Adminhtml就是Magento的后台管理系统,属于Magento的一个核心模块】

ACL是一个很复杂的话题,但是我会介绍一些最基本的概念,以便于理解Magento的权限控制。这部分内容和上下文关系不大,如果你不感兴趣,可以直接跳到本节结尾,复制一段XML到你的config.xml就行了。

在Magento中,对于有些资源的访问时有限制的。用户必须先经过认证才能访问相关资源。在这里,资源(Resource)是一个广义的概念,它可能是 指一个页面,也可能是一个功能。Magento的系统配置功能(System Config)就是需要认证才能访问的资源。

任何一个资源都是通过一个URI来标识。比如说“web”配置段(属于后台管理General标签页)的URI是
admin/system/config/web
我们“helloworld_options”段的URI是
admin/system/config/helloworld_options
当一个用户访问一个受保护的资源的时候,后台管理系统(Adminhtml)的执行控制器会执行以下步骤

  1. 为用户正在访问的资源生成一个URI
  2. 根据ACL系统检查该用户是否有权限访问指定的资源
  3. 如果用户拥有访问权限,那么进行用户指定的操作。否则,跳转到相应的错误页面(也可能是停止操作或者显示空白页面)。
    如果你去“System -> Permissions -> Roles”页面,点击“Add New Role”按钮,你会看到所有系统的资源都以树形结构显示在页面上。

添加ACL权限

刚才说ACL中没有我们配置段的信息,那么我们来创建一个。请注意,如果你是创建一个新的段,那么你需要创建一个新的权限,如果你在已有的段上添加内容,你不需要创建权限。

在config.xml中,添加以下内容
File: app/code/local/Zhlmmc/Helloworld/etc/config.xml

<!– … –>









Store Hello World Module Section 让我们来分析一下这段代码。所有的资源定义都包含在如下代码中 节点下面,每一个子节点都是URI的一部分,比如 代表URI admin/system 最后一个节点 Store Hello World Module Section 这里的内容将会在后台权限管理的时候显示出来,也就是我们定义的权限的名字。 <p>清空Magento缓存,刷新页面,你应该能看到我们创建的配置段了,标准的后台管理页面,但是主体内容是空的,只有一个“Save Config”按钮。你可能需要重新登录后台管理才能看到正确的页面。那是因为后台管理有一些额外的缓存。【译者注:我们添加了权限以后,管理员是默认拥 有该权限的,所以我们用管理员登录后台管理系统就能访问我们创建的段】</p> <p>请注意,不懂事出于什么原因,Magento把<adminhtml />部分从全局配置中删掉了。所以,我们不能用之前创建的Configviewer来查看这部分内容。我正在研究Magento把<adminhtml />存在哪里了。</p> <h4 id="添加组"><a href="#添加组" class="headerlink" title="添加组"></a>添加组</h4><p>【译者注:按照逻辑,这里应该讲的内容是添加选项。Mageto中,选项是按照组(Group)来划分的,所以我们在添加选项之前得先添加组。】修改system.xml<br>Location: app/code/local/Zhlmmc/Helloworld/etc/system.xml<br><config><br><tabs><br><helloconfig translate="label" module="helloworld"><br><label>Hello Config</label><br><sort_order>99999</sort_order><br></helloconfig><br></tabs><br><sections><br><helloworld_options translate="label" module="helloworld"><br><label>Hello World Config Options</label><br><tab>helloconfig</tab><br><frontend_type>text</frontend_type><br><sort_order>1000</sort_order><br><show_in_default>1</show_in_default><br><show_in_website>1</show_in_website><br><show_in_store>1</show_in_store><br><groups><br><messages translate="label"><br><label>Demo Of Config Fields</label><br><frontend_type>text</frontend_type><br><sort_order>1</sort_order><br><show_in_default>1</show_in_default><br><show_in_website>1</show_in_website><br><show_in_store>1</show_in_store><br></messages><br></groups><br></helloworld_options><br></sections><br></config><br>这里也没什么好解释的。刷新一下页面看看你就什么都明白了。</p> <h4 id="添加配置选项"><a href="#添加配置选项" class="headerlink" title="添加配置选项"></a>添加配置选项</h4><p>最后,我们要添加每一个单独的配置选项。配置选项是以<fields />节点的形式添加到<messages />节点下面的。<br><!– … –><br><messages translate="label"><br><label>Demo Of Config Fields</label><br><frontend_type>text</frontend_type><br><sort_order>1</sort_order><br><show_in_default>1</show_in_default><br><show_in_website>1</show_in_website><br><show_in_store>1</show_in_store><br><fields><br><hello_message><br><label>Message</label><br><frontend_type>text</frontend_type><br><sort_order>1</sort_order><br><show_in_default>1</show_in_default><br><show_in_website>1</show_in_website><br><show_in_store>1</show_in_store><br></hello_message><br></fields><br></messages><br><!– … –><br>这里有一个节点需要说明,“<frontend_type>”,刚才说这个节点没什么用。但是这里有用了,这个节点说明了这个选项的数据类 型。你可以把它换成别的类型,比如“time”。这里支持大部分默认的Varien定义的数据类型(lib/Varien/Data/Form /Element)。这个有点像是工厂(Factory)设计模式。让我们把类型改成“select”。你会看到一个下拉框,但是没有选项。我们来添加选 项。首先我们要添加一个源模型(Source Model)<br><hello_message><br><label>Message</label><br><frontend_type>select</frontend_type><br><!– adding a source model –><br><source_model>helloworld/words</source_model><br><sort_order>1</sort_order><br><show_in_default>1</show_in_default><br><show_in_website>1</show_in_website><br><show_in_store>1</show_in_store><br></hello_message><br>“<source_model>”定义了源模型的URI。和我们以前创建的模型一样,源模型也是一个模型,为“select”提供了默认的数据。我想我不说你也明白,根据这里的URI定义,我们要创建以下文件<br>File: app/code/local/Zhlmmc/Helloworld/Model/Words.php<br>class Zhlmmc_Helloworld_Model_Words<br>{<br>public function toOptionArray()<br>{<br>return array(<br>array('value'=>1, 'label'=>Mage::helper('helloworld')-><strong>('Hello')),<br>array('value'=>2, 'label'=>Mage::helper('helloworld')-></strong>('Goodbye')),<br>array('value'=>3, 'label'=>Mage::helper('helloworld')-><strong>('Yes')),<br>array('value'=>4, 'label'=>Mage::helper('helloworld')-></strong>('No')),<br>);<br>}<br>}<br>源模型提供了一个方法“toOptionsArray”,返回的数据时用来填充我们之前定义的配置选项的。这个方法在运行时会被“initFields”调用。“initFields”在以下类中定义<br>app/code/core/Mage/Adminhtml/Block/System/Config/Form.php<br>我们这里调用了帮助类的翻译函数(__)来获取数据。虽然不是很必要,但调用翻译函数总是一个好习惯。说不定哪天你要将模块翻译成日文呢。【译者注:值得 注意的是我们这里创建的模型不需要继承任何父类,只需要拥有“toOptionArray”方法就可以了。我觉得这个很不科学,起码要继承一个接口吧】</p> <h4 id="在已有的配置段或者组中添加数据"><a href="#在已有的配置段或者组中添加数据" class="headerlink" title="在已有的配置段或者组中添加数据"></a>在已有的配置段或者组中添加数据</h4><p>除了新建一个标签页,或者配置段,你也可以利用已有的标签页和配置段,向里面添加内容。比如我们添加以下代码到system.xml<br>File: app/code/local/Zhlmmc/Helloworld/etc/system.xml<br><config><br><!– … –><br><sections><br><!– … –><br><general><br><groups><br><example><br><label>Example of Adding a Group</label><br><frontend_type>text</frontend_type><br><sort_order>1</sort_order><br><show_in_default>1</show_in_default><br><show_in_website>1</show_in_website><br><show_in_store>1</show_in_store><br></example><br></groups><br></general><br><!– … –></p> </section> </config> 刷新页面,你会在“General”标签页下面看到一个新的组,叫做“Example of Adding a Group”。 <h4 id="如何获得配置数据"><a href="#如何获得配置数据" class="headerlink" title="如何获得配置数据"></a>如何获得配置数据</h4><p>到目前为止,我们只是讲了如何设置Magento,可以让用户可以配置我们的模块。现在让我们来看看如何获取用户的配置数据。<br>Mage::getStoreConfig('helloworld_options/messages/hello_message');<br>上面这行代码就可以获取我们上面配置的那个“select”选项的数据。这个函数的参数是我们要获取的数据的URI,格式如下<br>section_name/group_name/field_name<br>你也可以通过以下代码来获取一个组或者段的所有值<br>Mage::getStoreConfig('helloworld_options/messages');<br>Mage::getStoreConfig('helloworld_options');<br>最后,如果你想获取针对某个特定店面(store)的数据,你可以传入store ID<br>Mage::getStoreConfig('helloworld_options',1);</p> <h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>这一章我们讲了如何在Magento的后台管理中添加个性化的配置。我们也顺便介绍了帮助类的使用和ACL基础。这里最重要的内容是后台配置的层级 结构,标签页包含了配置段,配置段包含了组,组包含了配置选项。我们将在以后的章节中介绍系统配置的高级内容,包括自定义格式,数据验证等等。</p> </div> <footer class="article-footer"> <a data-url="https://blog.foolbird.net/1760.html" data-id="clqs2w2qq001bqci536hyh6mo" class="article-share-link">Share</a> <a href="https://blog.foolbird.net/1760.html#disqus_thread" class="article-comment-link">Comments</a> </footer> </div> <nav id="article-nav"> <a href="/1774.html" id="article-nav-newer" class="article-nav-link-wrap"> <strong class="article-nav-caption">Newer</strong> <div class="article-nav-title"> Magento安装教程 </div> </a> <a href="/1758.html" id="article-nav-older" class="article-nav-link-wrap"> <strong class="article-nav-caption">Older</strong> <div class="article-nav-title">深入理解Magento – 第六章 – 高级Magento模型</div> </a> </nav> </article> <section id="comments"> <div id="disqus_thread"> <noscript>Please enable JavaScript to view the <a href="//disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> </div> </section> </section> <aside id="sidebar"> <div id="search-form-wrap"> <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit"></button><input type="hidden" name="sitesearch" value="https://blog.foolbird.net"></form> </div> <div class="widget-wrap"> <h3 class="widget-title">Categories</h3> <div class="widget"> <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%85%B6%E4%BB%96/">其他</a><span class="category-list-count">42</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%AD%98%E6%A1%A3/">存档</a><span class="category-list-count">10</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%AE%A3%E4%BC%A0/">宣传</a><span class="category-list-count">7</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E6%8A%80%E6%9C%AF/">技术</a><span class="category-list-count">47</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E6%97%85%E8%A1%8C/">旅行</a><span class="category-list-count">29</span></li></ul> </div> </div> <div class="widget-wrap"> <h3 class="widget-title">Archives</h3> <div class="widget"> <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2023/12/">December 2023</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2020/01/">January 2020</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/12/">December 2018</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/08/">August 2018</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/12/">December 2017</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/12/">December 2016</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/12/">December 2015</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/09/">September 2015</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/07/">July 2015</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/05/">May 2015</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/04/">April 2015</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/01/">January 2015</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/06/">June 2014</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/05/">May 2014</a><span class="archive-list-count">3</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/10/">October 2013</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/09/">September 2013</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/07/">July 2013</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/04/">April 2013</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/03/">March 2013</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/01/">January 2013</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2012/11/">November 2012</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2012/10/">October 2012</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2012/09/">September 2012</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2012/03/">March 2012</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2012/01/">January 2012</a><span class="archive-list-count">3</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2011/12/">December 2011</a><span class="archive-list-count">7</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2011/11/">November 2011</a><span class="archive-list-count">8</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2011/10/">October 2011</a><span class="archive-list-count">15</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2011/07/">July 2011</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2011/06/">June 2011</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2011/03/">March 2011</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2011/02/">February 2011</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2010/10/">October 2010</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2010/03/">March 2010</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2010/01/">January 2010</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2009/08/">August 2009</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2009/06/">June 2009</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2008/12/">December 2008</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2008/10/">October 2008</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2008/09/">September 2008</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2008/08/">August 2008</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2008/05/">May 2008</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2008/04/">April 2008</a><span class="archive-list-count">6</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2007/12/">December 2007</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2007/11/">November 2007</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2007/09/">September 2007</a><span class="archive-list-count">8</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2007/07/">July 2007</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2007/06/">June 2007</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2007/05/">May 2007</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2007/03/">March 2007</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2007/02/">February 2007</a><span class="archive-list-count">11</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2007/01/">January 2007</a><span class="archive-list-count">6</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2006/12/">December 2006</a><span class="archive-list-count">4</span></li></ul> </div> </div> </aside> </div> <footer id="footer"> <div class="outer"> <div id="footer-info" class="inner"> © 2006 - 2023 王默 <a href="http://beian.miit.gov.cn/" target="_blank">吉ICP备13000316号-4</a> </div> </div> </footer> </div> <nav id="mobile-nav"> <a href="/" class="mobile-nav-link">Home</a> <a href="/archives" class="mobile-nav-link">Archives</a> <a href="/history" class="mobile-nav-link">History</a> <a class="mobile-nav-link" href="/atom.xml" title="RSS Feed">RSS</a> </nav> <script> var disqus_shortname = 'makerwang'; var disqus_url = 'https://blog.foolbird.net/1760.html'; (function(){ var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js'; (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); })(); </script> <script src="/js/jquery.min.js"></script> <link rel="stylesheet" href="/fancybox/jquery.fancybox.css"> <script src="/fancybox/jquery.fancybox.pack.js"></script> <script src="/js/script.js"></script> </div> </body> </html>