<?xml version="1.0" encoding="UTF-8"?>
<!--Generated by Squarespace V5 Site Server v5.13.158 (http://www.squarespace.com) on Wed, 22 May 2013 02:35:56 GMT--><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>Journal</title><link>http://www.stuartmitchell.com/journal/</link><description></description><lastBuildDate>Mon, 27 Feb 2012 01:19:55 +0000</lastBuildDate><copyright></copyright><language>en-NZ</language><generator>Squarespace V5 Site Server v5.13.158 (http://www.squarespace.com)</generator><item><title>My top n tips for python coding in Optimisation</title><dc:creator>Stuart Mitchell</dc:creator><pubDate>Thu, 02 Feb 2012 22:29:26 +0000</pubDate><link>http://www.stuartmitchell.com/journal/2012/2/3/my-top-n-tips-for-python-coding-in-optimisation-1.html</link><guid isPermaLink="false">729339:8553842:14845612</guid><description><![CDATA[<ol>
<li><p>Always write code for readability first.
Pre-optimisation is the root of a lot of evil and often makes the code more difficult to    improve later.
see <a href="http://chrisarndt.de/talks/rupy/2008/output/slides.html">http://chrisarndt.de/talks/rupy/2008/output/slides.html</a> for what is pythonic 
The python language is really been written to make the clearest code the most efficient see Ted's 
example where
<pre>   >>> for key in my_dict:</pre>
      looks better and is more efficient then
<pre>    >>> for key in my_dict.keys():</pre>
<p>which is inefficient as it creates a new list instead of returning an iterator
</li>
<li><p>If your code is slow use a profiler to find out why before you make changes.
Either use the logging module and print timestamps or use the cProfile module. 
I can't tell you the number of times I have assumed the slow code was for one reason and then found 
it was another.
Also <a href="http://code.google.com/p/jrfonseca/wiki/Gprof2Dot">http://code.google.com/p/jrfonseca/wiki/Gprof2Dot</a> is an excellent tool for making pretty graphs</p></li>
<li><p>Rigorously validate any optimisation. 
If your changes don't speed up the code revert them, this is a sliding scale for readability as above,
so if you change improves readability but does not change the execution time leave it in.
If your change makes the code impossible to read and understand, use lots of comments and only 
keep it if the speed increase is more than 30% or one minute.</p></li>
<li><p>(actual python hints start here)
Too much filtering
I have seen this a number of times when a using list comprehensions the programmer filters the same 
list multiple times.
For instance in a machine scheduling problem (written in pulp, product_mapping is a list of machines a 
product can be made on and allocate is a dictionary of variables allocating products to machines)
<pre>   
   for m in machines:
       prob += lpSum(allocate[p, m] for p in products if m in product_mapping[p]) <= 10
</pre>
<p>If there are a large number of products it is much better to iterate through that list once and compile a 
mapping of machines to products
<pre>   
   machine_mapping = {}
   for p, m_list in product_mapping.iteritems():
        for m in m_list:
            products = machine_mapping.setdefault(m, [])
            products.append(p)
   for m in machines:
       prob += lpSum(allocate[p, m] for p in machine_mapping[m]) <=10</p>
</pre>
</li>
<li><p>For large lists try to use generator expressions instead of list comprehensions, or in other words return iterators instead of full lists.
In Ted's example dict.keys() returns a new list that if the dictionary is big can hurt performance while dict.iterkeys() will return an iterator and will not have to build a new list each time.
Note</p>

<pre>   >>> for key in my_dict:
</pre>
      and 
<pre>   >>> for key in my_dict.iterkeys():
</pre>
      are equivalent </p>


<p>example 2 (summing odd numbers less then 1000)
Bad</p>

<pre>
      >>> total = 0
      >>> for i in [j for j in range(1000) if j % 2 == 0]:
      ...        total += i
</pre>
      Better (generator expression)
<pre>
      >>> total = 0
      >>> for i in (j for j in range(1000) if j % 2 == 0):
      ...        total += i
</pre>
      Even Better (xrange instead of range)
<pre>
      >>> total = 0
      >>> for i in (j for j in xrange(1000) if j % 2 == 0):
      ...        total += i
</pre>
      Best
<pre>
      >>> total = sum(j for j in xrange(1000) if j % 2 == 0)
</pre>

<p>This is only an issue with large lists n >= 1000000 in this case</p>

<pre>
      >>> from timeit import timeit
      >>> timeit('sum([j for j in range(1000000) if j % 2 == 0])', number=100)
      27.90494394302368
      >>> timeit('sum(j for j in range(1000000) if j % 2 == 0)', number=100)
      13.040030002593994
      >>> timeit('sum([j for j in xrange(1000000) if j % 2 == 0])', number=100)
      15.114178895950317
      >>> timeit('sum(j for j in xrange(1000000) if j % 2 == 0)', number=100)
      10.272619009017944</p>
</pre>
</li>
</ol>
]]></description><wfw:commentRss>http://www.stuartmitchell.com/journal/rss-comments-entry-14845612.xml</wfw:commentRss></item><item><title>Quick note about stress testing on Google Appengine</title><dc:creator>Stuart Mitchell</dc:creator><pubDate>Mon, 23 Jan 2012 00:56:51 +0000</pubDate><link>http://www.stuartmitchell.com/journal/2012/1/23/quick-note-about-stress-testing-on-google-appengine.html</link><guid isPermaLink="false">729339:8553842:14690563</guid><description><![CDATA[<p>In a follow up to my last post on GAE I have the following script that hammers a GAE application to make sure it does not fail under load. Note the following:</p>

