¶ 在家寻找外星人寻求帮助

2011-10-13 13:13

接触未来的现实版

俺收到了这封信:


SETI@home [email protected]
发件人当地时间	发送时间 17:24 (GMT-07:00)。发送地当前时间:上午6:17。 ✆
回复	[email protected]
主题	SETI@home Needs Your Help

Dear Zoom.Quiet:

SETI@home needs your help!

Green Bank Telescope In the last year, SETI@home has made great steps forward thanks to the generosity of volunteers like you. Earlier this year we were able to use the Green Bank Telescope (pictured) in West Virginia to expand our search to include the nearly 100 potentially habitable planets found by the Kepler Mission. We've also re-observed seventy two of the 102 sources of unidentified radio pulses found with our Astropulse search. We hope to observe the remaining sources soon. While it's likely that these pulses are a natural phenomenon, we don't yet know what we will find. Data from both these projects have arrived or are on their way to Berkeley and will be sent to our volunteers in the coming months. Without the support of user donations, these major new extensions to the SETI@home experiment would not have been possible.

Though the SETI@home experiment has been active for over eleven years, we are still branching out and exploring new scientific directions. As you may know, the data that your computer analyzes comes principally from the Arecibo radio telescope in Puerto Rico. While Arecibo is an immensely powerful telescope, it cannot see the entire sky. In the past we have been able to perform short duration observations at the Green Bank Telescope. But in the coming year, we plan to start continuous collection of data at the Green Bank Telescope, allowing us to listen in on parts of the sky that, up until now, we have not been able to reach.

We're also in the process of adding a new search algorithm to the SETI@home application. This new algorithm, called autocorrelation, will make us sensitive to certain broad band or spread spectrum transmissions without predicting their characteristics beforehand. No SETI sky survey has utilized this type of algorithm before.

SETI@home has always been a collaborative effort on a global scale; there is no other project on Earth that is quite as dependent on the help and contributions of the citizens of Earth at-large. In order to keep SETI@home up and running, as well as accomplish this year's scientific goals, we need your help. To make a secure tax-deductible donation click here, which will take you to a page of instructions on how to donate online or through mail via check. Any amount that you are willing to donate this holiday season would be a great help. Your contribution will not only allow SETI@home to continue to run as it has for the past eleven years, but also provide the opportunity to expand the search for intelligent life in exciting new directions. These efforts represent our best chance at answering the ever-elusive question: Are we alone?

Thank you for your support and continuing dedication to SETI@Home.

Sincerely,

Dr. Eric Korpela, Project Scientist

迷妄

SETI@home 这是多么浪漫的项目哪,都出现在不少网络小说中的科学项目; 就这么没了,卡尔小说中那些私人赞助并没有如期出现...

强大如美国,也要放弃科学的终极追求了嘛...

好在科学家有无数方法可以渡过经济危机,点击捐助 目前只要几万刀,就可以低烈度的继续寻找外星人了...


动力源自::txt2tags


§ 写于: Thu, 13 Oct 2011 | 永久链接;源文: rdf ,rss ,raw | 分类: /Quiet/SiFi §
[MailMe] [Print] Creative Commons License

作品Zoom.Quiet创作,采用知识共享署名-相同方式共享 2.5 中国大陆许可协议进行许可。 基于zoomquiet.org上的作品创作。

¶ 首届PyCon中国大会发动!

2011-10-10 10:10

大会

世界 Python 爱好者的顶级盛会 —— PyCon 大会将首次在中国举办!本次大会由(Python 软件基金会下的)PyCon.Org 正式授权 GTUG、TopGeek、CPyUG 等社区联合举办,由 Python 作者 Guido van Rossum 及其所在的 Google 公司提供关键支持。

本次大会云集了国内外最为杰出的 Python 开发者,国内 Python 领域的领军人物几乎悉数到场、作为 Python 重镇的各大知名公司几乎无一缺席,所有嘉宾都承诺将自己压箱底的 Python 绝活呈现给大家!沈游侠也会在大会上进行题为《Python,通向未来之路》的纯技术演讲,欢迎捧场。 12 月,让我们聚首上海! 大会订票已经开始 http://pycon.51qiangzuo.com 手速一定要快哦!

会议为期两天(12 月 3 日至 4 日),票价 60¥,全部用于会议期间的就餐费用,其余大会所有费用及礼品主要由 Google 等公司承担赞助。作为国内最大的赞助者,我们也同样很荣幸能够服务于广大中国 Python 爱好者。

ps:

感思

N久前就开始义务的狂热的不断的推广 Python 了:

  • 070322-introPy/
  • 100820-introPy/

    PyCon - PythonInfo Wiki 2003开始,每年举行一次, 后来,随着 Python 的发展,Google 的崛起,每年一次,已经无法满足全球 Python 程序猿的现摆了, 于是,每年,各国都有 PyCon 授权的正式大会来Party HIGH 一下, Pycon Asia Pacific2010 在新加坡也整起来了,亲历了一下,很爽; 只是没想到,今年,中国说搞就搞起来了!

    虽然 Python 在中国,社区不少,但是没有 JAVA/.NET/Ruby 等那么趁钱,光鲜, 大家都在自个儿happy 的用,不怎么出来吼; 但是,在中国的 Python 程序猿真的都很NB 哪, 不出来吼,整得是个NB社区样儿,学生们可不屑来学习的哪.

    好了,夸了 的定期FB聚会, 大家一喝高了,就有了冲动,一冲动就成了...

    其实我们玩的真不差了,相比国际上的玩法,有正式舞台了,多吼一吼,有益身心的!

    反正,俺一定要出台了,大家也尽力来哈!

动力源自::txt2tags


§ 写于: Mon, 10 Oct 2011 | 永久链接;源文: rdf ,rss ,raw | 分类: /Zen/pythonic §
[MailMe] [Print] Creative Commons License

作品Zoom.Quiet创作,采用知识共享署名-相同方式共享 2.5 中国大陆许可协议进行许可。 基于zoomquiet.org上的作品创作。

¶ ScrapBook辅助工具之expidxlevels

