<?xml version="1.0" encoding="UTF-8"?>
<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:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ptone</title>
	<atom:link href="http://ptone.com/dablog/feed/" rel="self" type="application/rss+xml" />
	<link>http://ptone.com/dablog</link>
	<description>Hodgepodge of thoughts, technical notes, and random observations</description>
	<lastBuildDate>Wed, 13 Jan 2010 22:18:33 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Python,Multiprocessing,Hyperthreading, and image resizing</title>
		<link>http://ptone.com/dablog/2010/01/pythonmultiprocessinghyperthreading-and-image-resizing/</link>
		<comments>http://ptone.com/dablog/2010/01/pythonmultiprocessinghyperthreading-and-image-resizing/#comments</comments>
		<pubDate>Wed, 13 Jan 2010 22:18:33 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Random Observation]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2010/01/pythonmultiprocessinghyperthreading-and-image-resizing/</guid>
		<description><![CDATA[I have the occasional need to resize a set of images.  I used to use Photoshop batch actions, then I used some droplets, and recently I&#8217;ve been using a simple python script with PIL (Python Image Library)

We recently got an 8 core Mac Pro, and I wanted to see if I could take more [...]]]></description>
			<content:encoded><![CDATA[<p>I have the occasional need to resize a set of images.  I used to use Photoshop batch actions, then I used some droplets, and recently I&#8217;ve been using a simple python script with PIL (Python Image Library)</p>

<p>We recently got an 8 core Mac Pro, and I wanted to see if I could take more advantage of all those cores when resizing images.</p>

<p><span id="more-134"></span>
One of the things that confused me when I first opened activity monitor, is that it had 16 processors listed.  A little digging turns up that this relates to Intel&#8217;s Hyperthreading technology, where they present the OS twice the cores and hand some extra concurrency on the chip.  There is some debate out there as to whether or not it makes a difference.</p>

<p>It&#8217;s frustrating to have all that power and watch a CPU utilization tool look like this:</p>

<p><img src="http://ptone.com/dablog/wp-content/uploads/2010/01/single.png" alt="Single" /></p>

<p>But that is what you get when a tool is not written to be parallel across processing units.  Much is made over Python&#8217;s limit to threading and the GIL, however it seems that multiple threads never take as much advantage of multicore horsepower as do multiple processes.</p>

<p>Thanks to Python&#8217;s <a href="http://docs.python.org/library/multiprocessing.html">multiprocessing library</a> it was very easy to create a worker <a href="http://docs.python.org/library/multiprocessing.html#module-multiprocessing.pool">pool</a> to handle the resizing.  The results are impressive.  The test task was to resize a folder of 350 jpeg files by 50% and save them to a folder.</p>

<p><img src="http://ptone.com/dablog/wp-content/uploads/2010/01/performance.png" alt="Performance" /></p>

<p>This shows you the performance gain by doing the image resizing in parallel.  It goes from a 6 minute task to a 30 second task.</p>

<p>What is interesting is that even though there are only 8 true cores, there is a 40% increase in speed using all 16 virtual cores, but almost no advantage in going any higher than that.  I&#8217;d say hyperthreading makes a difference in this case.</p>

<p>Now this is more like it:</p>

<p><img src="http://ptone.com/dablog/wp-content/uploads/2010/01/maxed.png" alt="Maxed" /></p>

<p>A couple assorted notes:</p>

<p>With 8 workers, there is a roughly 10% increase in performance seen when turning off hyperthreading (via processor prefpane from dev-tools).  It may be that the overhead of managing threads that aren&#8217;t doing much for you detracts from the overall performance?? Not sure.</p>

<p>Photoshop batch automate on the same task takes about 6 minutes, which seems to refute Adobe&#8217;s <a href="http://blogs.adobe.com/jnack/2006/12/photoshop_and_multicore.html">implication</a> that muliprocessing doesn&#8217;t often gain you much.</p>

<p>There is one gotcha however, and that is that there does seem to be some sort of memory leak with the multiprocessing module.  With just one worker in the pool, you can see a steadily increasing memory use that isn&#8217;t present in the same PIL code that isn&#8217;t run through the multiprocessing module.  This is probably a manifestation of <a href="http://bugs.python.org/issue6653">this bug</a></p>

<p>Finally, the script that I used to do the tests is available <a href="http://gist.github.com/276618">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2010/01/pythonmultiprocessinghyperthreading-and-image-resizing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pretty view of hg diff</title>
		<link>http://ptone.com/dablog/2009/11/pretty-view-of-hg-diff/</link>
		<comments>http://ptone.com/dablog/2009/11/pretty-view-of-hg-diff/#comments</comments>
		<pubDate>Fri, 20 Nov 2009 22:21:55 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Random Observation]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2009/11/pretty-view-of-hg-diff/</guid>
		<description><![CDATA[Been using hg, and like to use hg diff to help me make better commit notes &#8211; but been spoiled by bitbuckets HTML view of diffs

So here is a quick script that I keep on my path for viewing hg diff, formated with pygments &#8211; I&#8217;m sure it would be very easy to adopt this [...]]]></description>
			<content:encoded><![CDATA[<p>Been using hg, and like to use hg diff to help me make better commit notes &#8211; but been spoiled by bitbuckets HTML view of diffs</p>

<p>So here is a quick script that I keep on my path for viewing hg diff, formated with pygments &#8211; I&#8217;m sure it would be very easy to adopt this to git.</p>

<p><a href="http://gist.github.com/239803">here is the gist</a></p>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2009/11/pretty-view-of-hg-diff/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Setting up pinax on Dreamhost Private Server</title>
		<link>http://ptone.com/dablog/2009/10/setting-up-pinax-on-dreamhost-private-server/</link>
		<comments>http://ptone.com/dablog/2009/10/setting-up-pinax-on-dreamhost-private-server/#comments</comments>
		<pubDate>Thu, 29 Oct 2009 22:29:07 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[django pinax]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2009/10/setting-up-pinax-on-dreamhost-private-server/</guid>
		<description><![CDATA[using apache, mysql, mod_wsgi, and virtualenv

Dreamhost provides free hosting to nonprofits, and for now they seem to have thrown in a virtual private server.  This is hard not to take advantage of, and I&#8217;m hoping that the VPS is better performing than the shared hosting &#8211; but my concern is that they all share [...]]]></description>
			<content:encoded><![CDATA[<p>using apache, mysql, mod_wsgi, and virtualenv</p>

<p>Dreamhost provides free hosting to nonprofits, and for now they seem to have thrown in a virtual private server.  This is hard not to take advantage of, and I&#8217;m hoping that the VPS is better performing than the shared hosting &#8211; but my concern is that they all share the same mysql servers.  So here is how I got pinax up and running in its comfy and modern Python web stack.</p>

<p><span id="more-127"></span>
At first I tried to go the route of custom install of python2.6 &#8211; but got bogged down trying to get either passenger<em>wsgi or mod</em>wsgi to work properly &#8211; they both seemed to have fatal dead ends in the end.</p>

<p>The first thing you need to do is associate a domain with your PS and set it up as a directory of a user.</p>

<p>so that you have a user and directory like /home/django_user/example.com/</p>

<p>In the Dreamhost panel private server section &#8220;Web Server Configuration&#8221; uncheck &#8220;DreamHost Managed:&#8221;.  This will prevent any accidental changes you make in the panel from undoing the customizations you need to make to the apache config.</p>

<p>Next you need to create an admin user in the Dreamhost control panel for your PS, lets say django<em>admin, this probably should be a different user than is set up for the domain.  This user will just be configuring system level software, namely set the python version to use, install the mysql bindings, PIL, and mod</em>wsgi packages.</p>

<p>login as the admin user and then:</p>

<pre><code>mkdir src

# This is to set python 2.5 as the default - if you don't care you can skip this step - but I'm assuming this is done
cd /usr/bin/
sudo rm python
sudo ln -s python2.5 python


cd ~/src
# note that this is specific for 2.5 - use the right egg for your python version
wget http://pypi.python.org/packages/2.5/s/setuptools/setuptools-0.6c11-py2.5.egg#md5=64c94f3bf7a72a13ec83e0b24f2749b2
sudo sh setuptools-0.6c11-py2.5.egg
</code></pre>

<p>You next need to download the MySQL-python tarball from http://sourceforge.net/projects/mysql-python/ as there is no easy way to fetch it from the command line.  FTP it to your src/ directory of the admin user then:</p>

<pre><code>tar xvzf MySQL-python-1.2.3c1.tar.gz
cd MySQL-python-1.2.3c1
sudo python setup.py install

cd ..
wget http://effbot.org/media/downloads/Imaging-1.1.6.tar.gz
tar xvzf Imaging-1.1.6.tar.gz
cd Imaging-1.1.6
python setup.py build --force
sudo python setup.py install
python selftest.py
</code></pre>

<p>You should see: 57 tests passed. Next:</p>

<pre><code>sudo easy_install pip
sudo pip install virtualenv
# virtualenvwrapper is primarily useful if you are going to do 
# dev work or host many projects - I don't assume you fetch this
sudo pip install virtualenvwrapper

cd ~/src
wget http://modwsgi.googlecode.com/files/mod_wsgi-3.0c5.tar.gz
tar xvzf mod_wsgi-3.0c5.tar.gz 

./configure --with-apxs=/usr/local/dh/apache2/template/sbin/apxs --with-python=/usr/bin/python
make
sudo make install

# note that your private server ID replaces the 99999, 
# sub your favorite editor of choice (vi,emacs etc)

sudo pico /usr/local/dh/apache2/apache2-ps99999/etc/httpd.conf
</code></pre>

<p>find the section on modules and add: </p>

<pre><code>LoadModule wsgi_module /dh/apache2/template/lib/modules/mod_wsgi.so
</code></pre>

<p>Now your base python environment is configured, don&#8217;t log out of this user &#8211; as we will need to make more changes to the httpd.conf file later.  Instead open up another terminal session and login as your django_user</p>

<p>The first thing we need to do is create some folders we will use later</p>

<pre><code>mkdir src envs projects wsgi-scripts
</code></pre>

<p>Then we will grab pinax, install it, and activate the virtualenv</p>

<pre><code>cd ~/src
wget http://downloads.pinaxproject.com/Pinax-0.7.1-bundle.tar.gz
tar xvzf Pinax-0.7.1-bundle.tar.gz
python Pinax-0.7.1-bundle/scripts/pinax-boot.py ~/envs/pinax_test/
cd ~
source envs/pinax_test/bin/activate

#optional - update django to current release version
pip install -U django
</code></pre>

<p>Now we will create a basic pinax project</p>

<pre><code>pinax-admin clone_project basic_project projects/basictest
cd projects/basictest/
</code></pre>

<p>Before you continue, go back to the Dreamhost panel and create a mysql database for your project &#8211; note the name and password, and the host name.</p>

<p>Edit the settings.py in your basictest project to use these database settings</p>

<p>Now lets see if we can get pinax up and running:</p>

<pre><code>chmod +x manage.py 
./manage.py syncdb
./manage.py runserver 0.0.0.0:8000
</code></pre>

<p>You should now be able to go to http://example.com:8000 and see the pinax welcome screen, ctrl-C to stop the dev server.</p>

<p>To get pinax working with mod_wsgi you need two parts, a wsgi script, and changes to the apache configuration</p>

<p>create a file called pinax_basictest.wsgi in your wsgi-scripts folder.  Its contents should look like (cobbled from wsgi docs and pinax deployment sample wsgi file):</p>

<pre><code>import os
import sys
import site
sys.stdout = sys.stderr

# not needed in all environments - but is in others
os.environ['PYTHON_EGG_CACHE'] = '/tmp'

# this forces the virtualenv site-packages to be higher priority than system site-packages
site.addsitedir('/home/django_user/envs/pinax_test/lib/python2.5/site-packages')

sys.path.insert(0,'/home/django_user/projects/')

from django.conf import settings
os.environ['DJANGO_SETTINGS_MODULE'] = 'basictest.settings'

sys.path.insert(0, os.path.join(settings.PINAX_ROOT, "apps"))
sys.path.insert(0, os.path.join(settings.PROJECT_ROOT, "apps"))


import django.core.handlers.wsgi

application = django.core.handlers.wsgi.WSGIHandler()


# uncomment below to do a sanity check on the wsgi setup

# def test_wsgi(environ, start_response):
#     status = '200 OK'
#     output = 'Hello World! wsgi py \n' + sys.version + '\n' + '\n'.join(sys.path)
# 
#     response_headers = [('Content-type', 'text/plain'),
#                         ('Content-Length', str(len(output)))]
#     start_response(status, response_headers)
# 
#     return [output]
# 
# application = test_wsgi
</code></pre>

<p>Next you need to switch back to your admin user terminal (you didn&#8217;t close it right?) and edit your httpd.conf file again</p>

<pre><code>sudo pico /usr/local/dh/apache2/apache2-ps99999/etc/httpd.conf
</code></pre>

<p>go to the very end of the file, and before the last closing /virtualhost tag (so inside the virtualhost) add the following</p>

<pre><code># wsgi
&lt;Directory /home/django_user/wsgi-scripts&gt;
Order allow,deny
Allow from all
&lt;/Directory&gt;


# absolute path
WSGIScriptAlias / /home/django_user/wsgi-scripts/pinax_basictest.wsgi 

&lt;Directory "/home/django_user/projects/basictest/media"&gt;
    Allow from all
    Order allow,deny
&lt;/Directory&gt;


&lt;Directory "/home/django_user/envs/pinax_test/lib/python2.5/site-packages/django/contrib/admin/media"&gt;
    Allow from all
    Order allow,deny
&lt;/Directory&gt;

Alias "/media/" "/home/django_user/projects/basictest/media/"

# note some use hyphen - others _
Alias "/admin_media/" "/home/django_user/envs/pinax_test/lib/python2.5/site-packages/django/contrib/admin/media/"
</code></pre>

<p>Finally, still while in the admin user terminal  &#8211; restart apache (remember to change for your private server id):</p>

<pre><code>sudo /etc/init.d/httpd2 restart apache2-ps999999
</code></pre>

<p>Now you should be able to go to http://example.com and see the pinax welcome screen</p>

<p>If you get a 500 error:</p>

<ul>
<li>look in your apache error log which will be at /home/django_user/logs/example.com/http/error.log</li>
<li>uncomment the sanity check in the wsgi script to see if you can get basic hello world working, along with some info about what python environment is being used by wsgi</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2009/10/setting-up-pinax-on-dreamhost-private-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Restricting login to account based on IP address</title>
		<link>http://ptone.com/dablog/2009/10/restricting-login-to-account-based-on-ip-address/</link>
		<comments>http://ptone.com/dablog/2009/10/restricting-login-to-account-based-on-ip-address/#comments</comments>
		<pubDate>Wed, 28 Oct 2009 16:31:38 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[osx]]></category>
		<category><![CDATA[sys-admin]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2009/10/restricting-login-to-account-based-on-ip-address/</guid>
		<description><![CDATA[At work we needed to have a standard local account that would work off campus, but not on campus. Here was my solution.


First I check for the user and create it if it doesn&#8217;t exist

#!bash
user_exists=`dscl . -read /Users/remote GeneratedUID &#124; grep -c GeneratedUID`
if [ $user_exists -ne 1 ]; then
    echo "creating remote [...]]]></description>
			<content:encoded><![CDATA[<p>At work we needed to have a standard local account that would work off campus, but not on campus. Here was my solution.</p>

<p><span id="more-97"></span>
First I check for the user and create it if it doesn&#8217;t exist</p>

<pre><code>#!bash
user_exists=`dscl . -read /Users/remote GeneratedUID | grep -c GeneratedUID`
if [ $user_exists -ne 1 ]; then
    echo "creating remote user"
    sudo dscl . -create /Users/remote
    dscl . -create /Users/remote UserShell /bin/bash
    sudo dscl . -create /Users/remote RealName "remote"
    dscl . -create /Users/remote UniqueID 509
    dscl . -create /Users/remote PrimaryGroupID 1000
    dscl . -create /Users/remote NFSHomeDirectory /Local/Users/remote
    dscl . -passwd /Users/remote remote
fi
</code></pre>

<p>because these are fully managed machines, I know what UIDs are available.  (For a method that checks for available UID I&#8217;ve posted a script from Andrew Mortensen below)</p>

<p>The next part of the script will check if the user is logged in as &#8220;remote&#8221; and on campus using a regular expression (our two subnets are 10.5.5.X and 10.6.6.X).  You could also check a router, DHCP server, or internal DNS as other approaches.  If they are on campus I use a display utility called BigHonkingText to throw up a message and then kill the loginwindow.</p>

<pre><code>#!bash
user="$1"

if [ "$user" == "remote" ]; then
    IP=`ifconfig | grep "inet " | grep -v 127.0.0.1 | awk 'NR&gt;1{exit};{ print $2 }'`
    echo $IP
    if [[ "$IP" =~ 10.[5,6].[5,6].[0-9]* ]]; then
        echo "on campus"
    /usr/local/bin/BigHonkingText "account not allowed on campus"
    killall loginwindow
        # reboot
    fi
fi
</code></pre>

<p>Here is the script from Andrew Mortensen:</p>

<pre><code>#!bash
#! /bin/sh

# create a template user

export PATH=/bin:/usr/bin:/sbin:/usr/sbin

# arbitrary uid
N_UID=501

# arbitrary gid
N_GID=501

# user name
N_USERNAME="$1"

# home
N_HOME="/var/${N_USERNAME}"

# system default user home template
SYSHOMETEMPLATE="/System/Library/User Template/English.lproj"

# make sure the uid and gid are available
while [ true ]; do
    user="`dscl . -search /users UniqueID ${N_UID} 2&gt;/dev/null`"

    if [ -z "${user}" ]; then
    break
    fi

    N_UID=$((${N_UID} + 1));
done

while [ true ]; do
    group=`dscl . -search /groups PrimaryGroupID ${N_GID} 2&gt;/dev/null`

    if [ -z "${group}" ]; then
    break
    fi

    N_GID=$((${N_GID} + 1));
done

# create user
dscl . &lt;&lt;EOF
create "/users/${N_USERNAME}"
create "/users/${N_USERNAME}" AppleMetaNodeLocation /Local/Default
create "/users/${N_USERNAME}" GeneratedUID `uuidgen`
create "/users/${N_USERNAME}" UniqueID ${N_UID}
create "/users/${N_USERNAME}" PrimaryGroupID ${N_GID}
create "/users/${N_USERNAME}" Password "*"
create "/users/${N_USERNAME}" RecordName ${N_USERNAME}
create "/users/${N_USERNAME}" RecordType dsRecTypeNative:users
create "/users/${N_USERNAME}" NFSHomeDirectory ${N_HOME}
create "/users/${N_USERNAME}" RealName "Template User"
create "/users/${N_USERNAME}" UserShell /bin/bash
EOF
if [ $? -ne 0 ]; then
    logger -is Creation of ${N_USERNAME} failed.

    # destroy account
    dscl . -delete "/users/${N_USERNAME}" 2&gt;/dev/null
    exit 2
fi

# create group
dscl . &lt;&lt;EOF
create "/groups/${N_USERNAME}"
create "/groups/${N_USERNAME}" AppleMetaNodeLocation /Local/Default
create "/groups/${N_USERNAME}" GeneratedUID `uuidgen`
create "/groups/${N_USERNAME}" PrimaryGroupID ${N_GID}
create "/groups/${N_USERNAME}" RecordName ${N_USERNAME}
create "/groups/${N_USERNAME}" RecordType dsRecTypeNative:groups
create "/groups/${N_USERNAME}" Password "*"
create "/groups/${N_USERNAME}" GroupMembership ${N_USERNAME}
EOF
if [ $? -ne 0 ]; then
    logger -is Creation of ${N_USERNAME} failed.

    # destroy account
    dscl . -delete "/users/${N_USERNAME}" 2&gt;/dev/null
    dscl . -delete "/groups/${N_USERNAME}" 2&gt;/dev/null
    exit 2
fi

# make home directory
mkdir -m 0700 -p ${N_HOME}
ditto --rsrc "${SYSHOMETEMPLATE}" "${N_HOME}"

if [ $? -ne 0 ]; then
    logger -is Creation of ${N_USERNAME} failed.

    # destroy account
    dscl . -delete "/users/${N_USERNAME}" 2&gt;/dev/null
    dscl . -delete "/groups/${N_USERNAME}" 2&gt;/dev/null
    exit 2
fi

chown -R ${N_USERNAME}:${N_USERNAME} ${N_HOME}

logger -i Creation of template user ${N_USERNAME} succeeded.

exit 0
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2009/10/restricting-login-to-account-based-on-ip-address/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Installing MySQL Python bindings on OS X Leopard server</title>
		<link>http://ptone.com/dablog/2009/10/installing-mysql-python-bindings-on-os-x-leopard-server/</link>
		<comments>http://ptone.com/dablog/2009/10/installing-mysql-python-bindings-on-os-x-leopard-server/#comments</comments>
		<pubDate>Thu, 22 Oct 2009 16:56:11 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Random Observation]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2009/10/installing-mysql-python-bindings-on-os-x-leopard-server/</guid>
		<description><![CDATA[Installing the mysql-python package on Leopard is relatively easy if you&#8217;ve installed MySQL from the mysql.org distribution &#8211; but installing on Leopard Server is a bit more problematic.


The crux of the issue is that the version of MySQL that comes with Leopard Server does not include the header and library files needed for linking external [...]]]></description>
			<content:encoded><![CDATA[<p>Installing the mysql-python package on Leopard is relatively easy if you&#8217;ve installed MySQL from the mysql.org distribution &#8211; but installing on Leopard Server is a bit more problematic.</p>

<p><span id="more-96"></span>
The crux of the issue is that the version of MySQL that comes with Leopard Server does not include the header and library files needed for linking external libraries with.  This applies to 10.5, but a similar process should work with 10.6.</p>

<p>If you attempt to build the MySQLdb python module you&#8217;ll get errors like:</p>

<pre><code>building '_mysql' extension
gcc -fno-strict-aliasing -Wno-long-double -no-cpp-precomp -mno-fused-madd -fno-common -dynamic -DNDEBUG -g -Os -Wall -Wstrict-prototypes -DMACOSX -I/usr/include/ffi -DENABLE_DTRACE -arch i386 -arch ppc -pipe -Dversion_info=(1,2,3,'gamma',1) -D__version__=1.2.3c1 -I/usr/include -I/System/Library/Frameworks/Python.framework/Versions/2.5/include/python2.5 -c _mysql.c -o build/temp.macosx-10.5-i386-2.5/_mysql.o -fno-omit-frame-pointer -pipe -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DIGNORE_SIGHUP_SIGQUIT
_mysql.c:36:23: error: my_config.h: No such file or directory
_mysql.c:36:23: error: my_config.h: No such file or directory
_mysql.c:38:19: error: mysql.h: No such file or directory
_mysql.c:38:19: error: mysql.h: No such file or directory
</code></pre>

<p>Apple has a <a href="technote">http://support.apple.com/kb/TA25017</a> on the issue &#8211; and the solution is to download these separately.  You can also just install a different version of mysql &#8211; but for a variety of reasons, I wanted to continue to run the installed version.</p>

<p>So here are the commands that will build you a working mysql python binding:</p>

<p>(assumes you have dev tools installed)</p>

<p>grab the binding library source:</p>

<p>http://sourceforge.net/projects/mysql-python/files/</p>

<pre><code>mv path/to/MySQL-python-1.2.3c1.tar.gz /tmp
cd /tmp
tar xvzf MySQL-python-1.2.3c1.tar.gz
curl -O http://www.opensource.apple.com/other/MySQL-43.binaries.tar.gz
tar xzvf MySQL-43.binaries.tar.gz
tar xvzf MySQL-43.binaries/MySQL-43.root.tar.gz
cd usr
sudo ditto usr/include/ /usr/include/
sudo ditto usr/lib/ /usr/lib/
cd /tmp/MySQL-python-1.2.3c1
ARCHFLAGS='-arch i386 -arch x86_64'
export ARCHFLAGS
# edit site.cfg to point to point to /usr/bin/mysql_config
python setup.py build
sudo python setup.py install
</code></pre>

<p>To verify this worked &#8211; fire up a python console and &#8216;import MySQLdb&#8217;</p>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2009/10/installing-mysql-python-bindings-on-os-x-leopard-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Local editing of remote files</title>
		<link>http://ptone.com/dablog/2009/10/local-editing-of-remote-files/</link>
		<comments>http://ptone.com/dablog/2009/10/local-editing-of-remote-files/#comments</comments>
		<pubDate>Thu, 15 Oct 2009 23:05:35 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Random Observation]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2009/10/local-editing-of-remote-files/</guid>
		<description><![CDATA[So found this buried under some dust.  I had forgotten that I had ever set this up, but in adding some stuff to a .bash_profile on an older server found some code that I&#8217;ve spruced up bit for this post that lets you locally edit a remote file initiated via command in a remote [...]]]></description>
			<content:encoded><![CDATA[<p>So found this buried under some dust.  I had forgotten that I had ever set this up, but in adding some stuff to a .bash_profile on an older server found some code that I&#8217;ve spruced up bit for this post that lets you locally edit a remote file initiated via command in a remote SSH session.</p>

<p><span id="more-94"></span>
I&#8217;ve been mostly using transmit/SFTP to do editing of remote files with my local editor of choice (TextMate).  Before I switched to TextMate I was using TextWrangler.  The problem with using Transmit (or any FTP client) for editing is that if you are already where you need to be in a SSH session &#8211; you have to navigate to that same location in the FTP client before opening the file for local editing.</p>

<p>One feature TextWrangler has that TextMate does not is the ability to open files from a SFTP URL and save them back remotely when you do CMD-S.</p>

<p>So putting the following in the .bash_profile on the server will let you execute &#8220;redit somefile&#8221; which will cause a reverse ssh command to be sent you telling TextWrangler to open the file.</p>

<p>Some prereqs:</p>

<ul>
<li>You have to have key based SSH auth working in BOTH directions</li>
<li>You have to have the TextWrangler CLI tool (edit) installed</li>
<li>Since there is a good chance that the local user you are logged in as is different than the one you are shelling into as, you have to hard code that &#8211; so unless your name is preston &#8211; you will have to change that.</li>
</ul>

<p>`</p>

<pre><code>SSH_CLIENT_ADDRESS=`echo $SSH_CONNECTION | cut -f1 -d" "`
export SSH_CLIENT_ADDRESS

SSH_HOST_ADDRESS=`echo $SSH_CONNECTION | cut -f3 -d" "`
export SSH_HOST_ADDRESS

ME=`whoami`

function redit() {
    ssh preston@$SSH_CLIENT_ADDRESS edit \"sftp://$ME@$SSH_HOST_ADDRESS/$PWD/"$@"\"
}
</code></pre>

<p>`</p>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2009/10/local-editing-of-remote-files/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Marking all read in Mail.app</title>
		<link>http://ptone.com/dablog/2009/09/marking-all-read-in-mail-app/</link>
		<comments>http://ptone.com/dablog/2009/09/marking-all-read-in-mail-app/#comments</comments>
		<pubDate>Mon, 14 Sep 2009 17:38:14 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Random Observation]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2009/09/marking-all-read-in-mail-app/</guid>
		<description><![CDATA[I&#8217;ve always been annoyed that the only way to mark all as read for a mailbox was with a contextual menu in the sidebar &#8211; lets change that.


I use Butler as my quicklaunch keyboard macro tool &#8211; but you could use your favorite one to run the following script while reading mail.

#!applescript
tell application "Mail"
  [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve always been annoyed that the only way to mark all as read for a mailbox was with a contextual menu in the sidebar &#8211; lets change that.</p>

<p><span id="more-93"></span>
I use Butler as my quicklaunch keyboard macro tool &#8211; but you could use your favorite one to run the following script while reading mail.</p>

<pre><code>#!applescript
tell application "Mail"
    activate
    get message viewer 1's selected mailboxes
    repeat with thisBox in result
        set read status of (messages of thisBox whose read status is false) to true
    end repeat

end tell
</code></pre>

<p>I find this almost critical for getting through mailing list traffic.</p>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2009/09/marking-all-read-in-mail-app/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Launching OE-Cake</title>
		<link>http://ptone.com/dablog/2009/09/launching-oe-cake/</link>
		<comments>http://ptone.com/dablog/2009/09/launching-oe-cake/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 17:24:25 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[osx]]></category>
		<category><![CDATA[sysadmin]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2009/09/launching-oe-cake/</guid>
		<description><![CDATA[OE-Cake is still expired for OS X &#8211; lets work around that



So OE-Cake now has a beta for windows &#8211; but not OS X.

We still have the binary from their old version that expired some time ago &#8211; we were launching it with ARD with the below trick, but now I&#8217;ve moved it into a [...]]]></description>
			<content:encoded><![CDATA[<p>OE-Cake is still expired for OS X &#8211; lets work around that</p>

<p><span id="more-86"></span></p>

<p>So OE-Cake now has a beta for windows &#8211; but not OS X.</p>

<p>We still have the binary from their old version that expired some time ago &#8211; we were launching it with ARD with the below trick, but now I&#8217;ve moved it into a read-only applescript application that the students can launch themselves:</p>

<pre><code>try
    do shell script "sudo date 1103100008" user name "admin" password "*****" with administrator privileges
end try

do shell script "open /Applications/OE-CAKE\\!.app"
delay 10
do shell script "launchctl stop org.ntp.ntpd" user name "admin" password "*****" with administrator privileges
do shell script "launchctl start org.ntp.ntpd" user name "admin" password "*****" with administrator privileges
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2009/09/launching-oe-cake/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Making iPhone iTunes remote more useful</title>
		<link>http://ptone.com/dablog/2009/09/making-iphone-itunes-remote-more-useful/</link>
		<comments>http://ptone.com/dablog/2009/09/making-iphone-itunes-remote-more-useful/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 00:10:17 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[itunes]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2009/09/making-iphone-itunes-remote-more-useful/</guid>
		<description><![CDATA[The iTunes remote is pretty slick &#8211; if only it could turn on the stereo



I have a mac mini set up as a HTPC.  The music end of this was a bit neglected as it was originally set up to use a custom onscreen menu control to switch between several different iTunes libraries and [...]]]></description>
			<content:encoded><![CDATA[<p>The iTunes remote is pretty slick &#8211; if only it could turn on the stereo</p>

<p><span id="more-85"></span></p>

<p>I have a mac mini set up as a HTPC.  The music end of this was a bit neglected as it was originally set up to use a custom onscreen menu control to switch between several different iTunes libraries and then have basic control within them.</p>

<p>Now that we have iPhones in the house &#8211; I consolidated the decade + worth of iTunes libraries into one.</p>

<p>I wanted a way to control the speakers based on iTunes state.</p>

<p>So this little python script runs every 10 seconds, here is a quick outline of what it does.</p>

<p>If iTunes is playing, but the speakers are off &#8211; then adjust some volumes on the speakers, turn them on, then rewind the track.</p>

<p>If iTunes is paused for more than 2 minutes, and the speakers are on &#8211; and they were turned on by this autodetect system, then turn the speakers off.</p>

<p>The turning on and off is done by my original HTPC applescript which controls an <a href="http://www.irtrans.de/en/shop/usb.php">irTrans</a> USB IR transceiver through the iRed software.</p>

<p>Now we just fire up the remote app on the phone, and within a few seconds the speakers are on and the music is playing.</p>

<pre><code>#!/usr/bin/env python
# encoding: utf-8
"""

Created by Preston Holmes on 2009-09-05.
preston@ptone.com
Copyright (c) 2009

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

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

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

import sys
import os
from appscript import *
from subprocess import Popen, call, STDOUT, PIPE
import plistlib
import time

prefs = '/Library/Preferences/com.ptone.tuneswatcher.plist'
vol_target = '/Users/Preston/Documents/HTPC/targetvolume'

def sh(cmd):
    return Popen(cmd,shell=True,stdout=PIPE,stderr=PIPE).communicate()[0]

def itunes_running_():
    for p in psi.process.ProcessTable().items():
        try:
            if "Applications/iTunes" in p.command:
                return True
        except:
            pass
    return False

def init_prefs ():
    d = {'state':'unknown','last_state_change':time.time(),'auto_on':False}
    plistlib.writePlist (d,prefs)

def itunes_running():
    pcount = sh('ps -xa | grep -c iTunes').strip()
    return int(pcount) &gt; 3

def getSettings():
    settings_file = '/Users/preston/Documents/HTPC/settings'
    f = open(settings_file,'r')
    flines = f.readlines()
    f.close()
    settingsDict = {}
    for aLine in flines:
        aLine = aLine.rstrip('\n')
        #print aLine
        if aLine != '':
            apair = aLine.split(' ')
            settingsDict[apair[0]] = apair[1]
    return settingsDict

def read_prefs ():
    if not os.path.exists (prefs):
        init_prefs()
    d = plistlib.readPlist (prefs)
    htpc_settings = getSettings()
    d.update(htpc_settings)
    return d

def save_prefs(d):
    plistlib.writePlist (d,prefs)

def main():
    d = read_prefs()
    # print d
    is_running = itunes_running()
    if is_running:
        tunes = app("iTunes")
        # print "tunes.running"
        playing = (tunes.player_state() == k.playing)
        # print tunes.player_state() 
        # print playing
        if playing:  
            # print "tunes.playing"
            if d['speakers'] == 'off':
                # turn on speakers
                tunes.pause()
                sh ("""osascript -e 'tell application "HTPC" to power_speakers()'""")
                if int(d['volume']) &lt; 40:
                    open(vol_target,'w').write("50")
                    sh ("""osascript -e 'tell application "HTPC" to setVolume()'""")
                tunes.sound_volume.set(60)
                tunes.player_position.set(0)
                tunes.play()
                d['auto_on'] = True
                save_prefs(d)
                # start streamer here?
            if d['state'] != 'playing':
                d['state'] = 'playing'
                d['last_state_change'] = time.time()
                save_prefs(d)


        else: # iTunes not playing
            if d['state'] == 'playing':
                d['state'] = 'stopped'
                d['last_state_change'] = time.time()
                save_prefs(d)
            # check if last change was 5 minutes ago and turn off speakers
            if d['auto_on'] and ((time.time() - d['last_state_change']) &gt; 10):
                if d['speakers'] == 'on':
                    # turn speakers off only if turned on automatically
                    sh ("""osascript -e 'tell application "HTPC" to power_speakers()'""")
                    sh ("""osascript -e 'tell application "HTPC" to calibrateVolume()'""")
                d['auto_on'] = False
                save_prefs(d)
        # print (tunes.player_state() == k.stopped)


if __name__ == '__main__':
    main()
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2009/09/making-iphone-itunes-remote-more-useful/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Making Google Earth work for us</title>
		<link>http://ptone.com/dablog/2009/09/making-google-earth-work-for-us/</link>
		<comments>http://ptone.com/dablog/2009/09/making-google-earth-work-for-us/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 00:02:07 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[osx]]></category>
		<category><![CDATA[sysadmin]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2009/09/making-google-earth-work-for-us/</guid>
		<description><![CDATA[In our school environment, we had a couple issues with Google Earth&#8217;s default behaviors &#8211; here are my workarounds.



First off we have a student web proxy that works based on a whitelist concept.  So we have to allow any web traffic explicitly.  With the help of little snitch and one incomplete help page [...]]]></description>
			<content:encoded><![CDATA[<p>In our school environment, we had a couple issues with Google Earth&#8217;s default behaviors &#8211; here are my workarounds.</p>

<p><span id="more-84"></span></p>

<p>First off we have a student web proxy that works based on a whitelist concept.  So we have to allow any web traffic explicitly.  With the help of little snitch and one incomplete help page from google, here is what I&#8217;ve added to our global whitelist and seems to be allowing all the features:</p>

<ul>
<li>kh.google.com</li>
<li>www.keyhole.com</li>
<li>mw2.google.com</li>
<li>earth.google.com</li>
<li>auth.keyhole.com</li>
<li>maps.google.com</li>
<li>khmdb.google.com</li>
</ul>

<p>It also want access to www.google.com &#8211; but we don&#8217;t allow students to full google access &#8211; but Google Earth still seems to run fine.</p>

<p>The next annoyance was Google&#8217;s softwareupdate which wants to run for all users and update Google Earth on launch.</p>

<p>Adding the following to our loginhook fixed that:</p>

<pre><code>mkdir -P $nethomedir/Library/Google/
touch $nethomedir/Library/Google/GoogleSoftwareUpdate
chown root $nethomedir/Library/Google/GoogleSoftwareUpdate
chmod 644 $nethomedir/Library/Google/GoogleSoftwareUpdate
</code></pre>

<p>the $nethomedir var is fetched from dscl earlier in the script</p>

<p>Students need to have stored the proxy password in their keychain &#8211; but most have already done that when visiting a web page earlier.  They then just need to allow Google Earth to access their keychain.</p>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2009/09/making-google-earth-work-for-us/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>simple weak password generator</title>
		<link>http://ptone.com/dablog/2009/09/simple-weak-password-generator/</link>
		<comments>http://ptone.com/dablog/2009/09/simple-weak-password-generator/#comments</comments>
		<pubDate>Thu, 03 Sep 2009 21:04:39 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[sysadmin]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2009/09/simple-weak-password-generator/</guid>
		<description><![CDATA[There are times I need to create some easy to remember weak initial passwords for students &#8211; here is a quick script



Note that these are not strong passwords as they are the definition of &#8220;dictionary&#8221; passwords&#8230;

import sys
import os
import random

dfile = '/usr/share/dict/web2'

def main():
    for x in range(130):
       [...]]]></description>
			<content:encoded><![CDATA[<p>There are times I need to create some easy to remember weak initial passwords for students &#8211; here is a quick script</p>

<p><span id="more-83"></span></p>

<p>Note that these are not strong passwords as they are the definition of &#8220;dictionary&#8221; passwords&#8230;</p>

<pre><code>import sys
import os
import random

dfile = '/usr/share/dict/web2'

def main():
    for x in range(130):
        winner = False
        MAX = 234936
        suffix = random.randint (10,100)
        while not winner:
            choice = random.randint(1,MAX)
            f = open(dfile)
            for i,l in enumerate(f):
                l = l.strip()
                length = len(l)
                if i &lt; choice:
                    continue
                if length &gt; 3 and length &lt; 7:
                    winner = '%s%d' % (l,suffix)
                    break
        f.close()
        print winner.lower()


if __name__ == '__main__':
    main()
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2009/09/simple-weak-password-generator/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Managing mailman on the command line</title>
		<link>http://ptone.com/dablog/2009/08/managing-mailman-on-the-command-line/</link>
		<comments>http://ptone.com/dablog/2009/08/managing-mailman-on-the-command-line/#comments</comments>
		<pubDate>Mon, 24 Aug 2009 17:14:00 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[sysadmin]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2009/08/managing-mailman-on-the-command-line/</guid>
		<description><![CDATA[Even though we moved our email from OS X server to google apps for education &#8211; we still manage our lists with a local mailman instance (still on 10.4).  However the web based interface for adding new members can be a bit of a pain as it never seems to remember the right authorization [...]]]></description>
			<content:encoded><![CDATA[<p>Even though we moved our email from OS X server to google apps for education &#8211; we still manage our lists with a local mailman instance (still on 10.4).  However the web based interface for adding new members can be a bit of a pain as it never seems to remember the right authorization when switching between lists &#8211; luckily mailman has some great command line tools.</p>

<p><span id="more-82"></span></p>

<p>These are documented here:</p>

<p><a href="http://www.list.org/site.html">http://www.list.org/site.html</a></p>

<p>They are located in /usr/share/mailman/bin/</p>

<p>so you may want to add that to your path in .bash_profile</p>

<p>most have decent help summary with &#8211;help arg at command line</p>

<p>while the remove_members command accepts addresses on the command line itself:</p>

<pre><code>remove_members [options] [listname] [addr1 ...]

remove_members staff frank@foo.com
</code></pre>

<p>The add_members command specifically wants file input.  Sometimes I just want to add 2-3 so I use this trick:</p>

<pre><code>add_members -r - staff &lt;&lt;-EOF
&gt;sue@foo.com
&gt;bob@bar.com
&gt; &lt;cntl-d&gt;
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2009/08/managing-mailman-on-the-command-line/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Editing long commands</title>
		<link>http://ptone.com/dablog/2009/08/editing-long-commands/</link>
		<comments>http://ptone.com/dablog/2009/08/editing-long-commands/#comments</comments>
		<pubDate>Tue, 18 Aug 2009 21:39:52 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[osx]]></category>
		<category><![CDATA[tip]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2009/08/editing-long-commands/</guid>
		<description><![CDATA[Sometimes you get in a situation where you are editing a long command on the command line and you&#8217;d kill to be able to use your mouse to select a word or option in the middle.  This tip makes it a pleasure



First for me their was the discovery of cntl-a which jumps one back [...]]]></description>
			<content:encoded><![CDATA[<p>Sometimes you get in a situation where you are editing a long command on the command line and you&#8217;d kill to be able to use your mouse to select a word or option in the middle.  This tip makes it a pleasure</p>

<p><span id="more-81"></span></p>

<p>First for me their was the discovery of cntl-a which jumps one back to the beginning of a line, but just as often I wanted to delete a long path as an opt to a long command.</p>

<p>The first thing is to set your default Editor in your environment variables.  I use TextMate &#8211; but you could use textwrangler, VI, Emacs.</p>

<p>add a line like this to your ~/.bash_profile</p>

<p>export EDITOR=&#8221;mate -w&#8221;</p>

<p>then close your terminal session or &#8220;source ~/.bash_profile&#8221;</p>

<p>Now when you are in the middle of typing a long command, or after hitting the up arrow, press cntl-x and hold it, then hit &#8220;e&#8221;</p>

<p>boom &#8211; your current command opens up in your editor, you can use all the features of that editor, and when you save and close that file &#8211; the command will be executed back in your shell.</p>

<p>Since I&#8217;ve integrated this tip into my workflow &#8211; I find I use it all the time.</p>

<p>Only downside is GUI editors won&#8217;t work for SSH since you are in the remote hosts env &#8211; there is probably a tricky way to reverse-ssh the editor command back to you, but I haven&#8217;t explored that.</p>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2009/08/editing-long-commands/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Letting users get to (i)Work</title>
		<link>http://ptone.com/dablog/2009/08/letting-users-get-to-iwork/</link>
		<comments>http://ptone.com/dablog/2009/08/letting-users-get-to-iwork/#comments</comments>
		<pubDate>Thu, 13 Aug 2009 14:15:51 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Random Observation]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2009/08/letting-users-get-to-iwork/</guid>
		<description><![CDATA[iLife and iWork can throw up an awful lot of update dialogs and welcome screens for people who first launch them.  For users on my network I wanted to prevent those from coming up



There are a number of defaults that can be set to make these not appear.  The preferred way is to [...]]]></description>
			<content:encoded><![CDATA[<p>iLife and iWork can throw up an awful lot of update dialogs and welcome screens for people who first launch them.  For users on my network I wanted to prevent those from coming up</p>

<p><span id="more-80"></span></p>

<p>There are a number of defaults that can be set to make these not appear.  The preferred way is to manage these with MCX, but for now I&#8217;ve deployed these as a login script (its lazy-easy because its all in just one text file)</p>

<p>This will set defaults so that iWork and iLife don&#8217;t bug the user.  There are also defaults to turn off auto update check in perian, disable the welcome movie for Safari 4 and to set the standard file format for iWork 09 to use the iWork 08 package style file format which is more efficient when saving over the network.  Finally there is a default to tell iTunes not to look for shared music.</p>

<p>Most of these should be pretty straight forward to read &#8211; if you have others, please post them in the comments.</p>

<p>TODO: make these into MCX manifests?</p>

<pre><code># !/bin/bash
echo Setting iPrefs...

sudo -u $1 defaults write org.perian.Perian NextRunDate -date '4000-12-31 16:00:00 -0800'

# iWork

sudo -u $1 defaults -currentHost write com.apple.iWork SFLDefaultsAutoUpdateCheck -bool FALSE
defaults write /Library/Preferences/com.apple.iWork09 DisplayedRegistrationWindowCount -int 3
defaults write /Library/Preferences/com.apple.iWork09 ShouldNotSendRegistration -bool TRUE
chown admin:admin /Library/Preferences/com.apple.iWork09.plist
chmod 644 /Library/Preferences/com.apple.iWork09.plist

sudo -u $1 defaults write com.apple.iWork.Keynote DisplayedRegistrationWindowCount -int 2
sudo -u $1 defaults write com.apple.iWork.Keynote RegistrationHasBeenSent -bool TRUE
sudo -u $1 defaults -currentHost write com.apple.iWork.Keynote FirstRunFlag -bool TRUE
sudo -u $1 defaults write com.apple.iWork.Keynote dontShowWhatsNew -bool TRUE
sudo -u $1 defaults write com.apple.iWork.Keynote DisableSingleFileFormat -bool TRUE

sudo -u $1 defaults write com.apple.iWork.Pages DisplayedRegistrationWindowCount -int 2
sudo -u $1 defaults write com.apple.iWork.Pages RegistrationHasBeenSent -bool TRUE
sudo -u $1 defaults -currentHost write com.apple.iWork.Pages FirstRunFlag -bool TRUE
sudo -u $1 defaults write com.apple.iWork.Pages dontShowWhatsNew -bool TRUE
sudo -u $1 defaults write com.apple.iWork.Pages DisableSingleFileFormat -bool TRUE

sudo -u $1 defaults write com.apple.iWork.Numbers DisplayedRegistrationWindowCount -int 2
sudo -u $1 defaults write com.apple.iWork.Numbers RegistrationHasBeenSent -bool TRUE
sudo -u $1 defaults -currentHost write com.apple.iWork.Numbers FirstRunFlag -bool TRUE
sudo -u $1 defaults write com.apple.iWork.Numbers dontShowWhatsNew -bool TRUE
sudo -u $1 defaults write com.apple.iWork.Numbers DisableSingleFileFormat -bool TRUE

# Garageband
sudo -u $1 defaults write com.apple.garageband dontShowWhatsNew -bool TRUE
sudo -u $1 defaults write com.apple.garageband DfPrefs_NoDocumentPanel -bool TRUE
sudo -u $1 defaults write com.apple.garageband DfPrefs_NextUpgradeCheck -date 'Aug 10, 2012 12:00:00 PM'
sudo -u $1 defaults write com.apple.garageband DfPrefs_AskAboutUpgrades -dict '5.1' 'NO'

# iMovie
sudo -u $1 defaults write com.apple.iMovie8 dontShowWhatsNew -bool TRUE
sudo -u $1 defaults write com.apple.iMovie8 AutoUpgradeCheck -bool FALSE
sudo -u $1 defaults write com.apple.iMovie8 NextUpgradeCheck -date 'Aug 10, 2012 12:00:00 PM'
# no proof that this one is recognized - but it is in the others
sudo -u $1 defaults write com.apple.iMovie8 SFLDefaultsAutoUpdateCheck -bool FALSE

# iPhoto
sudo -u $1 defaults write com.apple.iPhoto CheckForUpdates -bool FALSE
sudo -u $1 defaults write com.apple.iPhoto dontShowWhatsNew -bool TRUE
sudo -u $1 defaults write com.apple.iPhoto GeocodeLookupPreference -int 0
sudo -u $1 defaults write com.apple.iPhoto NextUpgradeCheck -date 'Aug 10, 2012 12:00:00 PM'
# not so sure about these:
sudo -u $1 defaults write com.apple.iPhoto SFLDefaultsAutoUpdateCheck -bool FALSE
sudo -u $1 defaults write com.apple.iPhoto UpdateSplash -int 8

# iTunes
sudo -u $1 defaults write com.apple.iTunes lookForSharedMusic -bool FALSE

# iWeb
sudo -u $1 defaults write com.apple.iWeb dontShowWhatsNew -bool TRUE
sudo -u $1 defaults write com.apple.iWeb dismissDotMacUpsellWindow -bool TRUE
sudo -u $1 defaults write com.apple.iWeb SFLDefaultsAutoUpdateCheck -bool FALSE
sudo -u $1 defaults -currentHost write com.apple.iWeb FirstRunFlag -bool TRUE 

# Safari
sudo -u $1 defaults write com.apple.Safari LastDisplayedWelcomePageVersionString '4.0'
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2009/08/letting-users-get-to-iwork/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Geek distractions</title>
		<link>http://ptone.com/dablog/2009/08/geek-distractions/</link>
		<comments>http://ptone.com/dablog/2009/08/geek-distractions/#comments</comments>
		<pubDate>Fri, 07 Aug 2009 21:51:19 +0000</pubDate>
		<dc:creator>ptone</dc:creator>
				<category><![CDATA[Random Observation]]></category>

		<guid isPermaLink="false">http://ptone.com/dablog/2009/08/geek-distractions/</guid>
		<description><![CDATA[Tools are getting so sophisticated now &#8211; that they can be a distraction for the lightweight or part time coder.

You can get lost in the ins and outs of git vs hg, choosing a database engine (SQL vs Key-Value etc), javascript frameworks, PIP vs Buildout and integrating with virtualenv.

They all have their merit, especially to [...]]]></description>
			<content:encoded><![CDATA[<p>Tools are getting so sophisticated now &#8211; that they can be a distraction for the lightweight or part time coder.</p>

<p>You can get lost in the ins and outs of git vs hg, choosing a database engine (SQL vs Key-Value etc), javascript frameworks, PIP vs Buildout and integrating with virtualenv.</p>

<p>They all have their merit, especially to people who sit in this world all day long, but none of them directly produce work product for you.  They are tools &#8211; and its best to learn them bit by bit, not all at once, or you will be overwhelmed.</p>
]]></content:encoded>
			<wfw:commentRss>http://ptone.com/dablog/2009/08/geek-distractions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.614 seconds -->