<ol>
<li>Change the url for the endpoint to your app.</li>
<li>Change the test to be appropriate for what should be returned from your app.</li>
<li>The test endpoint should be unique (see the fake query string) or google will cache the results and your app will only see about two requests a second.</li>
</ol>

<pre>
"""
Stress tests a endpoint for a GAE application
"""
# rate is in requests per second
rate = 5
# test time is in seconds
test_time = 120
# url to hit has to be unique so that the request hits 
# the app not the cache
url = 'http://your-app.appspot.com/endpoint?test=%s'

test_string = "This string should be in the html response"

import time
import multiprocessing
import urllib
import random


def test():
    """
    The test function
    """
    url_open = urllib.urlopen(url%random.random())
    if test_string in url_open.read():
        pass
    else:
        print 'Failed'

if __name__ == '__main__':
    processes = []
    start = time.time()
    while time.time() <= start + test_time:
        p = multiprocessing.Process(target=test)
        p.start()
        processes.append(p)
        time.sleep(1.0 / rate)
    for p in processes:
        p.join()
    print 'Tested url %s times' % (test_time * rate)

</pre>
]]></description><wfw:commentRss>http://www.stuartmitchell.com/journal/rss-comments-entry-14690563.xml</wfw:commentRss></item><item><title>Auckland NZPUG presentation</title><dc:creator>Stuart Mitchell</dc:creator><pubDate>Wed, 18 Jan 2012 21:01:56 +0000</pubDate><link>http://www.stuartmitchell.com/journal/2012/1/19/auckland-nzpug-presentation.html</link><guid isPermaLink="false">729339:8553842:14638016</guid><description><![CDATA[<p>Last night I did a short presentation introducing Google App Engine GAE. This presentation is found <a href="http://www.slideshare.net/stuartmitchell/nzpug-google-appengine">here</a> the files associated with this presentation are <a href="http://dl.dropbox.com/u/5875344/nzpug-appengine.zip">here</a>. This includes a sample GAE application which is setup for testing.</p>
]]></description><wfw:commentRss>http://www.stuartmitchell.com/journal/rss-comments-entry-14638016.xml</wfw:commentRss></item><item><title>You can not pickle an xml.etree Element</title><dc:creator>Stuart Mitchell</dc:creator><pubDate>Sun, 30 Oct 2011 22:59:44 +0000</pubDate><link>http://www.stuartmitchell.com/journal/2011/10/31/you-can-not-pickle-an-xmletree-element.html</link><guid isPermaLink="false">729339:8553842:13531157</guid><description><![CDATA[<p>Yes that is right you will get an error that looks like this</p>

<pre><code>PicklingError: Can't pickle &lt;function copyelement at 0x226d140&gt;: it's not found as
__main__.copyelement
</code></pre>

<p>Great how pickle doesn't tell you that it is an xml.etree.Element that is causing the problem
or what this element is attached to.</p>