2011-09-08 13:13

1. 不折腾要死星人

嗯嗯嗯,从,,, 20041214101930 开始,坚持使用SCRAPBOOK :: Firefox Extension 进行离线网页的收集和整理了;

  • 一直很爽,而且内置的导出功能,可以一键将本地收集的网页通过一个标准的框架页面,用树状索引进行发布;
  • 使用 rsync 等等文件同步小工具,就可以发布一个静态的表述自个儿关注领域技术的纯资料网站了!
  • 其实一直以来就发布有这类两个网站:
  • 好处是那些优秀的文章,即使原文网站死了,依然在俺这儿原样可查,
  • 问题是:
    • 导出的那个索引树,随着时间的积累,已经大到无法忍受了!
    • 比如说, floss.zoomquiet.org 的树,包含 2万多节点,自身体积已经超过5M
    • 有网友吼,用 Chrome 都无法打开!
所以:
  • 得想招精简如此多节点的索引树了,,,
  • 为了时不时,在俺这儿打捞历史文章的亲们...

1.1. scraptools

所以,有了 ZoomQuiet / scraptools — Bitbucket

其中的 expidxlevels.py 就是专门进行自动索引化简的...

1.1.1. RDF

以前在相关讲演中吼过,选择 SCRAPBOOK :: Firefox Extension的好点之一,就是有标准的XML 数据输出,好进行二次处理

设想:
  • scrapbook.rdf (自动生成的记录树关系的RDF)进行合理解析
  • 整理成分级索引页面就可以解决单一索引的巨大加载问题了
杯具:
  • TMD没有一种XML解析库对付的了RDF!

scrapbook.rdf 的设计很简洁:

  • 根节点,索引各个 li
    
      <RDF:Seq RDF:about="urn:scrapbook:root">
        <RDF:li RDF:resource="urn:scrapbook:item20091114162455"/>
        <RDF:li RDF:resource="urn:scrapbook:item20050206112141"/>
      </RDF:Seq>
    
  • 每个 li 也可能是一组 Seq
    
      <RDF:Seq RDF:about="urn:scrapbook:item20070212000600">
        <RDF:li RDF:resource="urn:scrapbook:item20070212000504"/>
        <RDF:li RDF:resource="urn:scrapbook:item20070212000555"/>
      </RDF:Seq>
    
  • 不论 Seq 自身,还是真正的页面,都有一个描述节点来记录详情
    
      <RDF:Description RDF:about="urn:scrapbook:item20051216104753"
                       NS2:id="20051216104753"
                       NS2:type=""
                       NS2:title="吉卜力的新作也用blog宣傳"
                       NS2:chars="UTF-8"
                       NS2:comment=""
                       NS2:icon=""
                       NS2:source="http://www.bigsound.org/portnoy/weblog/001318.html" />
    
  • 如果只是分隔线,就是:
    
      <NC:BookmarkSeparator RDF:about="urn:scrapbook:item20091113232313"
                       NS2:id="20091113232313"
                       NS2:type="separator"
                       NS2:title=""
                       NS2:chars=""
                       NS2:comment=""
                       NS2:icon=""
                       NS2:source="" />
    

    那么一切就应该从 <RDF:Seq RDF:about="urn:scrapbook:root"> 节点开始爬就好的了,,,

FT!:
  • 不论内置的 xml.dom / xml.etree.ElementTree 还是伟大的 lxml
    • 都不支持根据 XML 节点的属性进行搜索!
    • 即使可以用 XPath 的算子过滤://NC[@RDF:about = "urn:scrapbook:root"] ,但是,没有库支持完全功能的XPath!
    • 俺总不能用 XSLT 先写好过滤,然后再调用支持 XSLT 的浏览器获得中间结果給 Py 用吧?!
  • 好的,有一堆 RDF 专用解析器
  • 可是,对于俺,这么简单的需求,就是没有简单的处置方法嘛?!
解决:
  • 冷静了一下,俺只是要进行简单的数据处理,并不一定要真的对 RDF 进行语义上的理解哪?!
  • XML 自古就有一种原始的,条带化基于事件的处理模型,曰 SAX
  • Py 内置有最简单的 expat库:
  • 跟着样例快速完成了处理部分,速度也非常的快

    
    def start_element(name, attrs):
        if "RDF:Seq" == name:
            CF.IS_SEQ = 1
            CF.IS_DESC = 0
            if "urn:scrapbook:root" == attrs['RDF:about']:
                #print 'ROOT element:', name, attrs
                CF.IS_ROOT = 1
                CF.DICTRDF['ROOT']['id'] = attrs['RDF:about'].split(":")[-1]
                CF.CRTID = attrs['RDF:about'].split(":")[-1]
                CF.DICTRDF['ROOT']['li'] = []
            else:
                CF.IS_ROOT = 0
                CF.CRTID = attrs['RDF:about'].split(":")[-1]
                CF.DICTRDF['SEQ'][CF.CRTID] = []
        else:
            CF.IS_SEQ = 0
            if "RDF:li" == name:
                CF.IS_DESC = 0
                CF.IS_LI = 1
                if CF.IS_ROOT:
                    CF.DICTRDF['ROOT']['li'].append(attrs['RDF:resource'].split(":")[-1])
                else:
                    CF.DICTRDF['SEQ'][CF.CRTID].append(attrs['RDF:resource'].split(":")[-1])
            elif "RDF:Description" == name:
                CF.IS_DESC = 1
                CF.IS_LI = 0
                CF.CRTID = attrs['RDF:about'].split(":")[-1]
                CF.DICTRDF['DESC'][CF.CRTID] = {
                    'id':attrs['NS2:id']
                    ,'type':attrs['NS2:type']
                    ,'title':attrs['NS2:title']
                    ,'source':attrs['NS2:source']
                    ,'chars':attrs['NS2:chars']
                    ,'icon':attrs['NS2:icon']
                    ,'comment':attrs['NS2:comment']
                    }
    
    
