Fri 22 February, 2008

add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furlThu 21 February, 2008

add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
2. A frame used by butchers for hanging carcasses by the legs.
add to del.icio.us. look up in del.icio.us.
add to furlWed 20 February, 2008

加载的文件系统的路径。现在就来说说jinja的模板本身的语法,jinja原先用过一次,
和django template极其相似,而且有意思的是它能在{% if %}使用运算符,
可以在模板中调用函数,a(),注意是带括号的。这些方面的改进让它与
django template相比,更具灵活和简便。来看看Shorty的模板吧。
既然和django template类似,那么就有模板继承的概念了。看看它的布局模板,templates/layout.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Shorty</title>
</head>
<body>
<h1><a href="{{ url_for('new') }}">Shorty</a></h1>
<div class="body">{% block body %}{% endblock %}</div>
<div class="footer">
<a href="{{ url_for('new') }}">new</a> |
<a href="{{ url_for('list') }}">list</a> |
use shorty for good, not for evil
</div>
</body>
</html>
url_for()这个函数的调用出自哪里呢?就是前面utils.py中定义的url_for函数。
这个函数由jinja的环境设置中配置,jinja_env.globals['url_for']=url_for,通过
这样设定之后,就能在模板的上下文中使用了。
有了这个layout.html后,就可以继承{% extends %}它了,并填充
{% block body %}{% endblock %}的内容了。看看new.html
{% extends 'layout.html' %}
{% block body %}
<h2>Create a Shorty-URL!</h2>
{% if error %}<div class="error">{{ error }}</div>{% endif -%}
<form action="" method="post">
<p>Enter the URL you want to shorten</p>
<p><input type="text" name="url" id="url" value="{{ url|e(true) }}"></p>
<p>Optionally you can give the URL a memorable name</p>
<p><input type="text" id="alias" name="alias">{#
#}<input type="submit" id="submit" value="Do!"></p>
<p><input type="checkbox" name="private" id="private">
<label for="private">make this URL private, so don't list it</label></p>
</form>
{% endblock %}
e(true)是jinja的一个filter,{# #}是注释块,这里是为了不留下空白符。
templates/display.html
{% extends 'layout.html' %}
{% block body %}
<h2>Shortened URL</h2>
<p>
The URL {{ url.target|urlize(40, true) }}
was shortened to {{ url.short_url|urlize }}.
</p>
{% endblock %}
url.target, url.short_url是URL的属性,参看models.py。
urlize也是filter
看了templates之后,还缺少一个东西,就是那些静态文件css/javascript怎么弄呢?
django中是把这些静态文件分离出来交给web server处理,开发时是用一个过渡的方式来处理。
还记得在最开头的目录结构中有一个static. werkzeug是在application.py中
加入下列代码:
from os import path
from werkzeug import SharedDataMiddleware
把STATIC_PATH加入到utils.py中
STATIC_PATH = path.join(path.dirname(__file__), 'static')
既然application.py是一个dispatch的话,那就继续扮演这个角色,包装一下原先定义的
__call__(),但是self.__call__ = wrap(self.__call__)这样的用法是不对,换个用法
把原先的__call__更名为dispatch,再用新的__call__来包装dispatch.
def __call__(self, environ, start_response):
return self.dispatch(environ, start_response)
这样处理后,就到__init__函数中,安排一个包装dispatch的包装器。
self.dispatch = SharedDataMiddleware(self.dispatch, {
'/static': STATIC_PATH
})
这就是充分利用了wsgi的middleware的作用,不断来增强wsgi的功能。
在utils.py用下面的url_map替换原先的url_map = Map()
url_map = Map([Rule('/static/<file>', endpoint='static', build_only=True)])
有了这个,就可以在html中加入css的引入。
<link rel="stylesheet" type="text/css" href="{{ url_for('static', file='style.css') }}">
从上面的介绍,基本上就介绍完Shorty的主干线了。models/views/templates/dispatch,
这4个环节,让werkzeug做的wsgi application的结构渐渐清晰起来。但是感觉上还是有些乱,
这是因为它还不是一个完整的framework,如果是一个完整的framework,比如django/pylons,
它就会隐藏哪些呢?
1.dispatch,这个不必由开发人员来处理,应该由框架处理。
2.模板的衔接上,不必由开发人员以编程的方式来配置模板,
应采取更简单的作法。
3.在utils.py中可以看到很多东西,什么东西都往那一撂,像个仓库,
应该能有更清楚的作法。
但是这样的开发方式有什么好处呢?
一个就是灵活,模板是自己的,orm是用自己的,有什么wsgi middleware可用,
都能加入,而且是以一种直观的方式加入。
二是对一些小的项目,可能就是一个或两个py文件就打发,整个项目的打包简单
了,不需要用不到的功能。
三就是对开发人员来说,扩展性由自己来定,这是wsgi middleware的特点决定
的,可以不断加入wsgi middleware,增加功能。
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
由它来连接models和templates
看代码吧
from werkzeug import redirect
from werkzeug.exceptions import NotFound
from shorty.utils import session, render_template, expose, validate_url, \
url_for
from shorty.models import URL
@expose('/')
def new(request):
error = url = ''
if request.method == 'POST':
url = request.form.get('url')
alias = request.form.get('alias')
if not validate_url(url):
error = "I'm sorry but you cannot shorten this URL."
elif alias:
if len(alias) > 140:
error = 'Your alias is too long'
elif '/' in alias:
error = 'Your alias might not include a slash'
elif URL.query.get(alias):
error = 'The alias you have requested exists already'
if not error:
uid = URL(url, 'private' not in request.form, alias).uid
session.commit()
return redirect(url_for('display', uid=uid))
return render_template('new.html', error=error, url=url)
@expose('/display/<uid>')
def display(request, uid):
url = URL.query.get(uid)
if not url:
raise NotFound()
return render_template('display.html', url=url)
@expose('/u/<uid>')
def link(request, uid):
url = URL.query.get(uid)
if not url:
raise NotFound()
return redirect(url.target, 301)
@expose('/list/', defaults={'page': 1})
@expose('/list/<int:page>')
def list(request, page):
pass
1.就是@expose,这里是在utils.py中定义的decorate,也就是说在执行views.py时
碰到@expose之类的,就会调用utils.py中的expose,然后就自动加入url map,
再由wsgi application的Shorty来处理,url_map.bind_to_environ(environ)。
2.激活模板的处理是render_template,这个werkzeug并没有含有,而是通过
选定的template引擎来处理的。这个例子是用Jinja的模板引擎。那么来看看
render_template是如何编写的。
3.在new()中处理表格form的内容,使用的是request.form.get来捕获用户输入的信息。
for os import path
from urlparse import urlparse
from werkzeug import Response
from jinja import Environment, FileSystemLoader
ALLOWED_SCHEMES = frozenset(['http', 'https', 'ftp', 'ftps'])
TEMPLATE_PATH = path.join(path.dirname(__file__), 'templates')
jinja_env = Environment(loader=FileSystemLoader(TEMPLATE_PATH))
jinja_env.globals['url_for'] = url_for
def render_template(template, **context):
return Response(jinja_env.get_template(template).render(**context),
mimetype='text/html')
def validate_url(url):
return urlparse(url)[0] in ALLOWED_SCHEMES
从这段代码中,可以看到要设置jinja的配置信息Environment,以及要加载
模板的路径TEMPLATE_PATH,我们在开头介绍项目的目录结构就有一个子目录
是templates,使用的加载器是FileSystemLoader。有了这个之后,
看render_template定义, template是模板本身,context是出入模板的上
下文相关的变量信息,然后打包生成html。这段代码也是放在utils.py文件中。
add to del.icio.us. look up in del.icio.us.
add to furl
承担了数据进出,分派url的映射处理,也就是
request=>url map=>views=>response
/ \
models templates
Shorty算是一个中枢,控制着整个数据的走向。在这个例子中url map的处理
有些特别,先按照它的处理走,有时间我们再按照django的urls.py方式独立出来。
下面就要对models/views/templates相对应的代码作些介绍了。
在utils.py中,配置了sqlalchemy的session,metadata,在application.py中
配置了create_engine,引入数据库引擎。下面来看看models.py中到底如何
来定义models的。
from datetime import datetime
from sqlalchemy import Table, Column, String, Boolean, DateTime
from shorty.utils import session, metadata, url_for, get_random_uid
url_table = Table('urls', metadata,
Column('uid', String(140), primary_key=True),
Column('target', String(500)),
Column('added', DateTime),
Column('public', Boolean)
)
class URL(object):
def __init__(self, target, public=True, uid=None, added=None):
self.target = target
self.public = public
self.added = added or datetime.utcnow()
if not uid:
while True:
uid = get_random_uid()
if not URL.query.get(uid):
break
self.uid = uid
@property
def short_url(self):
return url_for('link', uid=self.uid, _external=True)
def __repr__(self):
return '<URL %r>' % self.uid
session.mapper(URL, url_table)
这个是sqlalchemy的定义models的方式,先建Table,然后声明class,
最后用mapper来映射之。这与django定义models的方式不同。
get_random_uid是需要在utils.py进行补充的。是随机生成id号。
from random import sample, randrange
URL_CHARS = 'abcdefghijkmpqrstuvwxyzABCDEFGHIJKLMNPQRST23456789'
def get_random_uid():
return ''.join(sample(URL_CHARS, randrange(3, 9)))
定义好models之后,就可以用开始介绍的manage.py initdb来生成数据库的
表结构了。application.py和models.py中通过utils.py中定义的session,
metadata来关联在一起。
运行manage.py shell进入交互式shell来看看models的处理吧。
Interactive Werkzeug Shell
>>> from shorty.models import session, URL
>>> urls = [URL('http://example.org/'), URL('http://localhost:5000/')]
>>> URL.query.all()
[]
>>> session.commit()
>>> URL.query.all()
[<URL '5cFbsk'>, <URL 'mpugsT'>]
>>> URL('http://werkzeug.pocoo.org/', False, 'werkzeug-webpage')
>>> session.commit()
>>> URL.query.filter_by(public=False).all()
[<URL 'werkzeug-webpage'>]
>>> URL.query.filter_by(public=True).all()
[<URL '5cFbsk'>, <URL 'mpugsT'>]
>>> URL.query.get('werkzeug-webpage')
<URL 'werkzeug-webpage'>
add to del.icio.us. look up in del.icio.us.
add to furl
This video is a couple of years old now, but I haven't seen it posted on Youtube before, so I did. You know how on America's Funniest Home Videos about 80% of the videos are of some poor schmuck getting whacked in the nuts? This video takes it to a whole new level. I laugh so hard every time I watch this.
add to del.icio.us. look up in del.icio.us.
add to furl
“ I don’t mind if people don’t like me as long as it’s for things I am. ”
Steve Wozniak
add to del.icio.us. look up in del.icio.us.
add to furlTue 19 February, 2008

add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
在看werkzeug tutorial,感觉它的编排上有点和自己的思路相悖,所以我调整一下前后结构,按自己的理解来介绍这篇werkzeug tutorial的内容。这篇指南中的例子,采用的套路基本和django类似,就是用models/views/templates。
(一)目录结构
Werkzeug算是半个框架,创建一个project还没有自动化。那就手动开始做一个project的目录结构,按这个方式走一遍,就知道前后的关系了。这个应用是shorty,随便在一个目录下,比如在werktest目录下,创建如下的目录结构:
manage.py
shorty/
__init__.py
templates/
static/
manage.py和__init__.py还都是空文件。有__init__.py存在说明shorty是个包,manage.py是这个project的管理器,类似django project的manage.py。前面说过它用的是mtv的方式,那后面还有models.py, views.py一步步加入。
(二)manage.py
manage.py用来激活一个开发用的web server,以及其他的一些功能,比如调试器,初始化数据,交互式的shell之类。先来写一些代码到manage.py
#!/usr/bin/env python
from werkzeug import script
def make_app():
from shorty.application import Shorty
return Shorty('sqlite:////tmp/shorty.db')
def make_shell():
from shorty import models, utils
application = make_app()
return locals()
action_runserver = script.make_runserver(make_app, use_reloader=True)
action_shell = script.make_shell(make_shell)
action_initdb = lambda: make_app().init_database()
script.run()
werkzeug中的包script就是专门处理这些的。注意看其中的action_xxx之类的,针对这些命名,可以用manage.py xxx来调用,
比如说
manage.py shell,就是进入交互式shell,
manage.py initdb,就是初始化数据库,
manage.py runserver,就是启动开发用的web server,
而且user_reloader=True,还是针对代码变化随时重启的。
(三)wsgi application
在manage.py中,有个action_runserver,调用的是make_app,这个就是用来调用wsgi application的
def make_app():
from shorty.application import Shorty
return Shorty('sqlite:////tmp/shorty.db')
在shorty目录下,创建application.py,wsgi application有两种方式来创建的,一个是以函数xxx_wsgi_application(environ, start_response)的方式,另一个是以带有__call__(self, environ, start_response)的对象方式来创建,面向对象的方式更好些,因为通过封装,可以传入一些配置信息,还能处理一些wsgi middleware。所以看看shorty/application.py的代码:
from sqlalchemy import create_engine
from werkzeug import Request, ClosingIterator
from werkzeug.exceptions import HTTPException
from shorty.utils import session, metadata, local, local_manager, url_map
from shorty import views
import shorty.models
class Shorty(object):
def __init__(self, db_uri):
local.application = self
self.database_engine = create_engine(db_uri, convert_unicode=True)
def init_database(self):
metadata.create_all(self.database_engine)
def __call__(self, environ, start_response):
local.application = self
request = Request(environ)
local.url_adapter = adapter = url_map.bind_to_environ(environ)
try:
endpoint, values = adapter.match()
handler = getattr(views, endpoint)
response = handler(request, **values)
except HTTPException, e:
response = e
return ClosingIterator(response(environ, start_response),
[session.remove, local_manager.cleanup])
application.py中还导入了shorty.utils,这里导入了很多附加的处理,比如orm的初始化,url mapping的处理,看看shorty/utils.py吧:
from sqlalchemy import MetaData
from sqlalchemy.orm import create_session, scoped_session
from werkzeug import Local, LocalManager
from werkzeug.routing import Map, Rule
local = Local()
local_manager = LocalManager([local])
application = local('application')
metadata = MetaData()
session = scoped_session(lambda: create_session(application.database_engine,
transactional=True), local_manager.get_ident)
url_map = Map()
def expose(rule, **kw):
def decorate(f):
kw['endpoint'] = f.__name__
url_map.add(Rule(rule, **kw))
return f
return decorate
def url_for(endpoint, _external=False, **values):
return local.url_adapter.build(endpoint, values, force_external=_external)
通过上面两个py文件,你可以看到application.py中wsgi application,在__init__()中引入数据库引擎,这点在manage.py中有反映。
def make_app():
from shorty.application import Shorty
return Shorty('sqlite:////tmp/shorty.db')
返回的是Shorty对象,这样调用后,实际执行的有两个,一个就是Shorty.__init__(),另一个就是__call__(self, environ, start_response),
Shorty中定义的另一个函数init_database,是用来创建数据库的,在manage.py中由action_initdb来处理。
下面来看看__call__中的内容,既然这个是wsgi application的核心,这里应该就是负责uri dispatch的中转站,由它来分配相关的一些调用,这样的话,当然先要获取request的相关信息
request = Request(environ)
然后就是要分析request的信息,
local.url_adapter = adapter = url_map.bind_to_environ(environ)
这个看的有些晕了吧。
Try/except块中,对adapter对url进行分离
endpoint, values = adapter.match()
分离出相关的function,也就是具体的views,views沿用了django的用法,怎么找呢,它运用了python的getattr函数,这是对模块动态查询的
handler = getattr(views, endpoint)
就是先找到views.py中有无endpoint的函数,然后就去调用之
response = handler(request, **values)
如没有找到,则发生异常。
return ClosingIterator(response(environ, start_response),
[session.remove, local_manager.cleanup])
最后是个收尾,返回response(environ, start_response),这就是真正处理wsgi的地方。它是可以用middleware的方式进行连续的调用的。后面的函数,是回调函数,session.remove, local_manager.cleanup,
(四) utils.py到底有些什么
我们前面列出了utils.py的代码,它这里头杂七杂八的,什么都有,我也晕。
from werkzeug import Local, LocalManager
from werkzeug.routing import Map, Rule
local = Local()
local_manager = LocalManager([local])
application = local('application')
local对象是一个线程对象,它的属性都和当前的request绑定在一起,就能隐含的以线程安全的方式传递local对象,local_manager是用来跟踪所有的local对象,在request处理的最后结尾,能把local对象正确的删除之。
application = local('application')
这个是用字符串的local对象,返回的是一个proxy对象,指向的是local对象的名字,比如上面这句就是application指向的就是local.application,在Shorty中__init__()和__call__()中都有一句代码
local.application = self
而__init__()引入local.application = self实际没有什么用处,可是要在shell中使用,它就有用了,就能在交互状态下使用了。
from sqlalchemy import MetaData
from sqlalchemy.orm import create_session, scoped_session
metadata = MetaData()
session = scoped_session(lambda: create_session(application.database_engine,
transactional=True), local_manager.get_ident)
这里其实我也没有用过,scoped_session看介绍是一个factory函数,我也是云里雾里,不懂其中的内涵。local_manager.get_ident返回的是local对象内部使用的上下文的信息(context identifier)。似乎就是多个程序联用,可以使用同一个session来处理,这好像可以解决我原先碰到的那个问题,就是多个request来处理sqlalchemy的session,而这些session是处理同一个数据,如果session是不同的话,数据同步的问题就会出现,如果在这个scope_session统一来处理的话,就不会发生数据不一致的问题了。我只是猜测。上次我碰到问题的时候,最后是使用即刻写数据库,更新掉缓存。(待续)...
add to del.icio.us. look up in del.icio.us.
add to furlMon 18 February, 2008

add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
近日看到werkzeug出了0.2版本,它是colubrid的后续项目,因原先弄过colubrid的一个小应用,所以好奇地想看看werkzeug是什么样子。看完werkzeug的文档后,感觉还是要写点介绍的东西。
Werkzeug并不能算是一个web framework,它和colubrid一样,只是完成了web framework所需很少的一部分,基本可以把它作为完成了response和request的处理功能,而且是以wsgi的方式来完成的。那么以wsgi自居的出名的软件有几个:paste、pylons这两个是其中的代表。尤其pylons还是以paste为基础实现的一个比较完整的web framework。那werkzeug为何还要出现呢?从werkzeug的一些背景来看,一是原先有colubrid为蓝本,做了一些重新设计,二是paste作为一个wsgi超强的tool,过于复杂,附带的pastescript和pastedeploy和wsgi本身没有关系,只是作为wsgi的部署和运行需要,使得很多人对paste有种畏惧。而paste目前又将request和response独立出来以webobject的方式来处理,包之间的依赖关系又平添了一层。Werkzeug的简单,小巧,仅仅处理的就是wsgi的一系列小功能,使得它能填补paste阻碍造成的空间。
说werkzeug不能算一个web framework,是因为它不强制使用特定的模板引擎,也不强制使用orm,没有想django那样的admin,没有pylons那样的ajax的集成。werkzeug就是为wsgi应用编写的一组简单的工具,包括的功能有request、response对象的处理,http实体标签(entity tags),缓存控制的头信息(cache control headers),cookie处理,文件上传,以及url routing的处理(可以和django的url routing媲美)。
Werkzeug的出现对那些想组合适合自身需求的人来说,是个有趣的选择。它提供的tutorial文档充分展示了mvc,准确的说应该是mtvd(model/template/view/dispatch),就是django极力宣传的哲学套餐。可能werkzeug目前来说与django/pylons相比,开发效率上可能没有那么自动,不过它所展现的框架的脉络对开发人员来说是极具吸引力的。要加一个自动化工具来连接所需web framework的各组件,应该会促进更多人使用werkzeug。
如果想了解wsgi的详情,可以参看我以前blog的文章,还有一点,特别是以前还有一篇译文是讲why not many python web framework的,werkzeug恰恰是为其中的最薄弱的一环(如何处理wsgi)注入了新的活力和源泉。
有空我将继续werkzeug的介绍。
...
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl

- 说明
- 浏览器Flock是虽然是基于Mozillas Firefox,但是它速度更快并且提供更多的功能:在浏览器中直接阅读RSS,写博客和共享照片等等。这是我现在天天使用的浏览器。
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furlSun 17 February, 2008

add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
Last night I installed a custom firmware (CFW) on my PSP. The custom firmwares allow you to run unsigned homebrew (e.g. non-Sony sanctioned) applications.
Applications
The PSP homebrew community has been pretty active; there are several useful applications and emulators for lots of older systems. There are even emulators for obscure systems like the ColecoVision and Neo Geo.
Here's what works for me so far, in no particular order:
- VNC client
- SSH client
- Super Nintendo (SNES) emulator
- Game Boy Color emulator
- MS-DOS emulator
- J2ME/MIDP emulator (e.g Mobile Java, or the crappy games on your cell phone)
I also tried the Genesis, NES, and N64 emulators, but they aren't working yet. Here's a picture of the SNES emulator at work:
|
|
| Playing SNES on a PSP |
The custom firmware also allows you to dump UMDs and run them from a memory stick. Since it's pretty much impossible to fit a PSP and 8 UMDs in the your pockets without looking like a complete tool, I'm going to offload as many UMDs as I can into the 3GB remaining on my memory stick.
The next section explains the firmware installation process. If you don't have a PSP, you may still find my creatively ominous safety warnings entertaining.
Installation
Installing the custom firmware varies in complexity depending on the model of PSP model and version of the original firmware. If you're fortunate enough to have an older "phat" PSP (e.g. the larger black model) that's running firmware 1.00 or 1.50, then installing the custom firmware is fairly straightforward.
If you know someone with a PSP who already has the custom firmware installed, then the installation process is still easy enough, because they can use their PSP to help you with yours.
If you've got a newer PSP Slim (the smaller white model, like the one in the picture above) and/or are running a newer firmware, then there are no easy options left, so get ready for the comically unpleasant experience below.
In order to install the custom firmware, you'll need a spare battery and a spare memory stick. For the love of Douglas Adams, please do not use this post as a guide! There are several web sites (here and here) that cover the entire installation process in far more detail and with the appropriate safety precautions. If you mess this up you will turn your PSP into a lifeless and possibly explosive plastic brick.
The basic, high-level steps are as follows:
- Create a Pandora's battery. This is a battery that has been modified to make the PSP into boot from the memory stick.
- Create a Magic Memory Stick. This is a memory stick that has been specially formatted to boot and perform a firmware upgrade. Note that there are some limits on the capacity and brand of memory stick that can be used; see the guides above for more details.
- With the PSP powered off and the battery removed, insert the magic memory stick into the PSP.
- Insert the Pandora's battery. The PSP will power on automatically boot from the magic memory stick.
- Use the software on the magic memory stick to install the custom firmware. On the PSP Slim the display is blank, so you just have to hit X and wait. The lights on the front of the PSP will blink for several minutes. The PSP will automatically power off when the installation is finished.
- Remove the Pandora's battery and the magic memory stick. The memory stick can be reformatted and used as usual. The Pandora's battery can not, because some of the battery's safety features are disabled as part of the conversion process. In other words, do not attempt to use the Pandora's battery as a regular battery unless you want your PSP to melt into a smoldering puddle of goo.
- Power on the PSP using a regular battery or the power cable. Congratulations, you are now running the custom firmware.
The hardest part of this process is creating the Pandora's battery. If you know someone with a PSP that already has the custom firmware installed, then they can run an application on their PSP to temporarily "soft-mod" a regular battery into Pandora's battery.
If you don't know anyone with a PSP that already has the custom firmware installed, then the only way to convert a regular battery into a Pandora's battery is to "hard-mod" it; that means cutting open the battery casing and disconnecting one of the leads on the internal circuitry.
The guides I read (see above) have plenty of pictures, but I was still surprised by how small the pieces actually were. Here's a picture I just took of my Pandora's battery, including a ruler and quarter as size references:
|
|
| Inside a Pandora's Battery |
Creating a Magic Memory Stick is much simpler. Basically you:
- format the memory stick in a special way (using
mspformat) - copy the necessary firmware installation and upgrade files into place
- generates an Initial Program Load (IPL) file,
- copy the generated IPL file to the first sector of the memory stick
(using
mspinst)
If you're using Windows, the "TotalNewbi Installer" and "Pandora Easy GUI" tools can automate this process. In theory, anyway. When I tried to use them in my Windows XP VMWare instance, they both had problems. The TotalNewbi Installer simply refused to work, and the Pandora Easy GUI blue-screened XP each time I ran it.
Here's what finally worked:
- used Pandora Easy GUI to copy the firmware files into place and
generate the installer definition file (
mspinst.idl) - used
ddin Linux to copymspinst.iblinto the first sector of the Memory Stick
The good news is that creating the Pandora's Battery and Magic Memory Stick are the hardest steps in the process. Once you get past them, everything else is relatively straightforward. Even better, the process can be used to install custom firmware on any PSP, regardless of hardware model or firmware version.
That's it for me. If you're interested in the history and technical details of PSP homebrew, check out this extremely detailed PSP homebrew Wikipedia entry.
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furlSat 16 February, 2008

add to del.icio.us. look up in del.icio.us.
add to furlFri 15 February, 2008

add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl

- 说明
- 看看什么时候Rails应用程序的根目录下面的目录components开始被使用?还是一直让它空着?
- 参考资料
add to del.icio.us. look up in del.icio.us.
add to furl