<p>I have been using the multiprocessing module that internally uses pickle to transfer inputs and outputs between processes and it will fail with an even more cryptic message if there is an Element object somewhere in the inputs or outputs.</p>

<pre><code>Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 552, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 505, in run
    self.__target(*self.__args, **self.__kwargs)
  File "/usr/lib/python2.7/multiprocessing/pool.py", line 310, in _handle_tasks
    put(task)
TypeError: expected string or Unicode object, NoneType found
</code></pre>

<p>To find this problem I replaced pool.map() with map() and pool.apply_async() with apply.
Then I used pickle.dumps() on the inputs and outputs to find what was giving the problem.</p>

<pre><code>pickle.dumps(thingee)
pickle.dumps(a)
pickle.dumps(b)
result = apply(my_func, (thingee, a, b))
</code></pre>

<p>Then once I had found the offending object I had to subclass pickle.Pickler to get the debugger to jump in at the right spot.</p>

<pre><code>import pickle
class MyPickler (pickle.Pickler):
    def save(self, obj):
        try:
            pickle.Pickler.save(self, obj)
        except Exception, e:
            import pdb;pdb.set_trace()
</code></pre>

<p>Then call it like so</p>

<pre><code>import StringIO
output = StringIO.StringIO()
MyPickler(output).dump(thingee)
</code></pre>