技巧:
  • 就是用一堆判定,将有限的情况进行区分
  • 然后丢到个字典中,供给后续处理

    
    {"ROOT":{'id':'','li':[]}
    ,"SEQ":{'item...':[]
        ,,,}
    ,"DESC":{'item...':{'id':''
            ,'type':"" # folder||separator
            ,'icon':''
            ,'title':''
            ,'source':''
            ,'chars':''
            ,'comment':''
            }
        ,,,
        }
    }
    

1.1.2. yeild

好的,有了 RDF 正确的结构关系数据后,怎么优雅的输出成分层的索引页面?!

  • 俺习惯用内置的文本模板功能,通过纯文本的嵌套完成 html 的输出
  • 结果,发现,俺的网页整理到不同深度的目录中
    • 要想进行递归式的树状生成,很容易引发递归过深,Py 崩溃的现象

// scrapbook/chrome/scrapbook.jar->content/scrapbook/output.js 中
	processRescursively : function(aContRes)
	{
		this.depth++;
		var id = ScrapBookData.getProperty(aContRes, "id") || "root";
		this.content += '<ul id="folder-' + id + '">\n';
		var resList = ScrapBookData.flattenResources(aContRes, 0, false);
		for (var i = 1; i < resList.length; i++) {
			this.content += '<li class="depth' + String(this.depth) + '">';
			this.content += this.getHTMLBody(resList[i]);
			if (ScrapBookData.isContainer(resList[i]))
				this.processRescursively(resList[i]);
			this.content += "</li>\n";
		}
		this.content += "</ul>\n";
		this.depth--;
	},

  • SCRAPBOOK中的原生处理是硬递归的哪,,,
  • Py 有优雅的迭代式,但是不那么容易用起来:
    • yeild 的递归输出问题
    • 引发了社区列表讨论,结果获得的经验很简单:
      • 所有想返回的,都用 yeild 包装上!

于是,一切安定团结了,,,

用 shell 包装个命令,想发布本地 SCRAPBOOK 仓库时,一键完成!

1.2. TODO

当然总是有不如意的,留存以后,或是有心人完善了:

  1. 美化平面索引页面
    1. 排版和颜色
    2. CSS 限宽效果用JS 进行动态扩展
  2. 自动对所有抓取的页面,嵌入原始链接的提示
  3. 对整体仓库生成 site map 帮助 google 收录 ...

2. 时间帐单

  1. ~0.01h 起意,要折腾
  2. 0.5h rdf 理解
  3. 1h ElementTree 尝试
  4. 1h lxml 尝试
  5. ~2h RDF 解析模块收集
  6. ~1h rdflib 尝试
  7. ~0.5h 冷静
  8. ~0.5h expat完成解析
  9. ~1h 根索引页面输出
  10. ~2.5h 递归和迭代尝试
  11. ~2h 获得社区反馈,完成所有功能

合计,~13小时,哗,,,,大大超出原先半天的预计,纠其原因:

  1. 对XML体系的变态缺乏足够的敬畏
  2. 对递归的理解一直不扎实

事实证明:嘦不经过真实编程的理解,基本都是误解


动力源自::txt2tags


§ 写于: Thu, 08 Sep 2011 | 永久链接;源文: rdf ,rss ,raw | 分类: /utility/py4xml §
[MailMe] [Print] Creative Commons License

作品Zoom.Quiet创作,采用知识共享署名-相同方式共享 2.5 中国大陆许可协议进行许可。 基于zoomquiet.org上的作品创作。

¶ py2pre.py

2011-09-07 14:00

# -*- coding: utf-8 -*-
"""py - html Parser
    - refactory py2pre.py from xhtml.py

Copyright (c) 2011 Zoom.Quiet 
All rights reserved.

Redistribution and use in source and binary forms are permitted
provided that the above copyright notice and this paragraph are
duplicated in all such forms and that any documentation,
advertising materials, and other materials related to such
distribution and use acknowledge that the software was developed
by the zoomquiet.org.  The name of the
University may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.


"""


## Leo: tab_width=-4 page_width=80
__version__ = "v11.09.7"
__author__ = 'Zoom.Quiet '
__url__ = "http://blog.zoomquiet.org/pyblosxom/techic/PyBlosxom/plugins/py2pre.html"
__description__ = ".py export hmtl entry with syntaxhighlighter."

#from Pyblosxom import tools

def cb_entryparser(entryparsingdict):
    """
    Register self as plain file handler
    """
    entryparsingdict["py"] = parse
    return entryparsingdict
def parse(filename, request):
    #import os
    entrydata = {}
    source = open(filename, "r").read()
    #print filenames
    body = '
%s
' % source entrydata = {'body' : body ,'title' : filename.split("/")[-1] } return entrydata

§ 写于: Wed, 07 Sep 2011 | 永久链接;源文: rdf ,rss ,raw | 分类: /techic/PyBlosxom/plugins §
[MailMe] [Print] Creative Commons License

作品Zoom.Quiet创作,采用知识共享署名-相同方式共享 2.5 中国大陆许可协议进行许可。 基于zoomquiet.org上的作品创作。

¶ 升级到PyBlosxom 1.5rc3

2011-09-07 12:23

1. 不折腾要死星人

嗯嗯嗯,一清点,居然这么长时间没有发布正式点的 blog 了哪!

  • 想恢复每周的心得汇报,但是,俺有强迫症!
    • PyBloxom 非常好玩,好用
    • 但是,一直不甚完美
    • 不过,这也是俺喜欢她的原因~ 所有不完美之处,都可以自行 hacking!
所以:
  • 安装了 Disqus
  • 升級了 SyntaxHighlighter
  • 修复了 py.py
  • 修复了内置的分类索引

1.1. 评注

一直以来,PyBlosxom 没有内置一个靠谱的评注系统,是个囧事儿,

  • 现在,官方也想明白了,都 2.0时代了,不纠结了
  • Comments — PyBlosxom v1.5 documentation
    • 直接建议上 DISQUS
    • 为什么不呢?
      好:
          + 安装简单
          + 内置spam 管理
          + 支持提醒,回答,以及其它功能
      坏:
          - 作为web服务,没有全权控制
          - 可能难以迁移到其它服务/插件 ~ 虽然有评注的导出功能
      

      反正,俺用了,,很轻松,,而且支持多种 SSO 认证!

