<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/wordpress-mu-1.2.5" -->
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
        xmlns:opencore="http://www.openplans.org/opencore"
	>

<channel>
	<title>Topp Engineering</title>
	<link>http://www.openplans.org/projects/topp-engineering/blog</link>
	<description>Just another  weblog</description>
	<pubDate>Tue, 18 Nov 2008 22:48:27 +0000</pubDate>
	<generator>http://wordpress.org/?v=wordpress-mu-1.2.5</generator>
	<language>en</language>
			<item>
		<title></title>
		<link>http://www.openplans.org/projects/topp-engineering/blog/2008/11/18/18/</link>
		<comments>http://www.openplans.org/projects/topp-engineering/blog/2008/11/18/18/#comments</comments>
        	<slash:comments>0</slash:comments> 
		<pubDate>Tue, 18 Nov 2008 22:33:12 +0000</pubDate>
		<dc:creator>novalis</dc:creator>
                <opencore:userid>novalis</opencore:userid>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.openplans.org/projects/topp-engineering/blog/2008/11/18/18/</guid>
		<description><![CDATA[I did a bit more work on the Python optimizer last week. This time, the problem was tuple assignment. Consider the code:
a, (b, c) = d, e = 1, (2, 3)
This would get translated to:

LOAD_CONST 1
LOAD_CONST (2, 3)
BUILD_TUPLE 2 # builds the tuple (1, (2, 3)
DUP_TOP       # duplicates the [...]]]></description>
			<content:encoded xml:base="http://www.openplans.org/projects/topp-engineering/blog/2008/11/18/18/"><![CDATA[<p>I did a bit more work on the Python optimizer last week. This time, the problem was tuple assignment. Consider the code:</p>
<pre>a, (b, c) = d, e = 1, (2, 3)</pre>
<p>This would get translated to:<br />
</p>
<pre>LOAD_CONST 1
LOAD_CONST (2, 3)
BUILD_TUPLE 2 # builds the tuple (1, (2, 3)
DUP_TOP       # duplicates the top item on the stack, since
              # it's going to be assigned to two targets
UNPACK_SEQUENCE 2 #now, push each element of the tuple we just
                  #built onto the stack
STORE_FAST a
UNPACK_SEQUENCE 2 #unpack (2, 3)
STORE_FAST b
STORE_FAST c
UNPACK_SEQUENCE 2 #unpack the duplicate
STORE_FAST d
STORE_FAST e</pre>
<p>This is stupid, because it does a bunch of packing and unpacking of tuples. Tom Lee&#8217;s patch improves the situation by recognizing (1, (2, 3)) as a constant, and storing it in the constants table so that it does not need to be created on the fly. In other words, it replaces the first three operations of the above with:</p>
<pre>LOAD_CONST (1, (2, 3))</pre>
<p>This is much faster, but it&#8217;s still not optimally fast. The above Python code is equivalent to:</p>
<pre>a = 1
d = 1
b, c = e = 2, 3</pre>
<p>This produces the following bytecode:</p>
<pre>LOAD_CONST 1
STORE_FAST a
LOAD_CONST 1
STORE_FAST b
LOAD_CONST (2, 3)
DUP_TOP
UNPACK_SEQUENCE 2
STORE_FAST b
STORE_FAST c
STORE_FAST e</pre>
<p>
  <br /><a href="http://bugs.python.org/issue4327">My latest patch</a> to the optimizer does this conevrsion. At a slight space cost, the sequence could be further reduced by replacing the DUP_TOP UNPACK_SEQUENCE with a LOAD_CONST for each element. I decided not to do this, because not everyone will want to make time-space tradeoffs, and I&#8217;m not 100% sure it would be faster.
</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.openplans.org/projects/topp-engineering/blog/2008/11/18/18/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Zope 2 / Five permissions gotcha</title>
		<link>http://www.openplans.org/projects/topp-engineering/blog/2008/11/13/zope-2-five-permissions-gotcha/</link>
		<comments>http://www.openplans.org/projects/topp-engineering/blog/2008/11/13/zope-2-five-permissions-gotcha/#comments</comments>
        	<slash:comments>0</slash:comments> 
		<pubDate>Thu, 13 Nov 2008 23:40:49 +0000</pubDate>
		<dc:creator>Paul Winkler</dc:creator>
                <opencore:userid>slinkp</opencore:userid>
		
		<category><![CDATA[zope 3]]></category>

		<category><![CDATA[programming]]></category>

		<category><![CDATA[plone]]></category>

		<guid isPermaLink="false">http://www.openplans.org/projects/topp-engineering/blog/2008/11/13/zope-2-five-permissions-gotcha/</guid>
		<description><![CDATA[The zcml  tag doesn&#8217;t actually create a permission.&#160; (Or at least, that&#8217;s the case in Five. Dunno about &#8220;pure&#8221; zope 3.) &#160; The permission actually springs to life when you protect something with it.

This came up because I had an error similar to the one in&#160; this thread, while trying to reload rolemap.xml to [...]]]></description>
			<content:encoded xml:base="http://www.openplans.org/projects/topp-engineering/blog/2008/11/13/zope-2-five-permissions-gotcha/"><![CDATA[<p>The zcml  tag doesn&#8217;t actually create a permission.&nbsp; (Or at least, that&#8217;s the case in Five. Dunno about &#8220;pure&#8221; zope 3.) &nbsp; The permission actually springs to life when you protect something with it.
</p>
<p>This came up because I had an error similar to the one in&nbsp; <a href="http://plone.org/support/forums/general#nabble-td339972">this thread,</a> while trying to reload rolemap.xml to add my permission to a Plone site via GenericSetup; it wouldn&#8217;t load until I restored a commented-out view declaration that used the permission.<br />
  
</p>
<p>Now you know. I found it surprising.<br />
  </p>
]]></content:encoded>
			<wfw:commentRss>http://www.openplans.org/projects/topp-engineering/blog/2008/11/13/zope-2-five-permissions-gotcha/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Beautiful Application File Layouts</title>
		<link>http://www.openplans.org/projects/topp-engineering/blog/2008/11/06/beautiful-application-file-layouts/</link>
		<comments>http://www.openplans.org/projects/topp-engineering/blog/2008/11/06/beautiful-application-file-layouts/#comments</comments>
        	<slash:comments>7</slash:comments> 
		<pubDate>Fri, 07 Nov 2008 00:54:40 +0000</pubDate>
		<dc:creator>nickyg</dc:creator>
                <opencore:userid>nickyg</opencore:userid>
		
		<category><![CDATA[web-design]]></category>

		<category><![CDATA[best-practices]]></category>

		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.openplans.org/projects/topp-engineering/blog/2008/11/06/beautiful-application-file-layouts/</guid>
		<description><![CDATA[For all the web designers out there in the TOPPosphere&#8230;
  

From a designer&#8217;s POV, the most important files are templates, CSS, and javascript.&#160; They are the three pillars of web design.&#160; The sun rises and sets with them.&#160; They are best friends.&#160; So, ideally, they should be as close together as possible.
  

For [...]]]></description>
			<content:encoded xml:base="http://www.openplans.org/projects/topp-engineering/blog/2008/11/06/beautiful-application-file-layouts/"><![CDATA[<p><em>For all the web designers out there in the TOPPosphere&#8230;</em><br />
  
</p>
<p>From a designer&#8217;s POV, the most important files are templates, CSS, and javascript.&nbsp; They are the three pillars of web design.&nbsp; The sun rises and sets with them.&nbsp; They are best friends.&nbsp; So, ideally, they should be as close together as possible.<br />
  
</p>
<p>For example: here&#8217;s how files are laid out in a typical Pylons application:
</p>
<pre><code>/path/to/application/</code>:

  public/
    images/
    javascripts/
    stylesheets/
  templates/
    index.mako
    specific-group-of-templates/
    etc.

</pre>
<p>This is a really nice layout &#8212; the files are close together, and there&#8217;s never any question where something is or where it should go.&nbsp; New images go in public/images, new javscript goes in public/javascripts, etc.&nbsp; This is the same from one application to another.&nbsp; Ruby on Rails follows a similar pattern.
</p>
<p>By contrast, here&#8217;s the file layout in the <a href="http://www.communityalmanac.org">Almanac</a> project:
</p>
<pre><code>/path/to/application/</code>:

  parts/
    client/
       resource/
           lib/
              Almanac.js
           theme/
              almanac.css
              img/

   src/
      CommunityAlmanac/
         opengeo/
            almanac/
               templates/
                   mytemplate.pt

</pre>
<p> When I first saw this I was like AAAAH!&nbsp; Not to pick on the Almanac, though; I love the Almanac.&nbsp; Really, I do.&nbsp; But, it can be frustrating to work with. Not only are the files in far flung branches of the filesystem, but they&#8217;re in separate checkouts.&nbsp; This means lots of time spent switching back and forth between areas of the site (I ended up using two separate Coda profiles to work on these files), and two commits for nearly every change.<br />
  
</p>
<p>Could this have been avoided?&nbsp; I&#8217;m not sure.&nbsp; If we keep laying out apps this way, will the sky fall?&nbsp; Probably not.&nbsp; But if it&#8217;s possible, we should could consider the plight of the poor, defenseless designer when laying out our apps in the future.<br />
  
</p></p>
]]></content:encoded>
			<wfw:commentRss>http://www.openplans.org/projects/topp-engineering/blog/2008/11/06/beautiful-application-file-layouts/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Optimizing Python</title>
		<link>http://www.openplans.org/projects/topp-engineering/blog/2008/11/03/optimizing-python/</link>
		<comments>http://www.openplans.org/projects/topp-engineering/blog/2008/11/03/optimizing-python/#comments</comments>
        	<slash:comments>2</slash:comments> 
		<pubDate>Tue, 04 Nov 2008 02:00:43 +0000</pubDate>
		<dc:creator>novalis</dc:creator>
                <opencore:userid>novalis</opencore:userid>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.openplans.org/projects/topp-engineering/blog/2008/11/03/optimizing-python/</guid>
		<description><![CDATA[­I spent some time over the past few weeks looking into the internals of the Python compiler and bytecode interpreter.

First, some general impressions. The code is very clean C code. It actually uses Python objects internally for things that are annoying to safely represent in C, such as strings, vectors (Python lists), and hash tables [...]]]></description>
			<content:encoded xml:base="http://www.openplans.org/projects/topp-engineering/blog/2008/11/03/optimizing-python/"><![CDATA[<p>­I spent some time over the past few weeks looking into the internals of the Python compiler and bytecode interpreter.
</p>
<p>First, some general impressions. The code is very clean C code. It actually uses Python objects internally for things that are annoying to safely represent in C, such as strings, vectors (Python lists), and hash tables (Python dicts). This means that readers can piggyback on their existing understanding of Python. The bytecode interpreter is also straightforward and readable.
</p>
<p> The Python virtual machine is stack-based. Python bytecode is simply a list of operations with either zero or one sixteen-bit operand, depending on the operation. For example, a common section of code is:
</p>
<pre>...
LOAD_FAST 0
GET_ITER
FOR_ITER
STORE_FAST 1
...
</pre>
<p>LOAD_FAST and STORE_FAST give access to local variables. Every function has an array of locals, and the operand of LOAD_FAST/STORE_FAST is an index into that array. LOAD_FAST puts the value of the local onto the stack, and STORE_FAST pops a value off the stack and puts it into the local. GET_ITER gets an iterator for an iterable &#8212; it replaces the top of the stack with the iterator. FOR_ITER pushes the next value from the iterator on top of the stack on to the stack. You&#8217;re expected to pop it &#8212; the next operation is nearly always STORE_FAST. In fact, the Python bytecode interpreter has a predictor which quickly checks if the next operation is STORE_FAST, and skips some tests if so. So that snippet of code is the preamble of a for loop. Local variable 0 is the iterable, and local variable 1 is the iteration variable.
</p>
<p> If you want to see the bytecode for a function, the dis module will print it. Unfortunately, that&#8217;s all it will do &#8212; it won&#8217;t give it to you in a manipulable form. If you want to write your own functions in Python bytecode, you need peak.util.assembler, which does not in any way interoperate with dis. To check how Python interprets a given opcode, check in the Python source code, Python/ceval.c.
</p>
<p>The python compiler works in a fairly standard fashion &#8212; the source code is tokenized, the tokens become a concrete syntax tree, the CST becomes an abstract syntax tree, and the AST is compiled to bytecode. I started looking at the peephole optimizer, which operates on compiled bytecode (that is, an array of chars). I implemented a minor optimization for the case:
</p>
<pre>r = ...
return r
</pre>
<p>The bytecode looked like:
</p>
<pre>STORE_FAST n
LOAD_FAST n
RETURN_VALUE
</pre>
<p>My patch replaced it with just:
</p>
<pre>RETURN_VALUE
</pre>
<p>My patch was rejected, because apparently the additional six lines of code didn&#8217;t buy enough of a speed improvement for an uncommon case. In retrospect, however, it also didn&#8217;t work for all bytecode (although it may have worked for all bytecode produced by the Python compiler). Imagine if there were a jump to the LOAD_FAST from somewhere else in the code &#8212; for example, in the code
</p>
<pre>if x:
  r = 1
else:
  r = 2
return r
</pre>
<p>The last seven bytes of the bytecode would still initially look like:
</p>
<pre>...
STORE_FAST n
LOAD_FAST n
RETURN_VALUE
</pre>
<p>But if the store and load were removed, then the jump would lead directly to the return, which would result in a stack underflow.
</p>
<p>This neatly illustrates why doing anything on the bytecode level is a huge hassle. I went through a number of schemes to try to eliminate unnecessary store/load pairs at the bytecode level, but trying to figure out variable lifespans in the presence of forward and backwards jumps is not easy.
</p>
<p>I decided instead to take a suggestion made when I submitted my (broken) patch, and work at the AST level. <a href="http://www.deskchecked.com/">Thomas Lee</a> has been working on an AST-level optimizer. He wrote a set of functions that walk the AST and perform optimizations at each level. I also changed my focus, because I was a bit bored of thinking about local variables, and I wanted something easy for my first look at high-level C code in a long time.
</p>
<p>Python bytecode includes at least one operation which is not directly accessible from Python code: LIST_APPEND, which pops a value and a list off the stack and appends the value to the list. This is used in generating code for list comprehensions:
</p>
<pre>[x for x in somelist]
</pre>
<p>generates the following code for the body of the loop:
</p>
<pre>...
LOAD_FAST 1#a local is generated to hold the new list
LOAD_FAST 2 #the iteration variable, x
LIST_APPEND
...
</pre>
<p>Whereas if you were to try to write the comprehension with a for loop, you would get:
</p>
<pre>LOAD_FAST 1
LOAD_ATTR 0 #an index into the constant table: "append"
LOAD_FAST 2
CALL_FUNCTION 1 #remove x and the append function from the top of the stack and push the result of the call
POP_TOP
</pre>
<p>This is much slower. In part, it&#8217;s the cost of doing the attribute lookup each time, which is why it&#8217;s common to see code like
</p>
<pre>a = []
ap = a.append
for x in .....:
&nbsp; ap(x + ...)
return a
</pre>
<p> But the function call is naturally slower than the simpler LIST_APPEND operation. My new patch tries to determine statically if a local is all circumstances holds a list, and if so, generates LIST_APPEND whenever user code would call local.append. It&#8217;s not perfect &#8212; in particular, I could track local types on a more fine-grained level than per-function. But it&#8217;s a start. I submitted it today.
</p>
<p>Next, I think I&#8217;ll consider local elimination again &#8212; but at the AST level.­</p>
]]></content:encoded>
			<wfw:commentRss>http://www.openplans.org/projects/topp-engineering/blog/2008/11/03/optimizing-python/feed/</wfw:commentRss>
		</item>
		<item>
		<title>What Bothers Me About The Component Architecture</title>
		<link>http://www.openplans.org/projects/topp-engineering/blog/2008/10/20/what-bothers-me-about-the-component-architecture/</link>
		<comments>http://www.openplans.org/projects/topp-engineering/blog/2008/10/20/what-bothers-me-about-the-component-architecture/#comments</comments>
        	<slash:comments>8</slash:comments> 
		<pubDate>Mon, 20 Oct 2008 18:02:30 +0000</pubDate>
		<dc:creator>ianb</dc:creator>
                <opencore:userid>ianb</opencore:userid>
		
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.openplans.org/projects/topp-engineering/blog/2008/10/20/what-bothers-me-about-the-component-architecture/</guid>
		<description><![CDATA[ I&#8217;m not a big fan of the Zope 3 Component Architecture.&#160; A couple packages came out recently that made it clearer to me why.

The packages in question are repoze.bfg.httprequest&#160; and r­epoze.bfg.restrequest­.&#160; restrequest is easier to understand because it is more concrete: basically it adds marker interfaces to your request object for the request method, [...]]]></description>
			<content:encoded xml:base="http://www.openplans.org/projects/topp-engineering/blog/2008/10/20/what-bothers-me-about-the-component-architecture/"><![CDATA[<p> I&#8217;m not a big fan of the <a href="http://wiki.zope.org/zope3/ComponentArchitectureOverview">Zope 3 Component Architecture</a>.&nbsp; A couple packages came out recently that made it clearer to me why.
</p>
<p>The packages in question are <a href="http://pypi.python.org/pypi/repoze.bfg.httprequest">repoze.bfg.httprequest</a>&nbsp; and <a href="http://pypi.python.org/pypi/repoze.bfg.restrequest">r­epoze.bfg.restrequest</a>­.&nbsp; restrequest is easier to understand because it is more concrete: basically it adds marker interfaces to your request object for the request method, and you can add request_type=IGetRequest to your view declarations, hence declaring that a view is only applicable to that request method.&nbsp; You can do this with a decorator like:
</p>
<pre>@bfg_view(request_type=IGETRequest, for_=models.IMyModel)
def my_view_get(context, request):
    return Response("GETn")
</pre>
<p>Right now <a href="http://static.repoze.org/bfgdocs/">repoze.bfg</a> (a web framework) uses interfaces to do it&#8217;s dispatch to views, so this adds the ability to dispatch on request method.&nbsp; The existence of these packages bothers me a great deal, and it took a while to figure out why.&nbsp; These are entirely packages, with docs, tests, etc., that express something trivial.&nbsp; If repoze.bfg supported conditionals on views &#8212; functions that would indicate if the view was applicable to a request &#8212; then you could express this like:
</p>
</p>
<pre>@bfg_view(for_requests=lambda req: req.method=='GET', for_=models.IMyModel)
def my_view_get(context, request):
    return Response("GETn")­
</pre>
<p>This is basically what <a href="http://routes.groovie.org/">Routes</a> has done, though it additionally added request-method-dispatch as a primitive (just a keyword like method=&#8217;GET&#8217;).&nbsp; I think this is a much nicer construct, and no extra packages are required.&nbsp; More importantly, it doesn&#8217;t just <em>read</em> well (arguably IGETRequest reads a bit better), but it is easy to understand the <em>mechanism</em> and to extend or adjust that mechanism.&nbsp; If you want to dispatch based on the Accept header, you just use for_requests=lambda req: &#8216;application/xml&#8217; in req.accept.&nbsp; If you don&#8217;t want to write lambdas, you can just abstract this in the obvious way in a separate function or a class with a __call__ attribute.
</p>
<p>OK, so that&#8217;s simple enough: repoze.bfg should support this construct, and it&#8217;s just an unfortunately and hopefully temporary awkwardness that caused these libraries to be written.&nbsp; In theory anyone could, right now, write an alternative implementation of @bfg_view that accepts this.&nbsp; Of course, anyone could spend an hour or two and write a new framework from scratch, which makes this a less compelling argument: if someone decides to use repoze.bfg instead of writing their own framework or using a different framework, it&#8217;s not because they want to write or maintain their own infrastructure, or be in the situation where they&#8217;d ask &#8220;can you help me, but oh by the way I&#8217;m not actually using your stuff&#8221;?
</p>
<p>The other reason for this, I think, is ZCML.&nbsp; Here&#8217;s another way of expressing method-based dispatch:
</p>
</p>
<pre>&lt;bfg:view for=".models.IMyModel"
      request_type="repoze.bfg.restrequest.interfaces.IGETRequest"
      view=".views.my_view_get"
      /&gt;
</pre>
<p>There&#8217;s no place to put functions into ZCML, but there is room for interfaces.&nbsp; And more generally, interfaces are the tool that comes to mind most commonly when using the Component Architecture.&nbsp; I think it leads to this kind of anti-pattern all too often, the use of marker interfaces and the accompanying indirection when a simple function would do.&nbsp; There&#8217;s a claim that interfaces allow for more flexibility, but this is simply false: functions are completely general and ameniable to any kind of abstraction you want.&nbsp; Interfaces add <em>indirection</em>, and sometimes that&#8217;s useful, but in many cases like this the indirection is added before there&#8217;s any need for it, and when there might never be a need for it.
</p>
<p>It can be hard for me sometimes to articulate what bothers me about Zope 3-style architectures, because it&#8217;s hard to point to what exactly the alternative would be.&nbsp; Usually the alternative is: a few lines of code.&nbsp; Code is a powerful and extremely general abstraction, and especially in a dynamic language like Python the amount of abstraction you can add is substantial.&nbsp; And you don&#8217;t need to add the abstraction until you need it.&nbsp; So usually the alternative I see to the Component Architecture is simply a few lines of code, written for the specific case that is at hand.<br />
  </p>
]]></content:encoded>
			<wfw:commentRss>http://www.openplans.org/projects/topp-engineering/blog/2008/10/20/what-bothers-me-about-the-component-architecture/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Xinha at TOPP</title>
		<link>http://www.openplans.org/projects/topp-engineering/blog/2008/10/11/xinha-at-topp/</link>
		<comments>http://www.openplans.org/projects/topp-engineering/blog/2008/10/11/xinha-at-topp/#comments</comments>
        	<slash:comments>0</slash:comments> 
		<pubDate>Sat, 11 Oct 2008 06:24:06 +0000</pubDate>
		<dc:creator>Ethan Jucovy</dc:creator>
                <opencore:userid>ejucovy</opencore:userid>
		
		<category><![CDATA[xinha]]></category>

		<guid isPermaLink="false">http://www.openplans.org/projects/topp-engineering/blog/2008/10/11/xinha-at-topp/</guid>
		<description><![CDATA[



We&#8217;ve been using Xinha at TOPP for a while, and with two of us now core developers, I thought it would be worthwhile to try to hash out what we&#8217;re hoping to get out of our investment in Xinha.&#160; Here, as a first step, is a discussion of Xinha-related goals and strategies that Doug, Nick [...]]]></description>
			<content:encoded xml:base="http://www.openplans.org/projects/topp-engineering/blog/2008/10/11/xinha-at-topp/"><![CDATA[<div>
<div>
<div>
<div>
<p>We&#8217;ve been using <a href="http://xinha.org/">Xinha</a> at TOPP for <a href="http://blog.ianbicking.org/evaluating-wysiwyg-editors.html">a while</a>, and with <a href="http://douglas.mayle.org/">two</a> <a href="http://www.nicholasbs.com/">of us</a> now core developers, I thought it would be worthwhile to try to hash out what we&#8217;re hoping to get out of our investment in Xinha.&nbsp; Here, as a first step, is a discussion of Xinha-related goals and strategies that Doug, Nick B-­S, Sonali, Ian and I all agree on.
        </p>
<p>&nbsp;
        </p>
<h3>Goals<br />
        </h3>
</p></div>
<div>
<p><em>This section will address the goals which inform and are served by our commitment to Xinha.</em>
        </p>
<p>1. Promote a document model of the web for easy human-readability, machine-readability and interoperability in a broader network of applications and services.
        </p>
<p>2. Build best-of-breed tools which can be repurposed for a variety­ of uses and in a variety of contexts, and which are good enough to attract business and financing on their own, whether as standalone products or as candidates for integration into other products.
        </p>
<p>3. Develop real communities of users and developers to collectively steer and own the software that we are involved with, with TOPP&#8217;s role in each limited to that of an initial catalyst if necessary, and to that of one equal user, producer and beneficiary among many.
        </p>
<p>4. Provide a solid base of tools to enable more and richer creation, editing and remixing of documents on the web to enable a more free and active exchange of communications, ideas and culture.
        </p>
<p>5. Help as many people as possible through our work, whether their rel­ationship to that work is casual or committed, technical or non-technical.
        </p>
<p>&nbsp;
        </p>
<h3>Strategies<br />
          <br />
        </h3>
<p><em>This section will address the strategic directions we have set for our involvement with Xinha to further our broad goals.</em>
        </p>
<p><a href="#g1">1.</a> An essential c­omponent of the strategy is developing and promoting useful and easy tools for web document creation and editing.­
        </p>
<ul>
<li>To promote wide adoption, we must provide end-user value up front and allow our own value to naturally emerge from the user&#8217;s intentional actions.&nbsp; To that end, our tools must push HTML and CSS down to the level of implementation details for the casual end user, and the casual user&#8217;s preferred actions should epiphenominally contribute to a document-driven web.</li>
<li>To promote deep adoption, we must instruct interested end users in the philosophy and practice of the document model.&nbsp; To that end, our tools must provide tiered layers of value which simultaneously steer end users toward a deeper understanding of the underlying technologies and reward curious end users for their hard-won knowledge with increased functionality or flexibility &#8212; but without sacrificing the immediate value of a casual user&#8217;s interactions with the tools: upfront investment not required, and learning curves remaining smooth. </li>
</ul>
<p>&nbsp;
        </p>
<p><a href="#g2">2.</a> A WYSIWYG text editor is a very promising candidate to add to our portfolios of tools and expertise; it has broad applicability and appeal.&nbsp; Because of the nature of a WYSIWYG editor, it is not likely to be a direct source of funding or work; rather, its value will mainly come from reusing it as a component of increasingly many projects.&nbsp; Its presence in our portfolio increases the value of our portfolio as a whole.
        </p>
<ul>
<li>To ensure reusability for a variety of uses, the software must provide flexible functionality and user interface.&nbsp; To that end, the software should provide a sensible (and, ideally, requiring no deep technical knowledge) configuration layer, enable plugin development and skinning capabiities, and should provide tools to minimize the effort and overhead of reconfiguration.</li>
<li>To ensure reusability in a variety of contexts, the software must be easy to install, decoupled from any particular broader environment, and integratable into any number of broader environments.&nbsp; To that end, the software must rely upon and promote general standards and best practices for intercommunication and integration of application components.</li>
<li>To build a best-of-breed WYSIWYG editor, the software must implement powerful functionality solidly and must present an extremely appealing interface to users.&nbsp; To that end, we need to identify that functionality and interface by iterative use and user feedback. </li>
</ul>
<p>&nbsp;
        </p>
<p><a href="#g3">3.</a> Xinha has a history of community activity and has a commitment to real collective code ownership; it is rightly billed as &#8220;the community-built open source online HTML editor.&#8221;<br />
          
        </p>
<ul>
<li>To ensure that Xinha remains owned by its community and not by TOPP or any other organization, we must be careful not to put anything into the core repository which narrowly serves TOPP&#8217;s needs or does not have the support of the community.</li>
<li>To encourage an active and dedicated community to steer the project, we should pursue initiatives to increase Xinha&#8217;s visibility and to build interest and enthusiasm, and we should be prepared to offer any necessary organizational resources toward infrastructure for an open source community.</li>
</ul>
<p>&nbsp;
        </p>
<p><a href="#g5">5.</a> In addition to building a great WYSIWYG editor, we should <a href="http://douglas.mayle.org/2008/10/03/the-wild-west-of-javascript/">actively share the domain-specific knowledge </a>we gain in the process of building it.
        </p>
</p></div>
</p></div>
</p></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.openplans.org/projects/topp-engineering/blog/2008/10/11/xinha-at-topp/feed/</wfw:commentRss>
		</item>
		<item>
		<title>contentmirror</title>
		<link>http://www.openplans.org/projects/topp-engineering/blog/2008/10/10/contentmirror/</link>
		<comments>http://www.openplans.org/projects/topp-engineering/blog/2008/10/10/contentmirror/#comments</comments>
        	<slash:comments>0</slash:comments> 
		<pubDate>Fri, 10 Oct 2008 17:10:30 +0000</pubDate>
		<dc:creator>Robert Marianski</dc:creator>
                <opencore:userid>rmarianski</opencore:userid>
		
		<category><![CDATA[ploneconf]]></category>

		<guid isPermaLink="false">http://www.openplans.org/projects/topp-engineering/blog/2008/10/10/contentmirror/</guid>
		<description><![CDATA[ At ploneconf, Kapil gave an interesting talk on a project called contentmirror (http://code.google.com/p/contentmirror/). It allows you to serialize your plone content into a relational database, in a pretty transparent way. It does this by hooking into the zope3 lifecycle events, and pushes the data out to the database synchronously in the same thread.


  [...]]]></description>
			<content:encoded xml:base="http://www.openplans.org/projects/topp-engineering/blog/2008/10/10/contentmirror/"><![CDATA[<p> At ploneconf, Kapil gave an interesting talk on a project called contentmirror (<a href="http://code.google.com/p/contentmirror">http://code.google.com/p/contentmirror/).</a> It allows you to serialize your plone content into a relational database, in a pretty transparent way. It does this by hooking into the zope3 lifecycle events, and pushes the data out to the database synchronously in the same thread.
</p>
<p>
  <br />Although I haven&#8217;t tried it myself, the process looked easy, simple, and straightforward. Kapil made a conscious effort to keep it simple, and work for the most common use cases. Other scenarios will require using custom adapters.
</p>
<p>
  <br />It is a one way sync however. Any writes back to the relational database will not be reflected in the plone site. And, by default it will only catch archetypes. If you have other content types, you&#8217;d have to write custom adapters to get it working.
</p>
<p>
  <br />Using contentmirror can be useful for plone sites where you&#8217;d like to share the data with other applications. This opens up some exciting possibilities, like being able to use the django admin to look at the plone data. Anything that works with sql should be workable. It&#8217;s fairly new, but it&#8217;ll be interesting to see what people do with it.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.openplans.org/projects/topp-engineering/blog/2008/10/10/contentmirror/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Respect and conversation on PlanetDev</title>
		<link>http://www.openplans.org/projects/topp-engineering/blog/2008/09/30/respect-and-conversation-on-planetdev/</link>
		<comments>http://www.openplans.org/projects/topp-engineering/blog/2008/09/30/respect-and-conversation-on-planetdev/#comments</comments>
        	<slash:comments>5</slash:comments> 
		<pubDate>Tue, 30 Sep 2008 23:25:45 +0000</pubDate>
		<dc:creator>Ethan Jucovy</dc:creator>
                <opencore:userid>ejucovy</opencore:userid>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.openplans.org/projects/topp-engineering/blog/2008/09/30/respect-and-conversation-on-planetdev/</guid>
		<description><![CDATA[The other day I saw that Rollie had tagged http://www.kottke.org/08/09/tech-conference-panels-suck for inclusion in the PlanetDev feed.
I found that seeing it there and reading it really upset me.&#160; Jackie saw me get upset and helped me realize that there were actually some broadly useful points to share about why it did and what this means in [...]]]></description>
			<content:encoded xml:base="http://www.openplans.org/projects/topp-engineering/blog/2008/09/30/respect-and-conversation-on-planetdev/"><![CDATA[<p>The other day I saw that Rollie had tagged <a href="http://www.kottke.org/08/09/tech-conference-panels-suck">http://www.kottke.org/08/09/tech-conference-panels-suck</a> for inclusion in the <a href="http://planetdev.openplans.org">PlanetDev</a> feed.</p>
<p>I found that seeing it there and reading it really upset me.&nbsp; Jackie saw me get upset and helped me realize that there were actually some broadly useful points to share about why it did and what this means in a greater context, so at her suggestion I&#8217;m going to try to unpack them here.</p>
<p>The referenced post &#8212; and the post that *it* references &#8212; is basically contentless.&nbsp; Some <a href="http://www.wired.com/culture/lifestyle/news/2005/02/66679">popular blogger</a> is linking to someone&#8217;s writeup of their personal impressions of a single panel at a tech conference.&nbsp; He&#8217;s not adding any particular commentary of his own so presumably it&#8217;s an approving reference.&nbsp; So for the essential content we go to the &nbsp;<a href="http://realdanlyons.com/blog/2008/09/24/emtech-inanity/">original reference</a> itself.&nbsp; That post is equally contentless: as Kottke correctly observes with his summary headline, the post is meant to put forth a general theory about technical conferences and the &#8220;geeks&#8221; who organize and attend them&nbsp; via a proof by anecdote.&nbsp; It says: &#8220;I attended this one event, I felt this way about it, therefore I can offer general observations on a whole class of events and people.&#8221;&nbsp; Well, we all know how rigorous that line of argument is.</p>
<p>Just for fun, though, let&#8217;s take it to its logical conclusion.&nbsp; What, actually, is being put forth here?&nbsp; That panels at tech conferences suck &#8212; because some guy on the internet went to one conference panel with an absurdly broad topic and didn&#8217;t get anything out of it except a lousy blog post &#8212; and so, I suppose, we should conclude that we shouldn&#8217;t be spending our time, energy and money on tech conferences?&nbsp; Is this really a conversation worth having?&nbsp; Of course there are good conferences and less valuable conferences in every field and discipline, from geology to nursing to quilting.&nbsp; And at each conference, the individual sessions and panels will have a whole range of quality and outcomes.&nbsp; To draw any conclusions about the broad category of tech conferences from a single failed panel at a single event is ignoring this reality and generalizing to what should be an obvious point of absurdity.&nbsp; Come on.</p>
<p>So, essentially, it feels like this tagged item simply doesn&#8217;t contribute anything to a conversation; it&#8217;s a dead-end post with no information to impart and no worthwhile lessons to be drawn.&nbsp; Its appearance on PlanetDev is an invasion of our communal space, and we all individually waste our time discovering its lack of value.</p>
<p>The world is full of those little distractions, though, and while I don&#8217;t like them, I don&#8217;t usually get too emotional when I see a Google Sponsored Link.&nbsp; But of course this post&#8217;s content is not just unproductive; it&#8217;s unabashedly, gleefully insulting, playing to offensive stereotypes.&nbsp; Har, har, tech &#8220;geeks&#8221; have no social skills, have no grounding in reality, get excited about techno-fantastical topics, aren&#8217;t good at explaining themselves.&nbsp; Oh, and let&#8217;s mock their various supposed developmental disorders and drug indulgences!</p>
<p>This type of content sort of bothers me personally, but it points to something broader than just that.&nbsp; While I&#8217;m sure this was totally unintentional, by putting this on PlanetDev Rollie effectively just pushed this type of stereotyping and mockery out into our group.&nbsp; And, honestly, I really hope that we&#8217;re better than that, that we can create a culture of respect and collaboration here at TOPP, a safe space where no one will be mocked by a coworker for his interests or through implied association with a stereotype.&nbsp; I can&#8217;t imagine anyone here is interested in descending into petty warring tribes based on our job descriptions.&nbsp; So, please, let&#8217;s not get into the business of trading insults between designers and engineers, or any other &#8220;subgroups&#8221; at TOPP; let&#8217;s be respectful of each other and of everyone&#8217;s individual skills and interests, let&#8217;s work together without rivalry, and let&#8217;s respect our public spaces.<br />
<br /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.openplans.org/projects/topp-engineering/blog/2008/09/30/respect-and-conversation-on-planetdev/feed/</wfw:commentRss>
		</item>
		<item>
		<title>pyinstall: A New Hope</title>
		<link>http://www.openplans.org/projects/topp-engineering/blog/2008/09/24/pyinstall-a-new-hope/</link>
		<comments>http://www.openplans.org/projects/topp-engineering/blog/2008/09/24/pyinstall-a-new-hope/#comments</comments>
        	<slash:comments>15</slash:comments> 
		<pubDate>Wed, 24 Sep 2008 05:20:25 +0000</pubDate>
		<dc:creator>ianb</dc:creator>
                <opencore:userid>ianb</opencore:userid>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.openplans.org/projects/topp-engineering/blog/2008/09/24/pyinstall-a-new-hope/</guid>
		<description><![CDATA[Note: since this was written I have renamed pyinstall to pip.
  

­Have you ever been frustrated by easy_install? Yeah, me neither. But I have heard whispers of discontent.

So I&#8217;m introducing a new tool for the installation of Python packages: pyinstall.

pyinstall is mostly easy_install compatible. That means it finds distributions in the same way as [...]]]></description>
			<content:encoded xml:base="http://www.openplans.org/projects/topp-engineering/blog/2008/09/24/pyinstall-a-new-hope/"><![CDATA[<p><strong>Note:</strong> since this was written I have renamed pyinstall to <a href="http://pip.openplans.org">pip</a>.<br />
  
</p>
<p>­Have you ever been frustrated by <a href="http://peak.telecommunity.com/DevCenter/EasyInstall">easy_install</a>? Yeah, me neither. But I have heard whispers of discontent.
</p>
<p>So I&#8217;m introducing a new tool for the installation of Python packages: <a href="http://pypi.python.org/pypi/pyinstall">pyinstall</a>.
</p>
<p>pyinstall is mostly easy_install compatible. That means it finds distributions in the same way as easy_install and it installs packages via setuptools. If you are familiar with easy_install you&#8217;ll know how to use pyinstall right away. This is not a repudiation of the mechanisms of easy_install, but a refinement. What does it refine?
</p>
<p>First, it is a more user friendly easy_install. It collects everything it needs before it installs anything. The console output is intended to be concise and helpful. It says *why* it is doing things, tracking the set of dependencies that led to the installation of each package, and some of how it found the packages. It knows a little more about Subversion than easy_install, and I plan to add native support for other version control systems directly to it (this is easier now than it would have been a few years ago, since it seems there&#8217;s a clear and finite set of viable version control systems).
</p>
<p>It also has some added features that I think are important for version management. Specifically the features of its predecessor PoachEggs, which you may not have heard of - but pyinstall at this point is at least a third-generation implementation of these ideas, if not more. You can install a set of packages from a &#8220;requirements file&#8221;, which really is little more than a list of packages to install. This is a seemingly small improvement, but the idea is to move requirements <em>out of setup.py</em> and into something that is managed separately from any library or package. By separating out this management you can control the application environments without having to touch the applications or libraries themselves. In addition you can generate new requirements files from a working installation: just run <code>pyinstall --freeze=requirements.txt</code> and it will write out a file that can be used to install the <em>exact version</em> of everything that is installed. One of the most common complaints about easy_install once you get second-order dependencies is that you can&#8217;t easily reproduce working environments, and this fixes that.
</p>
<p>Another feature is a &#8220;pybundle&#8221;, which is just an archive of a set of libraries. Here&#8217;s something you can try:
</p>
<pre>$ virtualenv my-app
$ cd my-app
$ source bin/activate
... set up my-app environment just how you want it ...
$ pyinstall.py --freeze=my-app-req.txt
$ pyinstall.py --bundle=my-app.pybundle -r my-app-req.txt
... then on another machine ...
$ pyinstall.py my-app.pybundle
</pre>
<p>The pybundle format is pretty simple: it&#8217;s a lot of source files in one zip file. It isn&#8217;t a binary package format at all, it&#8217;s just source, and all it saves you is the finding and downloading of packages. But I think that simple process is a big part of why no-dependency libraries and frameworks are sought after (not to say that&#8217;s the <em>only</em> reason).
</p>
<p>Despite the many rewrites preceeding this, pyinstall is still very young &#8212; but for the most part if you get something installed, then it worked, and if it didn&#8217;t get something installed then you can always fall back on easy_install (and <a href="http://trac.openplans.org/poacheggs">submit a bug report</a>).&nbsp; If you have suggestions, also submit a ticket or ask about it on the <a href="http://groups.google.com/group/python-virtualenv/">virtualenv list</a>.
</p>
<p>To get started: <code>easy_install pyinstall</code>­ or jus­t grab the <a href="https://svn.openplans.org/svn/pyinstall/trunk/pyinstall.py">single-file executable</a>.<br />
  </p>
]]></content:encoded>
			<wfw:commentRss>http://www.openplans.org/projects/topp-engineering/blog/2008/09/24/pyinstall-a-new-hope/feed/</wfw:commentRss>
		</item>
		<item>
		<title>My first Django app</title>
		<link>http://www.openplans.org/projects/topp-engineering/blog/2008/08/12/my-first-django-app/</link>
		<comments>http://www.openplans.org/projects/topp-engineering/blog/2008/08/12/my-first-django-app/#comments</comments>
        	<slash:comments>3</slash:comments> 
		<pubDate>Wed, 13 Aug 2008 00:15:11 +0000</pubDate>
		<dc:creator>Paul Winkler</dc:creator>
                <opencore:userid>slinkp</opencore:userid>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.openplans.org/projects/topp-engineering/blog/2008/08/12/my-first-django-app/</guid>
		<description><![CDATA[I&#8217;m about to head off on vacation, so this seemed like as good a time as any to kick this out of my drafts folder&#8230;&#160;

 As some of you know, I&#8217;ve been doing the brainpower project as a Django admin application.

The reasons for this decision were:
  


Django admin is touted as a very quick [...]]]></description>
			<content:encoded xml:base="http://www.openplans.org/projects/topp-engineering/blog/2008/08/12/my-first-django-app/"><![CDATA[<p>I&#8217;m about to head off on vacation, so this seemed like as good a time as any to kick this out of my drafts folder&#8230;&nbsp;
</p>
<p> As some of you know, I&#8217;ve been doing the <a href="http://openplans.org/projects/brainpower">brainpower</a> project as a <a href="http://www.djangobook.com/en/1.0/chapter06/">Django admin</a> application.
</p>
<p>The reasons for this decision were:<br />
  
</p>
<ul>
<li>Django admin is touted as a very quick way to build CRUD applications, since it generates a UI from your model that in many cases is good enough for end users. No forms to write, maybe just a little tweaking. Brainpower is nothing other than a simple CRUD application, so this sounded like a perfect match.<br />
   </li>
<li>Good excuse to learn a little about Django.<br />
   </li>
<li>Get me to do something other than Zope for once in my freakin&#8217; life. </li>
</ul>
<p>
  <br />So how did that pan out?
</p>
<p>Well, in one month since our first requirements-gathering meeting with our &#8220;customer&#8221; (Liz and Robin from Streetfilms), in addition to all the other stuff I&#8217;ve been doing, I built something they said was good enough to start using. I did in really just a week or so of work, alone, from scratch, with almost zero advance knowledge of Django. I even spent some time testing and tuning performance (just enough that I feel confident we won&#8217;t ever have a problem with it). This also includes a full suite of Flunc tests; a random content generation script that I used for the performance tests; and a build script for development &amp; deployment using Fassembler.
</p>
<p>The core code is tiny: the bulk of it is in a 250-line models.py module that is reasonably clean.
</p>
<p> As usual, writing the core code is only a small part of the story. A large portion of my time went to things like figuring out how to conveniently run external functional tests against django with a scratch database, writing and fixing the build script, and troubleshooting my initial attempts at deployment (tripping on <a href="http://code.djangoproject.com/ticket/7595">a django bug</a>.).
</p>
<p>I do have some general early impressions of Django.
</p>
<h3>Things I liked<br />
</h3>
<ul>
<li>The admin interface is, indeed, pretty slick (with a few minor oddnesses like a pretty useless Time widget).</li>
<li>If I had another little CRUD app to build that seemed well-matched for Django, I could probably do it <em>ridiculously</em> fast.</li>
<li>The Django docs are pretty decent for the most part, much better than the current state of, say, Zope 2 docs, and more extensive and thorough than the Pylons docs. (Too bad I had to quickly un-learn a bunch of stuff when I had to switch to developing against more recent django checkouts.)</li>
<li>The stable release&#8217;s way to create an admin UI &#8212; by writing an inner class named Admin inside your Model &#8212; smelled really bad to me. Thankfully, this is gone in the newforms-admin branch. Similarly, you used to wire up custom validators inside your Model class and do cleanup in its save() method; now you can do custom validation in a ModelForm subclass, and you can do data cleanup in the same place. Newforms-admin is pretty nice!<br />
  </li>
<li>Got a multiple choice field that you need users to be able to extend with new choices?&nbsp; Just add a foreign key field to your model referencing another model, and it just plain works in exactly the way you&#8217;d hope.&nbsp; Slick!<br />
  </li>
</ul>
<p>
  
</p>
</p>
<h3>Gripes<br />
</h3>
<ul>
<li>I wish they had used an existing template language, I don&#8217;t see anything compellingly different about Django&#8217;s.<br />
   </li>
<li>I wish Django&#8217;s setup.py had a &#8220;develop&#8221; command.</li>
<li>I wish the tools for syncing your models to your database were more developed. You seem to be entirely on your own for migrations. For example, if you modify the type of a field in a Model, you&#8217;ll likely need to either drop your tables and recreate them, or if you have production data to preserve, either do a dump-modify-restore cycle or hand-hack the database in place to keep your app working. At one point I ended up needing to do a dump-modify-restore using xml exports and lxml transforms; it took longer than I would have liked and I might try another strategy next time. For other model modifications such as adding a field, you might be able to get away with re-running manage.py syncdb; unfortunately I don&#8217;t know how to predict when this will just work and when it won&#8217;t.</li>
<li>I wish all Django manage.py operations could be performed non-interactively. For example, for my flunc tests I wanted to reliably create and destroy a scratch database with a test admin user. Django provides a way to do most of this, but the commands that create an admin user must be run interactively. I tried using a database fixture, but that didn&#8217;t work reliably &#8212; I&#8217;m wildly guessing there&#8217;s some salt that gets reset and I don&#8217;t know when? I ended up having my test script use <a href="http://www.noah.org/wiki/Pexpect">pexpect</a> to drive the interactive commands.</li>
<li>It seems I arrived at an inconvenient time. Django 0.96.2 may be the &#8220;latest stable release&#8221;, but it&#8217;s aging. The developers are all focused on a &#8220;newforms-admin&#8221; branch, which is cleaner and more extensible, but this work hasn&#8217;t landed on trunk yet. I don&#8217;t know when that will happen, or what else will change before another stable release. I opted to develop against the old stable release. I thought I was being smartly conservative :-p Unfortunately I soon hit a <a href="http://code.djangoproject.com/ticket/7528">really irritating bug</a>. While trying to understand the admin code enough to find a workaround (and feeling like I was on <a href="http://www.google.com/search?hl=en&amp;q=z+shaped+learning+curve+zope&amp;btnG=Search">a familiar learning curve</a>), I was advised to check if trunk still had the same problem, which meant an hour or two adjusting my code to work against trunk. Trunk turned out to fix only half of the problem. Then a week later the bug got fully fixed&#8230; on the newforms-admin branch. So much for trying to stick to a stable release! Maybe I was just unlucky. If I didn&#8217;t need to search fields from a join, I wouldn&#8217;t have hit this bug. (But isn&#8217;t that a common need?)<br />
   </li>
<li>Customizing and extending the admin UI is commonly done in a way that also seems <a href="http://plone.org/documentation/tutorial/creating-plone-themes">vaguely familiar</a>: You just make a copy of the thing you want to modify and hack away on it. I&#8217;ve already had a hint of pain with this &#8212; my two modified template copies broke on both Django upgrades. That&#8217;s how things typically go in the Plone world: Every single skin override you did on a Plone site would add a drop of future pain to every Plone upgrade you ever tried to do.
<p>This is a hard problem to solve. Just as Plone did, Django admin seems to be gradually adding more plug-in extension points so you don&#8217;t have to override the core templates as often; instead you just flip some configuration switch and/or add another template that magically gets slurped into the right place. Which has its own headaches, as every one of those bits of flexibility adds to the learning curve.&nbsp; Let&#8217;s hope <a href="http://en.wikipedia.org/wiki/Greenspun's_Tenth_Rule">Greenspun&#8217;s Tenth</a> doesn&#8217;t grow a corollary substituting Plone for Lisp :-]<br />
  </li>
</ul>
<p>
  </p>
]]></content:encoded>
			<wfw:commentRss>http://www.openplans.org/projects/topp-engineering/blog/2008/08/12/my-first-django-app/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