<p>And finally I got my answer</p>
]]></description><wfw:commentRss>http://www.stuartmitchell.com/journal/rss-comments-entry-13531157.xml</wfw:commentRss></item><item><title>Notes on building C extensions with python</title><dc:creator>Stuart Mitchell</dc:creator><pubDate>Tue, 18 Oct 2011 09:34:47 +0000</pubDate><link>http://www.stuartmitchell.com/journal/2011/10/19/notes-on-building-c-extensions-with-python.html</link><guid isPermaLink="false">729339:8553842:13371602</guid><description><![CDATA[<p>Previously, when I have needed to access C libraries with python I have used the [ctypes](http://docs.python.org/library/ctypes.html) library</p><p>However while I have be working on the [dippy module](https://projects.coin-or.org/CoinBazaar/wiki/Projects/Dippy) I have needed to link it into some fairly complicated C code (being the [DIP library](https://projects.coin-or.org/Dip)).</p><p>Dippy is a python extension module that directly uses the python c api. As Qi-Shan Lim and [Michael O'Sullivan](http://www.des.auckland.ac.nz/uoa/michael-osullivan) wrote dippy I will not go into details of its implementation but instead discuss a toy example using [Cython](http://docs.cython.org).</p><p>So taken from the basic [Cython tutorial](http://docs.cython.org/src/userguide/tutorial.html) (altered to use setuptools) we start with a hello world example.</p><p>Preliminaries<br />=============</p><p> 1. Install cython (on ubuntu $sudo apt-get install cython)<br /> 2. Setup a virtual environment to play with</p><p>    $ mkdir cython-example</p><p>    $ cd cython-example</p><p>    $ virtualenv .  #note you can't use --no-site-packages as you need cython</p><p>    $ source bin/activate</p><p>    (cpython-example)$</p><p><br />The Hello World example<br />-----------------------</p><p>Create these files</p><p>helloworld.pyx</p><p>    print "Hello World"</p><p>and setup.py (this is far to complicated but I wanted to use setuptools instead of disutils)</p><p>    #!/usr/bin/env python<br />    <br />    from setuptools import setup<br />    from distutils.extension import Extension</p><p>    # setuptools DWIM monkey-patch madness<br />    # http://mail.python.org/pipermail/distutils-sig/2007-September/thread.html#8204<br />    import sys<br />    if 'setuptools.extension' in sys.modules:<br />        m = sys.modules['setuptools.extension']<br />        m.Extension.__dict__ = m._Extension.__dict__<br />    <br />    setup(<br />        setup_requires=['setuptools_cython'],<br />        ext_modules = [Extension("helloworld", ["helloworld.pyx"],<br />                                 language="c++")]<br />    )</p><p><br />Then do the following</p><p>    (cython-example)$ python setup.py build_ext -i<br />    (cython-example)$ python<br />    >>> import helloworld<br />    Hello World</p><p>You will also see a helloworld.c generated by Cython.</p><p>Adding an External Dependency<br />-----------------------------</p><p>This is the real brain twister I had to figure out. Lets import a constant from a large C++ project.</p><p>helloworld.pyx</p><p>    cdef extern from "Decomp.h":<br />        double DecompBigNum</p><p>    print "Hello World %s" % DecompBigNum</p><p>Now we build it:</p><p>    (cython-example)$ python setup.py build_ext -I DIP-trunk/include/coin -i<br />    (cython-example)$ python<br />    >>> import helloworld<br />    Hello World 1e+21</p><p>Linking shared libraries madness<br />--------------------------------</p><p>If you start using functions you need to include the libraries for the big project</p><p>    (cython-example)$ python setup.py build_ext \<br />                      -I DIP-trunk/include/coin -L DIP-trunk/lib -i</p><p>Now the nasty problem that does occur is when your big dependency is actually built with shared libraries. Then your new .so file will be dependent on a lot of libraries that may not be on the user's system.</p><p>    (cython-example)$ ldd _dippy.so <br />    linux-vdso.so.1 =>  (0x00007fff1e08f000)<br />  libDecomp.so.0 => not found<br />   libAlps.so.0 => not found<br /> libCbcSolver.so.0 => /usr/lib/libCbcSolver.so.0 (0x00007ffccade2000)<br />  libCgl.so.0 => /usr/lib/libCgl.so.0 (0x00007ffccaafd000)<br />  libCbc.so.0 => /usr/lib/libCbc.so.0 (0x00007ffcca804000)<br />  libOsiClp.so.0 => /usr/lib/libOsiClp.so.0 (0x00007ffcca5be000)<br />    libOsi.so.0 => /usr/lib/libOsi.so.0 (0x00007ffcca366000)<br />  libOsiCbc.so.0 => not found<br />   libClp.so.0 => /usr/lib/libClp.so.0 (0x00007ffcc9fd4000)<br />  libCoinUtils.so.0 => /usr/lib/libCoinUtils.so.0 (0x00007ffcc9c8a000)<br />  libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007ffcc9984000)<br />   libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ffcc96fe000)<br /> libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007ffcc94e8000)<br /> libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ffcc92ca000)<br /> libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffcc8f35000)<br /> librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007ffcc8d2d000)<br />   libVol.so.0 => /usr/lib/libVol.so.0 (0x00007ffcc8b26000)<br />  liblapack.so.3gf => /usr/lib/liblapack.so.3gf (0x00007ffcc7f30000)<br />    libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007ffcc7d18000)<br /> libbz2.so.1.0 => /lib/libbz2.so.1.0 (0x00007ffcc7b08000)<br />  /lib64/ld-linux-x86-64.so.2 (0x00007ffccb302000)<br />  libblas.so.3gf => /usr/lib/libblas.so.3gf (0x00007ffcc7292000)<br />    libgfortran.so.3 => /usr/lib/x86_64-linux-gnu/libgfortran.so.3 (0x00007ffcc6fae000)</p><p>In fact, this library will not even work on _your_ system as the dependencies are listed as 'not found'. To get it to work on your system you would use the RPATH directive.</p><p>    (cython-example)$ python setup.py build_ext \<br />                      -I DIP-trunk/include/coin -L DIP-trunk/lib \<br />                      -R DIP-trunk/lib -i</p><p>    (cython-example)$ ldd _dippy.so <br />  linux-vdso.so.1 =>  (0x00007fff399ff000)<br />  libDecomp.so.0 => DIP-trunk/lib/libDecomp.so.0 (0x00007fc1c42a3000)<br />   libAlps.so.0 => DIP-trunk/lib/libAlps.so.0 (0x00007fc1c4071000)<br />   libCbcSolver.so.0 => DIP-trunk/lib/libCbcSolver.so.0 (0x00007fc1c3da3000)<br /> libCgl.so.0 => DIP-trunk/lib/libCgl.so.0 (0x00007fc1c3aac000)<br /> libCbc.so.0 => DIP-trunk/lib/libCbc.so.0 (0x00007fc1c37b9000)<br /> libOsiClp.so.0 => DIP-trunk/lib/libOsiClp.so.0 (0x00007fc1c3574000)<br />   libOsi.so.0 => DIP-trunk/lib/libOsi.so.0 (0x00007fc1c3324000)<br /> libOsiCbc.so.0 => DIP-trunk/lib/libOsiCbc.so.0 (0x00007fc1c3114000)<br />   libClp.so.0 => DIP-trunk/lib/libClp.so.0 (0x00007fc1c2d94000)<br /> libCoinUtils.so.0 => DIP-trunk/lib/libCoinUtils.so.0 (0x00007fc1c2a68000)<br /> libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fc1c2741000)<br />   libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc1c24bc000)<br /> libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fc1c22a6000)<br /> libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc1c2087000)<br /> libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc1c1cf3000)<br /> /lib64/ld-linux-x86-64.so.2 (0x00007fc1c4785000)</p><p>See those nasty hard coded paths, this library would obviously never work on anyone else's system.</p><p>Static Linking<br />--------------</p><p>The way (I've found) to fix this with a project with auto config is to build it with the following.<br /> <br />    $ ./configure --disable-shared --with-pic  #pic needed for 64bit<br />    $ make</p><p>Then all the dependencies are statically linked and hen finally we get it all in one library</p><p>    (cython-example)$ python setup.py build_ext \<br />                      -I DIP-trunk/include/coin -L DIP-trunk/lib -i<br />    (cython-example)$ ldd _dippy.so<br />    linux-vdso.so.1 =>  (0x00007fffd75ff000)<br />  libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f377f7d2000)<br />   libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f377f54d000)<br /> libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f377f336000)<br /> libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f377f118000)<br /> libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f377ed84000)<br /> /lib64/ld-linux-x86-64.so.2 (0x00007f37802d7000)</p>
]]></description><wfw:commentRss>http://www.stuartmitchell.com/journal/rss-comments-entry-13371602.xml</wfw:commentRss></item><item><title>Finding python memory leaks with objgraph</title><category>memory</category><category>programming</category><category>pulp</category><category>python</category><dc:creator>Stuart Mitchell</dc:creator><pubDate>Fri, 05 Aug 2011 01:18:50 +0000</pubDate><link>http://www.stuartmitchell.com/journal/2011/8/5/finding-python-memory-leaks-with-objgraph.html</link><guid isPermaLink="false">729339:8553842:12397350</guid><description><![CDATA[<p>An example using the python objgraph library to debug a circular reference.</p>
]]></description><wfw:commentRss>http://www.stuartmitchell.com/journal/rss-comments-entry-12397350.xml</wfw:commentRss></item><item><title>skeleton a template for python projects</title><dc:creator>Stuart Mitchell</dc:creator><pubDate>Wed, 20 Apr 2011 09:36:13 +0000</pubDate><link>http://www.stuartmitchell.com/journal/2011/4/20/skeleton-a-template-for-python-projects.html</link><guid isPermaLink="false">729339:8553842:11210685</guid><description><![CDATA[<p>I presented a talk on <a href="http://sphinx.pocoo.org/">sphinx</a> &nbsp;at the Auckland python users group. Instead of trying to present all the various interactions between sphinx and setup.py. I used <a href="http://pypi.python.org/pypi/skeleton/">skeleton</a>, a tool that can be used to create python projects.</p>
<p>Skeleton uses templates to create a ready made project, similar to pastescript.</p>
<p>Imade a fork of this project on <a href="https://github.com/stumitchell/skeleton">github</a> and added a template where sphinx is integrated into the project. This fork is currently availible as <a href="http://pypi.python.org/pypi/skeleton_stu/">skeleton_stu</a> on pypi until the changes are merged to the original project.&nbsp;</p>
<p>To create a basic sphinx package</p>
<p>$pip install skeleton_stu</p>
<p>$skeleton_package_sphinx [your_directory]</p>
<p>answer a few questions and then you are done :-)</p>]]></description><wfw:commentRss>http://www.stuartmitchell.com/journal/rss-comments-entry-11210685.xml</wfw:commentRss></item><item><title>Squarespace website</title><dc:creator>Stuart Mitchell</dc:creator><pubDate>Sat, 16 Apr 2011 10:27:43 +0000</pubDate><link>http://www.stuartmitchell.com/journal/2011/4/16/squarespace-website.html</link><guid isPermaLink="false">729339:8553842:11173407</guid><description><![CDATA[<p>Well I'm converting my website to use squarespace.</p>
<p>Seems okay but I would like wysiwyg table construction.</p>]]></description><wfw:commentRss>http://www.stuartmitchell.com/journal/rss-comments-entry-11173407.xml</wfw:commentRss></item><item><title>random.seed() and python module imports</title><category>programming</category><category>python</category><category>random</category><dc:creator>Stuart Mitchell</dc:creator><pubDate>Thu, 13 Jan 2011 09:25:00 +0000</pubDate><link>http://www.stuartmitchell.com/journal/2011/1/13/randomseed-and-python-module-imports.html</link><guid isPermaLink="false">729339:8553842:11173398</guid><description><![CDATA[<p>Interesting factoid on the random library.&nbsp;</p>
<p>I use random.seed() in my tests to get reproducible numbers (to test&nbsp;graphing and stats functions) and I have found the following unexpected behavior.&nbsp;<br />&gt;&gt;&gt; import random&nbsp;<br /><br />imports the random library as a singleton therefore, if you write:&nbsp;<br />&gt;&gt;&gt; random.seed(0)&nbsp;<br /><br />it will actually set a seed for all code (including library code) that uses&nbsp;the random library.&nbsp;Worse than that if your test code calls a library that uses random it will&nbsp;get a number from&nbsp;that sequence and now the random numbers in your tests are not in the same&nbsp;sequence&nbsp;as they may have been without the library call (this is the problem that&nbsp;caused me to think about this)&nbsp;</p>
<p>Therefore my blanket recommendation for all code that uses random.seed() is&nbsp;that&nbsp;the import line be changed to the following:&nbsp;<br />&gt;&gt;&gt; from random import Random&nbsp;<br />&gt;&gt;&gt; random = Random()&nbsp;<br /><br />this will give you a new instance of random that will only be used within&nbsp;your module scope,&nbsp;and all previous calls to random.seed() etc will continue to work.</p>]]></description><wfw:commentRss>http://www.stuartmitchell.com/journal/rss-comments-entry-11173398.xml</wfw:commentRss></item><item><title>How to root and update your htc hero.</title><category>android</category><category>htc hero</category><dc:creator>Stuart Mitchell</dc:creator><pubDate>Thu, 23 Dec 2010 09:23:00 +0000</pubDate><link>http://www.stuartmitchell.com/journal/2010/12/23/how-to-root-and-update-your-htc-hero.html</link><guid isPermaLink="false">729339:8553842:11173395</guid><description><![CDATA[<p><br />I just did this because I was having problems mounting and tethering my hero<br /><br />1. download and install universal android root&nbsp;<br /><a class="ot-anchor" href="http://www.tgdaily.com/mobility-features/51631-universal-root-arrives-on-android">http://www.tgdaily.com/mobility-features/51631-universal-root-arrives-on-android</a>&nbsp;remember to allow non-market applications, and use a file manager to install the apk<br /><br />2. Download and install Titanium Backup (from the market)&nbsp;<a class="ot-anchor" href="http://matrixrewriter.com/android/">http://matrixrewriter.com/android/</a>&nbsp;(use this to backup your apps and data). This will also test is<br /><br />3. Download and install ROM manager (from the market)&nbsp;<a class="ot-anchor" href="http://www.androidzoom.com/android_applications/tools/rom-manager_fjxs.html">http://www.androidzoom.com/android_applications/tools/rom-manager_fjxs.html</a><br />This will install a recovery image (that will allow you to use custom roms)<br /><br />4. Download a rom from&nbsp;<a class="ot-anchor" href="http://android-roms.net/hero/">http://android-roms.net/hero/</a>&nbsp;I used the elelinux one put this on the root of your sd card and rename update.zip.<br /><br />5. Use ROM manager to boot to recovery image<br /><br />6. Make a Nandroid backup of your current system (make sure there is room on your sdcard<br /><br />6. Choose a factory reset and wipe dalvik cache in the recovery menu<br /><br />7. Install the new rom from update.zip (this is a menu option in the recovery rom)<br /><br />7.5 if anything goes wrong with the update (I forgot to do the wipe) remove the battery (if your screen is frozen) and recover your original settings with nandroid from the recovery menu (though for some reason I had to use Rom manager to reflash my recovery image.</p>]]></description><wfw:commentRss>http://www.stuartmitchell.com/journal/rss-comments-entry-11173395.xml</wfw:commentRss></item></channel></rss>