1.2. SyntaxHighlighter

之前,俺为了节省流量,使用了 官方提供的 hosting...

  • 结果伟大的功夫网,总是令展示效果不理想!
  • 现在想通了,直接升级 到 SyntaxHighlighter 3.0.83
  • 并指向本地的各种资源
  • 比较贴心的是,这次有了 Dynamic Brush Loading
    • 不用象以往,逐一JS 的加载了

      
      function path(){
          var args = arguments;
          var result = [];
          for(var i = 0; i < args.length; i++){
            result.push(args[i].replace('@', '/pybshare/syntaxhighlighter_3.0.83/scripts/'));
            };
          return result;
          };
      SyntaxHighlighter.autoloader.apply(null, path(
          'applescript            @shBrushAppleScript.js',
          'bash shell             @shBrushBash.js',
          'css                    @shBrushCss.js',
          'diff patch pas         @shBrushDiff.js',
          'erl erlang             @shBrushErlang.js',
          'js jscript javascript  @shBrushJScript.js',
          'text plain             @shBrushPlain.js',
          'py python              @shBrushPython.js',
          'sass scss              @shBrushSass.js',
          'sql                    @shBrushSql.js',
          'xml xhtml xslt html    @shBrushXml.js'
          ));
      
      SyntaxHighlighter.all()
      
PS:
  • 也有更加轻量的 prettify
  • 但是,没有 SyntaxHighlighter 的高亮功能
  • 而且,已经和 t2t 深度定制过,使用很好,也就不追赶了,,,

1.3. 插件

1.5 的插件体系好象有所变化,不那么简单的可以理解了,,,

1.3.1. py2pre.py

py2pre.py

意图:
  • 简单的将目录中的 .py 脚本渲染成合适的 html 展示
问题:
解决:
技巧:
  • 直接复用 SyntaxHighlighter 的效能
  • 将所有脚本内容丢到约定的 <pre> 中就好

    
    #...
    def parse(filename, request):
        entrydata = {}
        source = open(filename, "r").read()
        body = '<pre class="brush: python">%s</pre>' % source
        entrydata = {'body' : body
                     ,'title' : filename.split("/")[-1]
                     }
        return entrydata
    
    

1.3.2. cp4idx2category.py

这货不是 PyBlosxom 标准插件,只是发布辅助脚本

问题:
  • 发现使用 pyblosxom-cmd staticrender --config </path/2/config.py> 生成的静态页面,分类索引页面有问题:
    • 正常的分类索引中,只包含目录中一个文章
    • 如果是 非内容目录,比如说py 脚本目录,倒是可以包含所有内容,可页面输出又有乱码
尝试:
  • 吼了列表,没人理
  • 也忘记以前是否正当了
  • 追踪代码:

Traceback (most recent call last):
  File "/usr/local/bin/pyblosxom-cmd", line 25, in <module>
    sys.exit(command_line_handler("pyblosxom-cmd", sys.argv))
  File "/usr/local/lib/python2.6/dist-packages/Pyblosxom/commandline.py", line 466, in command_line_handler
    return f(command, argv)
  File "/usr/local/lib/python2.6/dist-packages/Pyblosxom/commandline.py", line 362, in run_static_renderer
    return p.run_static_renderer(options.incremental)
  File "/usr/local/lib/python2.6/dist-packages/Pyblosxom/pyblosxom.py", line 409, in run_static_renderer
    tools.render_url_statically(config, url, q)
  File "/usr/local/lib/python2.6/dist-packages/Pyblosxom/tools.py", line 940, in render_url_statically
    response = render_url(cdict, url, querystring)
  File "/usr/local/lib/python2.6/dist-packages/Pyblosxom/tools.py", line 983, in render_url
    p.run(static=True)
  File "/usr/local/lib/python2.6/dist-packages/Pyblosxom/pyblosxom.py", line 182, in run
    blosxom_handler(self._request)
  File "/usr/local/lib/python2.6/dist-packages/Pyblosxom/pyblosxom.py", line 947, in blosxom_handler
    renderer.render()
  File "/usr/local/lib/python2.6/dist-packages/Pyblosxom/renderers/blosxom.py", line 330, in render
    content = self.render_content(self._content)
  File "/usr/local/lib/python2.6/dist-packages/Pyblosxom/renderers/blosxom.py", line 273, in render_content
    self.render_template(parse_vars, "story", override=1))
  File "/usr/local/lib/python2.6/dist-packages/Pyblosxom/renderers/blosxom.py", line 370, in render_template
    {"entry": entry, "template": template})
  File "/usr/local/lib/python2.6/dist-packages/Pyblosxom/renderers/blosxom.py", line 405, in _run_callback
    defaultfunc=lambda x:x)
  File "/usr/local/lib/python2.6/dist-packages/Pyblosxom/tools.py", line 780, in run_callback
    output = func(input)
  File "/home/zoomq/workspace/3hg/zoomquiet-default/pyblosoxm/zoomquiet/plugins/preformatter/markdown-plugin.py", line 44, in cb_story
...

日!这么深的调用栈?!


pyblosxom-cmd   命令工具
    |
    +-> commandline.py  解析参数,准备环境
        |
        +-> pyblosxom.py    调用工具
             ^      |
             |      +-> tools.py    组织插件,参数
             |          |
             +----<-----+   嗯嗯嗯?!回调 pyblosxom.py 
             使用 renderer.render() 和动态网站流程一样,输出内容

  • FT! 具体分类目录在哪个环节生成基本找遍不到了,,,因为将所有需要渲染的,都丢到一个列表中了,,
