
A couple of days ago I was lamenting the state of webstats, although I was a little vague as to my purpose. Specifically I was wanting to find out about the screen resolutions and user-agents viewing a couple of sites.
To get screen resolutions you really need to inject javascript into your pages, which is icky. Still its a small price to pay, and chances are most people won't notice.
Of course there are drawbacks:
This is the gist of it:
$ cd /usr/src/
I haven t used Xen HVM until recently. When I was at Amazon and
Ok, so following the trend, I created some time ago a new GPG
key, which I'm now transitioning too. I've set up a transition
document, available at http://molly.corsac.net/~corsac/key-transition.txt.
It's signed by both the old and the new keys and is reproduced
below:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: RIPEMD160,SHA512
Wed, 11 Nov 2009 13:44:05 +0100
I've recently set up a new RSA-based GPG key, and will be transitioning away
from my old DSA-based one. The old key will be revoked soon, so I prefer all
future correspondence to use the new one. I would also like to ensure that
this new key is well-integrated into the web of trust. This message is signed
by both keys to certify the transition.
The old DSA key was:
pub 1024D/C5C05BAE 2004-11-11
Key fingerprint = DE26 2FC4 7097 FFC6 DE2C D8C0 4D44 C020 C5C0 5BAE
The new RSA key is:
pub 4096R/71EF0BA8 2009-05-06
Key fingerprint = 4510 DCB5 7ED4 7040 60C6 6476 3055 0F78 71EF 0BA8
If you already know my old key, you can verify that the new key is
signed by the old one:
gpg --check-sigs 71EF0BA8
If you don't already know my old key, or if you're extra-paranoid, you
can check the fingerprint against the one given above:
gpg --fingerprint 71EF0BA8
If you have previously signed my old DSA key, and if you're satisfied
that you've got the correct new RSA key, then I'd appreciate it if you
would sign my new key as well:
caff 71EF0BA8
The caff program is in the signing-party package in Debian. Please be careful
to generate signatures that don't rely on the weakening SHA-1 hash algorithm,
which requires some careful configuration even if you've already configured
gpg correctly. See http://www.gag.com/bdale/blog/posts/Strong_Keys.html for
the gory details.
Thanks,
- --
Yves-Alexis Perez
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
iEYEAREDAAYFAkr6sqQACgkQTUTAIMXAW64HiACeIyabQueDHAeiAX8EkIeApiDj
++UAn2z7YkjHx0lQh0+s5WdhikG0YztiiQIcBAEBCgAGBQJK+rKkAAoJEDBVD3hx
7wuodUcQAKMbG9Rehxz+uZ6fST99cHt5Fjnv9TorY4hQaQK+85ZgiwPaHMHfYM1G
5hcrXI+JFUpz8j40deZuaWuspOdHBHwnHNQril8MqT0CJgtB6HFTo+w/7Lmmui5M
DDMMed39UJl7bF73hV9ywGecxPpeh+dtoVnh0VT16uK2xTvW6ICEZgaPw1xfPUHS
+jxQ7I05X1OWQkPpmhxXJqGclDyO+qx4CJZsOxUAvt2LphHxhZxB3QE5OUdudGKQ
AH6KhC4rpNQdJVMX20SG8PybL/AipN3Y8N/63VkoqVC2heRlaQ69HjsuqIAkIyan
hHnqmJH8Q+TDTbdKZvOQv6jcd4o3VSibz0T9MwnOfqQ0uRYyTpaXC0vLUH6lXaC4
eK+VVWbY8vCAFHR3h80Q61i2me2HU5ly7a/W22dz19zzDNNC5q9MO78uIYkUK78N
Z0wzJrmOxRyhvs5DOSOpNVlXZhffNQM1f42xxG8cUDaIf7pR5jK+xqHV7tIBQE1D
CrD0mt+YQCnngK0i4wQTO7VT/vjypf4A9W+VSsoJJpRhBbngU4pHu9JWqO84/7AA
j5FN8ug15MWysaS+FQ/EqzHmT7BGBWaTPv3yGlHKUjx0w4bPEpbH7y3fwHAcmOFf
xFRzvZFQ03zeer06yAqTVNuwr77HZgrCzgyQVgIkegAg6iUPiZcs
=CBT+
-----END PGP SIGNATURE-----
In Ubuntu Server Edition 9.10: No hardware required,
Matt Zimmerman announces that from now on, "every release of Ubuntu Server
Edition is simultaneously available on EC2".
Amazon's EC2 documentation
says: "the ability to create and publish kernels and ramdisks is restricted
to Amazon EC2 and selected vendors". Canonical appears to be one of those
vendors. Their newest EC2 AMI's contain modules from an Ubuntu build of
linux-xen (2.6.27-23).
Eric Hammond, who has been for a while making both
Ubuntu and Debian images for EC2
says
Historically on EC2, neither Debian nor Ubuntu have had completely Debian and Ubuntu stacks from the kernel up. Instead, we've had to make do with patching the runtime on top of older kernels (2.6.16, 2.6.18, 2.6.21) built for other distros (Fedora Core). Amazingly, we've managed to hold this together and keep it running well for a couple years on EC2.He goes on to describe current problems with eg, Debian's new udev version and the available EC2 kernels. Furthermore, anticipating today's news:
When the point comes where I am not publishing the base Ubuntu server AMIs, it will not make sense for me to publish new Debian AMIs either.Those wanting to run Debian on EC2 will be stuck with duct-taping together Debian with the available kernels. Maybe I'm wrong. Maybe Ubuntu is actually working with Debian's kernel team, and will be letting them use Canonical's access to publish AKI's of official Debian kernels. Or maybe Ubuntu is working with Debian's kernel team to include identical linux-xen kernel in Debian, so the Ubuntu AKI's could be used. But appearances are that this is another case where Ubuntu has managed to take a situation that was less than ideal for all concerned, and turn it into an advantage for Ubuntu, while at the same time being a unfixable loss for Debian. My mouse's perspective is that a) we maybe only have so many losses left in us (altho we did get thru that whole dinosaur thing ok!) and b) King Kong is still oddly dependent on his mammilian heritage to be up there with his head in the cloud, tearing at Godzilla and stamping on us.
@expose("json") @validate(validator_dispatcher, error_handler=api_validation_error) def list_colours(self, filter=None, productID=None, maxResults=100, **kw): # Call API res = self.engine.list_colours(filter, productID, maxResults) # Return result return dict(r=res)It would be nice, however, to have an
@webapi() decorator that
automatically wraps the function result with the dict:
def webapi(func): def dict_wrap(*args, **kw): return dict(r=func(*args, **kw)) return dict_wrap # ...in the controller... @expose("json") @validate(validator_dispatcher, error_handler=api_validation_error) @webapi def list_colours(self, filter=None, productID=None, maxResults=100, **kw): # Call API res = self.engine.list_colours(filter, productID, maxResults) # Return result return resThis works, as long as @webapi appears last in the list of decorators. This is because if it appears last it will be the first to wrap the function, and so it will not interfere with the
tg.decorators machinery.
Would it be possible to create a decorator that can be put anywhere among the
decorator list? Yes, it is possible but tricky, and it gives me the feeling
that it may break in any future version of TurboGears:
class webapi(object): def __call__(self, func): def dict_wrap(*args, **kw): return dict(r=func(*args, **kw)) # Migrate the decoration attribute to our new function if hasattr(func, 'decoration'): dict_wrap.decoration = func.decoration dict_wrap.decoration.controller = dict_wrap delattr(func, 'decoration') return dict_wrap # ...in the controller... @expose("json") @validate(validator_dispatcher, error_handler=api_validation_error) @webapi def list_colours(self, filter=None, productID=None, maxResults=100, **kw): # Call API res = self.engine.list_colours(filter, productID, maxResults) # Return result return resAs a convenience, TurboGears 2 offers, in the
decorators module, a way to
build decorator "hooks":
class before_validate(_hook_decorator): '''A list of callables to be run before validation is performed''' hook_name = 'before_validate' class before_call(_hook_decorator): '''A list of callables to be run before the controller method is called''' hook_name = 'before_call' class before_render(_hook_decorator): '''A list of callables to be run before the template is rendered''' hook_name = 'before_render' class after_render(_hook_decorator): '''A list of callables to be run after the template is rendered. Will be run before it is returned returned up the WSGI stack''' hook_name = 'after_render'The way these are invoked can be found in the
_perform_call function in
tg/controllers.py.
To show an example use of those hooks, let's add a some polygen wisdom to every
data structure we return:
class wisdom(decorators.before_render): def __init__(self, grammar): super(wisdom, self).__init__(self.add_wisdom) self.grammar = grammar def add_wisdom(self, remainder, params, output): from subprocess import Popen, PIPE output["wisdom"] = Popen(["polyrun", self.grammar], stdout=PIPE).communicate()[0] # ...in the controller... @wisdom("genius") @expose("json") @validate(validator_dispatcher, error_handler=api_validation_error) def list_colours(self, filter=None, productID=None, maxResults=100, **kw): # Call API res = self.engine.list_colours(filter, productID, maxResults) # Return result return resThese hooks cannot however be used for what I need, that is, to wrap the result inside a dict. The reason is because they are called in this way:
controller.decoration.run_hooks( 'before_render', remainder, params, output)and not in this way:
output = controller.decoration.run_hooks( 'before_render', remainder, params, output)So it is possible to modify the output (if it is a mutable structure) but not to exchange it with something else. Can we do even better? Sure we can. We can assimilate
@expose and @validate
inside @webapi to avoid repeating those same many decorator lines over and
over again:
class webapi(object): def __init__(self, error_handler = None): self.error_handler = error_handler def __call__(self, func): def dict_wrap(*args, **kw): return dict(r=func(*args, **kw)) res = expose("json")(dict_wrap) res = validate(validator_dispatcher, error_handler=self.error_handler)(res) return res # ...in the controller... @expose("json") def api_validation_error(self, **kw): pylons.response.status = "400 Error" return dict(e="validation error on input fields", form_errors=pylons.c.form_errors) @webapi(error_handler=api_validation_error) def list_colours(self, filter=None, productID=None, maxResults=100, **kw): # Call API res = self.engine.list_colours(filter, productID, maxResults) # Return result return resThis got rid of
@expose and @validate, and provides almost all the
default values that I need. Unfortunately I could not find out how to access
api_validation_error from the decorator so that I can pass it to the
validator, therefore I remain with the inconvenience of having to explicitly
pass it every time.
Over the last few days I have worked for some hours on packaging the last dependency of GNOME Shell that was missing in Debian: gjs. That work has been sponsored by Collabora, along with the work required to package GNOME Shell itself. I was very impressed by the time it took for FTP Masters and Assistants to deal with the new packages - it only took a couple days for each; kudos!
What this all means is that you can now easily test GNOME Shell, and even make it your default environment on a Debian unstable system, by just installing the gnome-shell package. As I expected, some people have been having trouble with the new package, but the general feedback has been fairly positive. If the README.Debian package doesn t help you with your specific issue, do take the time to file a bug report!
By the way, thanks go to Joss, for his work on dh_girepository, and for him, and Sebastian Dr ge for their work on creating the new GObject Introspection policy.
@expose("json") def list_colours(self, filter=None, productID=None, maxResults=100, **kw): # Call API res = self.engine.list_colours(filter, productID, maxResults) # Return result return resTo validate the parameters we can use forms, it's their job after all:
class ListColoursForm(TableForm): fields = [ # One field per parameter twf.TextField("filter", help_text="Please enter the string to use as a filter"), twf.TextField("productID", help_text="Please enter the product ID"), twf.TextField("maxResults", validator=twfv.Int(min=0), default=200, size=5, help_text="Please enter the maximum number of results"), ] list_colours_form=ListColoursForm() #... @expose("json") @validate(list_colours_form, error_handler=list_colours_validation_error) def list_colours(self, filter=None, productID=None, maxResults=100, **kw): # Parameter validation is done by the form # Call API res = self.engine.list_colours(filter, productID, maxResults) # Return result return resAll straightforward so far. However, this means that we need two exposed methods for every API call: one for the API call and one error handler. For every API call, we have to type the name several times, which is error prone and risks to get things mixed up. We can however have a single error handler for all methonds:
def get_method(): ''' The method name is the first url component after the controller name that does not start with 'test' ''' found_controller = False for name in pylons.c.url.split("/"): if not found_controller and name == "controllername": found_controller = True continue if name.startswith("test"): continue if found_controller: return name return None class ValidatorDispatcher: ''' Validate using the right form according to the value of the "method" field ''' def validate(self, args, state): method = args.get("method", None) # Extract the method from the URL if it is missing if method is None: method = get_method() args["method"] = method return forms[method].validate(args, state) validator_dispatcher = ValidatorDispatcher()This validator will try to find the method name, either as a form field or by parsing the URL. It will then use the method name to find the form to use for validation, and pass control to the
validate method of that form.
We then need to add an extra "method" field to our forms, and arrange the forms
inside a dictionary:
class ListColoursForm(TableForm): fields = [ # One hidden field to have a place for the method name twf.HiddenField("method") # One field per parameter twf.TextField("filter", help_text="Please enter the string to use as a filter"), #... forms["list_colours"] = ListColoursForm()And now our methods become much nicer to write:
@expose("json") def api_validation_error(self, **kw): pylons.response.status = "400 Error" return dict(form_errors=pylons.c.form_errors) @expose("json") @validate(validator_dispatcher, error_handler=api_validation_error) def list_colours(self, filter=None, productID=None, maxResults=100, **kw): # Parameter validation is done by the form # Call API res = self.engine.list_colours(filter, productID, maxResults) # Return result return res
api_validation_error is interesting: it returns a proper HTTP error status,
and a JSON body with the details of the error, taken straight from the form
validators. It took me a while to find out that the form errors are in
pylons.c.form_errors (and for reference, the form values are in
pylons.c.form_values). pylons.response is a WebOb Response that we can play with.
So now our client side is able to call the API methods, and get a proper error
if it calls them wrong.
But now that we have the forms ready, it doesn't take much to display them in
web pages as well:
def _describe(self, method): "Return a dict describing an API method" ldesc = getattr(self.engine, method).__doc__.strip() sdesc = ldesc.split("\n")[0] return dict(name=method, sdesc = sdesc, ldesc = ldesc) @expose("myappserver.templates.myappapi") def index(self): ''' Show an index of exported API methods ''' methods = dict() for m in forms.keys(): methods[m] = self._describe(m) return dict(methods=methods) @expose('myappserver.templates.testform') def testform(self, method, **kw): ''' Show a form with the parameters of an API method ''' kw["method"] = method return dict(method=method, action="/myapp/test/"+method, value=kw, info=self._describe(method), form=forms[method]) @expose(content_type="text/plain") @validate(validator_dispatcher, error_handler=testform) def test(self, method, **kw): ''' Run an API method and show its prettyprinted result ''' res = getattr(self, str(method))(**kw) return pprint.pformat(res)In a few lines, we have all we need: an index of the API methods (including their documentation taken from the docstrings!), and for each method a form to invoke it and a page to see the results. Make the forms children of AjaxForm, and you can even see the results together with the form.
Hey all!
I m sorry I haven t been very active with my packages recently. I all-of-a-sudden started grad school and have been swamped with studying. I also started a contract and have been busy trying to learn a new codebase while contributing something other than snark.
I promise I ll get back to packaging IronRuby and IronPython on Mono for Debian as soon as things start settling down. Getting an A in the class is higher priority, though, sorry
Don t worry. I haven t forgotten about you ;)
Cheers,
C.J.
PS, I am implementing a Perl library to exercise my understanding of the class. You can follow along at the search.cpan.org page for Lingua::HPSG or by cloning the git repo:
$ git clone git://karma.colliertech.org/colliertech/langparser
I have been meaning to switch to OpenStreetMap for a while now, but the fact that it didn't work with Privoxy was holding me back. I don't enjoy surfing the web without protection and Privoxy is one of the most convenient ways of enhancing one's browsing experience on Debian and Ubuntu.Then I downloaded the same URLs without Privoxy into a noproxy/ directory:$ http_proxy=localhost:8118 wget URL
To find identical files, I ran md5sums in each directory:$ http_proxy= wget URL
After deleting all identical files, I was left with:md5sum *
Which I diff'ed together:index.html
OpenLayers.js?1251388304
The first file, index.html did not have any relevant changes, but I noticed in the second one that a few of thesecolordiff -u noproxy/FILE privoxy/FILE
were replaced withthis.moveTo(this.position)
Searching for "concat" in /etc/privoxy/, I found that the "jumping-windows" filter was the culprit. After disabling it, all of the problems went away.''.concat(this.position)
-filter jumping-windows
.openstreetmap.org
Order Without Law is a fantastic book by Robert Ellickson published
in 1991. In a way, the book is an in-depth case study of the irrelevance
of law. Subtitled, "how neighbors settle disputes," Ellickson shows how
people solve complicated problems in an archetypal area of liability law
without knowledge of the law. Ellickson shows that even when people know
exactly what the law says, they often ignore it in favor of community
norms and, in his examples, models of "neighborliness."
Specifically, the book is about how neighbors in northern California
settle disputes related to damage caused by roaming cattle, how
neighbors construct and share costs of fences, and how, although the law
is frequently debated in relation to classifying land as either open or
closed to free grazing, the law tends to take a back seat to unwritten
norms in the way that problems are actually solved. There is order and a
shared understanding of rules in Ellickson's account; it just has very
little to do with the law.
As part of his description, Ellickson goes into some detail about the
types of damage that cattle cause. For example, Ellickson describes how
bulls, will often break down barbed wire fences and go on rampages
impregnating heifers, eating vast amounts of food, and destroying crops
and equipment.
When I was on a long bike trip through northern California a few
weeks ago, I was sitting under a tree waiting for my cyling partner to
catch up. A giant black bull nearby noticed me. Shorting, mooing, and
shaking ribbons of slobber from its mouth, it lumbered toward me. Only a
rather weak-looking barbed wire fence separated us. All I could think
about was Order Without Law.
The Monad
Reader is a monthly newsletter by Haskellers. From the announcement
email:
This month's issue has a definite introductory theme. It includes republished
book reviews, notes on learning, a look at the differences between functional
and object oriented programming, and distributed computation.
As always, The Monad.Reader invites submissions on Haskell and related
topics. Send a summary or abstract for your article to shae@ScannedInAvian.com
-- Shae Matijs Erisson
Next.