解决:
  • 其实复杂的技术问题,总是有很2的解决方案的
  • 既然难以解决原有的渲染问题,那么 使用期待的页面替换有问题的就KO的哈!
    • 俺的 category_static.py 插件生成的树状索引: category-index.html 很可以
    • 那么对其进行相关裁剪,复制到对应目录中不就得了!?

      先小小的增补一下category_static.py
      
      # ...
      for e in etree[p][1:]:
          body += '<span id="%s" class="indents">%s</span><a href="%s%s.html">%s</a><br>\n'%(
                  "/".join(etree[p][0])
                  ,"..."*len(etree[p][0])
                  ,_baseurl
                  ,e[1]
                  ,e[0]
                  )
      
      
      
  • 在前导空间的span 中增加代表文章所在分类目录的 id

那么 cp4idx2category.py就可以简单的完成了:


# -*- coding: utf-8 -*-
'''
将 category_static.py 生成的树状分类索引页面,复制并修订为各个目录中的 index.html
'''
__version__ = 'cp4idx2category v11.09.7'
__author__ = 'Zoom.Quiet <zoomquiet+pyb at gmail dot com>'

import os
import sys
import re
import shutil

def cp4gen(path):
    IDX = "%s/category-index.html"% path
    p = re.compile("%s\/\d{4}"%path )
    for root, dirs, files in os.walk(path):
        if path == root:
            pass
        elif p.match(root):
            pass
        elif "plugin_info" in root:
            pass
        else:
            aimpath = root.replace(path,"")
            exp = ""
            for i in open(IDX,'r'):
                if '<span id="' in i:
                    if aimpath in i:
                        exp += i
                else:
                    exp += i
            open("%s/index.html"% root,"w").write(exp)
    return

if __name__ == '__main__':      # this way the module can be
    if 2 != len(sys.argv):
        print """ %s usage::
$ python cp4idx2category.py path/2/_static
            |               +- 生成的静态页面入口
            +- 脚本自身
        """ % VERSION
    else:
        path = sys.argv[1]
        cp4gen(path)

只要每次,完成静态整站渲染后,用cp4idx2category.py刷一下,就KO!

1.4. TODO

不断维护的完美之折腾...

PyBlosxom 静态化发布体系:
  1. Hg/Git 的 hooks 开发部署
  2. dot 的自动包含图片热区定义的 t2t 处理
  3. Leo 中的自动化发布脚本按钮

2. 时间帐单

  1. ~0.01h 起意,要折腾
  2. ~.5h SyntaxHighlighter升級
  3. ~2.5h DISQUS 加装,主要是注册和文档查阅耗时
  4. ~1h 列表吼,E文真的很难以表述清楚...
  5. ~1h py2pre.py 重构完成
  6. ~1h cp4idx2category.py 山寨完成
  7. ~1.5h 记录成文

    合计,7小时,哗,,,,

动力源自::txt2tags


§ 写于: Wed, 07 Sep 2011 | 永久链接;源文: rdf ,rss ,raw | 分类: /techic/PyBlosxom §
[MailMe] [Print] Creative Commons License

作品Zoom.Quiet创作,采用知识共享署名-相同方式共享 2.5 中国大陆许可协议进行许可。 基于zoomquiet.org上的作品创作。

¶ plugininfo.py

2011-08-31 23:22

"""
Summary
=======

This plugin is maintained at::

   http://www.bluesock.org/~willg/pyblosxom/

Check that URL for new versions, better documentation, and submitting
bug reports and feature requests.


Usage
=====

This plugin goes through all the plugins you have installed on your blog
and extracts information about the plugin.

To kick it off, the url starts with ``/plugin_info`` .

If there are plugins you want to run that you don't want showing up,
list them in the ``plugininfo_hide`` property of your ``config.py`` file::

   py["plugininfo_hide"] = ["myplugin", "myotherplugin"]

It takes a list of strings.

----

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Copyright 2002-2007 Will Guaraldi

SUBVERSION VERSION: $Id: plugininfo.py,v 2872b22e2ace 2011/10/27 07:08:25 zoomquiet+hg $

Revisions:
2007-07-07 - Converted documentation to restructured text.
2007-05-19 - Brushed up the code, fixed documentation, ...
2005-11-11 - Pulled into another new version control system
1.8 - (26 October, 2005) pulled into new version control system
1.7 - (09 December, 2004) fixed date_head issue and stopped showing 
      docstrings
1.6 - (04 May 2004) added comment handling
1.5 - (18 February 2004) added the ability to "hide" plugins so that
      we don't talk about them
1.4 - (17 February 2004) added alphabetical sorting of plugins and fixed
      num_entries issue
1.3 - (14 July 2003) added $plugincount variable
1.2 - (5/27/2003) minor fixes in the build_entry
"""
import Pyblosxom.plugin_utils
import Pyblosxom.entries.base
import time
import os.path

__author__  = "Will Guaraldi - willg at bluesock dot org"
__version__ = "$Date: 2011/10/27 07:08:25 $"
__url__     = "http://www.bluesock.org/~willg/pyblosxom/"
__description__ = "Shows information about plugins that you're running."

TRIGGER = "/plugin_info"

def verify_installation(request):
    config = request.getConfiguration()

    # check to see if the user has specified the "plugininfo_hide" 
    # property
    if not config.has_key("plugininfo_hide"):
        # the user doesn't have the property set, so we let them know
        # they can set it and it prevents specified plugins from showing
        # up.
        print "Note: You can set 'plugininfo_hide' to hide plugins you " + \
              "don't want showing up."

    else:
        # they do have plugininfo_hide set, so we verify that the value
        # is valid-ish.
        val = config["plugininfo_hide"]

        if not type(val) in [ list, tuple ]:
            print "'plugininfo_hide' must be a list of strings."
            return 0

        for mem in val:
            if not type(mem) == str:
                print "'plugininfo_hide' must be a list of strings."
                return 0
    return 1

def build_entry(request, mem):
    """build_entry(Request, plugin) -> PyBlosxom.entries.base.BaseEntry

    Takes a plugin, extracts information from it, and builds a PyBlosxom
    entry from the results.  It returns the BaseEntry object.
    """
    plugindata = []
    plugindata.append("
")

    # previously we pulled __doc__, but more and more people are storing
    # documentation for the plugin as well as license information--which
    # isn't really what we want to show.  we really want the author, version,
    # and url for the plugin.  currently these are stored in __author__,
    # __version__, and __url__ (though those should be changed to something
    # like VERSION, AUTHOR, and URL so as to avoid confusion with Python
    # special things.
    plugindata.append("AUTHOR: " + str(getattr(mem, "__author__", None)) + "\n")
    plugindata.append("VERSION: " + str(getattr(mem, "__version__", None)) + "\n")
    if hasattr(mem, "__url__"):
        plugindata.append("URL: %s\n" % \
                          (str(mem.__url__), str(mem.__url__)))

    plugindata.append("
") # build a dict of the metadata that generate_entry needs d = { "title": mem.__name__, "absolute_path": TRIGGER[1:], "fn": mem.__name__, "file_path": TRIGGER[1:] + "/" + mem.__name__ } # build the body of the entry body = "".join(plugindata) entry = Pyblosxom.entries.base.generate_entry(request, d, body, None) return entry def cb_prepare(args): request = args["request"] data = request.getData() config = request.getConfiguration() antiplugins = config.get("plugininfo_hide", []) plugins = Pyblosxom.plugin_utils.plugins plugins = [m for m in plugins if m.__name__ not in antiplugins] data["plugincount"] = len(plugins) INIT_KEY = "plugininfo_initiated" def cb_date_head(args): """ If we're showing plugins, then we don't want the date_head templates kicking in--so we block that. """ request = args["request"] data = request.getData() if data.has_key(INIT_KEY): args["template"] = "" return args def cb_staticrender_filelist(args): """ This is test code--trying to work additional bits into the static renderer. """ request = args["request"] filelist = args["filelist"] flavours = args["flavours"] config = request.getConfiguration() antiplugins = config.get("plugininfo_hide", []) plugins = Pyblosxom.plugin_utils.plugins plugins = [m for m in plugins if m.__name__ not in antiplugins] if plugins: for mem in plugins: url = os.path.normpath(TRIGGER + "/" + mem.__name__ + ".") for f in flavours: filelist.append( (url + f, "") ) for f in flavours: filelist.append( (os.path.normpath(TRIGGER + "/index." + f), "") ) def cb_filelist(args): request = args["request"] pyhttp = request.getHttp() data = request.getData() config = request.getConfiguration() if not pyhttp["PATH_INFO"].startswith(TRIGGER): return data[INIT_KEY] = 1 data['root_datadir'] = config['datadir'] config['num_entries'] = 9999 entry_list = [] antiplugins = config.get("plugininfo_hide", []) plugins = Pyblosxom.plugin_utils.plugins plugins = [m for m in plugins if m.__name__ not in antiplugins] pathinfo = pyhttp["PATH_INFO"] # if the browser requested the TRIGGER or TRiGGER/index, then we # kick in and show plugin information for all plugins. if pathinfo == TRIGGER or pathinfo.startswith(TRIGGER + "/index"): plugins.sort(lambda x,y: cmp(x.__name__, y.__name__)) for mem in plugins: entry_list.append(build_entry(request, mem)) return entry_list # the browser requested to see information on a specific plugin. # we need to pull off the flavour that was requested # (if there was one). FIXME - this is a good candidate for a tools # function. pathinfo = pathinfo[len(TRIGGER):] if pathinfo.startswith("/"): pathinfo = pathinfo[1:] if pathinfo.endswith("/"): pathinfo = pathinfo[:-1] filename, ext = os.path.splitext(pathinfo) if ext[1:]: data["flavour"] = ext[1:] d = {} for mem in plugins: d[mem.__name__] = mem # if the browser requested to look at a specific plugin, then # we only show that one. if d.has_key(filename): return [build_entry(request, d[filename])] # if the plugin the browser requested isn't in the list of # plugins, then we return an empty list of entries--PyBlosxom # will show a "that doesn't exist" message for that. return [] # vim: tabstop=4 shiftwidth=4

§ 写于: Wed, 31 Aug 2011 | 永久链接;源文: rdf ,rss ,raw | 分类: /techic/PyBlosxom/plugins §
[MailMe] [Print] Creative Commons License

作品Zoom.Quiet创作,采用知识共享署名-相同方式共享 2.5 中国大陆许可协议进行许可。 基于zoomquiet.org上的作品创作。

¶ zqarchives.py

2011-08-31 23:22

# -*- coding: utf-8 -*-

# vim: tabstop=4 shiftwidth=4
"""
- zoomq 100419 fixed for export month/year with count
Walks through your blog root figuring out all the available monthly archives in
your blogs.  It generates html with this information and stores it in the
$archivelinks variable which you can use in your head or foot templates.

You can format the output with the key "archive_template".

A config.py example:

    py['archive_template'] = '
  • %(m)s/%(y)s
  • ' Displays the archives as list items, with a month number slash year number, like 06/78. The vars available with typical example values are: b 'Jun' m '6' Y '1978' y '78' Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Copyright 2004, 2005 Wari Wahab """ __author__ = "Wari Wahab - wari at wari dot per dot sg" __version__ = "$Id: zqarchives.py,v 2872b22e2ace 2011/10/27 07:08:25 zoomquiet+hg $" __url__ = "http://blog.zoomquiet.org/pyblosxom/techic/PyBlosxom/plugins/zqarchives.html" from Pyblosxom import tools import time, os def verify_installation(request): config = request.get_configuration() if not config.has_key("archive_template"): print "missing optional config property 'archive_template' which " print "allows you to specify how the archive links are created. " print "refer to pyarchive plugin documentation for more details." return 1 class PyblArchives: def __init__(self, request): self._request = request self._archives = None def __str__(self): if self._archives == None: self.gen_linear_archive() return self._archives def gen_linear_archive(self): config = self._request.get_configuration() data = self._request.get_data() root = config["datadir"] archives = {} archive_list = tools.walk(self._request, root) fulldict = {} fulldict.update(config) fulldict.update(data) template = config.get('archive_template', '%(y)s.%(m)s') #%(Y)s-%(b)s #print fulldict["base_url"] for mem in archive_list: timetuple = tools.filestat(self._request, mem) timedict = {} for x in ["B", "b", "m", "Y", "y"]: timedict[x] = time.strftime("%" + x, timetuple) fulldict.update(timedict) if not archives.has_key(timedict['Y'] + timedict['m']): archives[timedict['Y'] + timedict['m']] = [template % fulldict,1] else: archives[timedict['Y'] + timedict['m']][1] += 1 archives[timedict['Y'] + timedict['m']][0] = template % fulldict #print archives #return arc_keys = archives.keys() arc_keys.sort() arc_keys.reverse() yearmonth = {} result = [] #base archives walk and count every year's mounth for key in arc_keys: yearname = key[:-2] if yearname in yearmonth.keys(): yearmonth[yearname][0] += archives[key][1] yearmonth[yearname][1].append(archives[key]) else: yearmonth[yearname] = [archives[key][1],[]] yearmonth[yearname][1].append(archives[key]) #print yearmonth["2007"] mon_keys = yearmonth.keys() mon_keys.sort() mon_keys.reverse() #print mon_keys for year in mon_keys: #print "%s%s"%(year,yearmonth[year][0]) monode = yearmonth[year][1] result.append("
  • %s(%d)
  • "%(fulldict["base_url"],year,year,yearmonth[year][0])) if 1==len(monode): #print "%s%s"%(monode[0][0],monode[0][1]) result.append("
  • %s(%d)
  • "%(monode[0][0],monode[0][1])) else: for m in monode: #print m #print "%s%s"%(m[0],m[1]) result.append("
  • %s(%d)
  • "%(m[0],m[1])) #result.append("%s%s"%(month[0],month[1])) #print result self._archives = '\n'.join(result) def cb_prepare(args): request = args["request"] data = request.get_data() data["archivelinks"] = PyblArchives(request)

  • § 写于: Wed, 31 Aug 2011 | 永久链接;源文: rdf ,rss ,raw | 分类: /techic/PyBlosxom/plugins §
    [MailMe] [Print] Creative Commons License

    作品Zoom.Quiet创作,采用知识共享署名-相同方式共享 2.5 中国大陆许可协议进行许可。 基于zoomquiet.org上的作品创作。

    ¶ zqcategories.py

    2011-08-31 23:22

    # -*- coding: utf-8 -*-
    # vim: tabstop=4 shiftwidth=4
    """
    - 仅仅要求可以根据指定顺序输出分类目录
    
    Walks through your blog root figuring out all the categories you have
    and how many entries are in each category.  It generates html with
    this information and stores it in the $categorylinks variable which
    you can use in your head or foot templates.
    
    You can format the output by setting "category_begin", "category_item",
    "category_end" and properties.
    
    Categories exist in a hierarchy.  "category_start" starts the category listing
    and is only used at the very beginning.  The "category_begin" property begins a 
    new category group and the "category_end" property ends that category group.  
    The "category_item" property is the template for each category item.  Then
    after all the categories are printed, "category_finish" ends the category
    listing.
    
    For example, the following properties will use 
      to open a category,
    to close a category and
  • for each item: py["category_start"] = "
      " py["category_begin"] = "
      • " py["category_item"] = r'
      • %(category)s
      • ' py["category_end"] = "
      " py["category_finish"] = "
    " Another example, the following properties don't have a begin or an end but instead use indentation for links and displays the number of entries in that category: py["category_start"] = "" py["category_begin"] = "" py["category_item"] = r'%(indent)s%(category)s (%(count)d)
    ' py["category_end"] = "" py["category_finish"] = "" There are no variables available in the category_begin or category_end templates. Available variables in the category_item template: variable example datatype ======== ======= ======== base_url http://joe.com/blog/ string fullcategory_urlencoded 'dev/pyblosxom/status/' string fullcategory 'dev/pyblosxom/status/' string (urlencoded) category 'status/' string category_urlencoded 'status/' string (urlencoed) flavour 'html' string count 70 int indent '    ' string Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Copyright 2004, 2005, 2006 Will Guaraldi """ __author__ = "Will Guaraldi - willg at bluesock dot org" __version__ = "$Id: zqcategories.py,v 2872b22e2ace 2011/10/27 07:08:25 zoomquiet+hg $" __url__ = "http://blog.zoomquiet.org/pyblosxom/techic/PyBlosxom/plugins/zqcategories.html" #__url__ = "http://pyblosxom.sourceforge.net/" __description__ = "Builds a list of categories." from Pyblosxom import tools import re, os DEFAULT_START = r'
      ' DEFAULT_BEGIN = r'
      • ' DEFAULT_ITEM = r'
      • %(category)s (%(count)d)
      • ' DEFAULT_END = "
    • " DEFAULT_FINISH = "
    " DEFAULT_ROOT = [] def verify_installation(request): config = request.getConfiguration() if not config.has_key("category_template"): print "missing optional config property 'category_template' which allows " print "you to specify how the category hierarchy is rendered. see" print "the documentation at the top of the pycategories plugin code " print "file for more details." return 1 class PyblCategories: def __init__(self, request): self._request = request self._categories = None config = self._request.getConfiguration() self._baseurl = config.get("base_url", "") self.genCategories() def __str__(self): if self._categories == None: self.genCategories() return self._categories def genCategories(self): config = self._request.getConfiguration() root = config["datadir"] start_t = config.get("category_start", DEFAULT_START) begin_t = config.get("category_begin", DEFAULT_BEGIN) item_t = config.get("category_item", DEFAULT_ITEM) end_t = config.get("category_end", DEFAULT_END) finish_t = config.get("category_finish", DEFAULT_FINISH) #zoomq: configed order by mind the catrgorise root_path_list = config.get("category_root_list", DEFAULT_ROOT) cfgBaseUrl = config.get("base_url", "") form = self._request.getForm() flavour = (form.has_key('flav') and form['flav'].value or config.get('default_flavour', 'html')) #print flavour # build the list of all entries in the datadir output = "" #@others if 0==len(root_path_list): #as default walk and export Categories as word order elist = tools.Walk(self._request, root) output += self._subCategories(elist,root,"") else: for rootCategory in root_path_list: subroot = "%s/%s"%(root,rootCategory) self._baseurl = "%s/%s"%(cfgBaseUrl,rootCategory) elist = tools.Walk(self._request, subroot) output += self._subCategories(elist,subroot,rootCategory) # then we join the list and that's the final string #self._categories = "\n".join(output) self._categories = output def _subCategories(self,elist,root,rootname): config = self._request.getConfiguration() form = self._request.getForm() flavour = (form.has_key('flav') and form['flav'].value or config.get('default_flavour', 'html')) start_t = config.get("category_start", DEFAULT_START) begin_t = config.get("category_begin", DEFAULT_BEGIN) item_t = config.get("category_item", DEFAULT_ITEM) end_t = config.get("category_end", DEFAULT_END) finish_t = config.get("category_finish", DEFAULT_FINISH) # peel off the root dir from the list of entries elist = [mem[len(root)+1:] for mem in elist] # go through the list of entries and build a map that # maintains a count of how many entries are in each # category elistmap = {} for mem in elist: mem = os.path.dirname(mem) elistmap[mem] = 1 + elistmap.get(mem, 0) self._elistmap = elistmap #print self._elistmap # go through the elistmap keys (which is the list of # categories) and for each piece in the key (i.e. the key # could be "dev/pyblosxom/releases" and the pieces would # be "dev", "pyblosxom", and "releases") we build keys # for the category list map (i.e. "dev", "dev/pyblosxom", # "dev/pyblosxom/releases") clistmap = {} for mem in elistmap.keys(): mem = mem.split(os.sep) for index in range(len(mem)+1): p = os.sep.join(mem[0:index]) clistmap[p] = 0 # then we take the category list from the clistmap and # sort it alphabetically clist = clistmap.keys() clist.sort() output = [] indent = 0 output.append(start_t) # then we generate each item in the list for item in clist: itemlist = item.split(os.sep) num = 0 for key in self._elistmap.keys(): if item == '' or key == item or key.startswith(item + os.sep): num = num + self._elistmap[key] if not item: tab = "" else: tab = len(itemlist) * "  " if indent > len(itemlist): for i in range(indent - len(itemlist)): output.append(end_t) elif indent < len(itemlist): for i in range(len(itemlist) - indent): output.append(begin_t) # now we build the dict with the values for substitution d = { "base_url": self._baseurl, "fullcategory": item + "/", "category": itemlist[-1] + "/", "flavour": flavour, "count": num, "indent": tab } # this prevents a double / in the root category url if item == "": d["fullcategory"] = item #print d # this adds urlencoded versions d["fullcategory_urlencoded"] = tools.urlencode_text(d["fullcategory"]) d["category_urlencoded"] = tools.urlencode_text(d["category"]) # and we toss it in the thing output.append(item_t % d) indent = len(itemlist) output.append(end_t * indent) output.append(finish_t) # export define item's name output[2] = output[2].replace(">/"," class='rootcategory'>%s/"%rootname) return "\n".join(output) def cb_prepare(args): request = args["request"] data = request.getData() data["categorylinks"] = PyblCategories(request)

  • § 写于: Wed, 31 Aug 2011 | 永久链接;源文: rdf ,rss ,raw | 分类: /techic/PyBlosxom/plugins §
    [MailMe] [Print] Creative Commons License

    作品Zoom.Quiet创作,采用知识共享署名-相同方式共享 2.5 中国大陆许可协议进行许可。 基于zoomquiet.org上的作品创作。

    ¶ pyfilenamemtime.py

    2011-08-31 23:22

    # -*- coding: utf-8 -*-
    # -*- coding: utf-8 -*-
    """
    If a filename contains a timestamp in the form of YYYY-MM-DD-hh-mm,
    change the mtime to be the timestamp instead of the one kept by the
    filesystem.  For example, a valid filename would be
    foo-2002-04-01-00-00.txt for April fools day on the year 2002.
    
    Permission is hereby granted, free of charge, to any person
    obtaining a copy of this software and associated documentation
    files (the "Software"), to deal in the Software without restriction,
    including without limitation the rights to use, copy, modify,
    merge, publish, distribute, sublicense, and/or sell copies of the
    Software, and to permit persons to whom the Software is furnished
    to do so, subject to the following conditions:
    
    The above copyright notice and this permission notice shall be
    included in all copies or substantial portions of the Software.
    
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
    BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE.
    
    Copyright 2004, 2005 Tim Roberts
    """
    ## Leo: tab_width=-4 page_width=80
    # vim: tabstop=4 shiftwidth=4
    import os, re, time
    
    __author__ = 'Tim Roberts http://www.probo.com/timr/blog/'
    __version__ = '$Id: pyfilenamemtime.py,v 2872b22e2ace 2011/10/27 07:08:25 zoomquiet+hg $'
    
    DAYMATCH = re.compile('([0-9]{4})-([0-1][0-9])-([0-3][0-9])-([0-2][0-9])-([0-5][0-9]).[\w]+$')
    
    def cb_filestat(args):
        filename = args["filename"]
        stattuple = args["mtime"]
    
        mtime = 0
        mtch = DAYMATCH.search(os.path.basename(filename))
        if mtch:
            try:
                year = int(mtch.groups()[0])
                mo = int(mtch.groups()[1])
                day = int(mtch.groups()[2])
                hr = int(mtch.groups()[3])
                minute = int(mtch.groups()[4]) 
                mtime = time.mktime((year,mo,day,hr,minute,0,0,0,-1))
            except:
                # TODO: Some sort of debugging code here?
                pass
    
        if mtime: 
            args["mtime"] = tuple(list(stattuple[:8]) + [mtime] + list(stattuple[9:]))
    
        return args
    
    
    

    § 写于: Wed, 31 Aug 2011 | 永久链接;源文: rdf ,rss ,raw | 分类: /techic/PyBlosxom/plugins §
    [MailMe] [Print] Creative Commons License

    作品Zoom.Quiet创作,采用知识共享署名-相同方式共享 2.5 中国大陆许可协议进行许可。 基于zoomquiet.org上的作品创作。