xUnique – Xcode project file merge with no conflicts


If you are an Objective C developer using Xcode, and push your code to Git/SVN like other guys did in the team, I think you most probably have encountered the merge conflicts of project.pbxproj file.

It’s such a pain to merge this file by searching the file with <<<,>>> and ===, and then deleting and keeping lines by your judge. It would leave some unused lines or even make Xcode build fail due to wrong decision.

Since UUID generated by Xcode in project.pbxproj file is not unique for all machines, different Xcode got different UUID for the same file or filegroup. That’s why it created conflicts.


I just found that Xcode does not care the UUID in the file, it just needs to be unique in the file. So I made xUnique to fix the merge conflicts issue.

How it works

  • All elements in project file are actually connected as a tree
  • We give a path to every node of the tree using its unique attribute; this path is the absolute path to the root node connected by these attributes
  • Apply MD5 hex digest to the path for the node
  • these digests are the new UUIDs in the project file
  • Sort project file using my pure Python implementation of my modified sort-Xcode-project-file, supports following new features:
    • sort PBXFileReference and PBXBuildFile sections
    • avoid modified changes in Git/SVN if no change made in the project file

How to use

  1. Put xUnique.py file in your project repository somewhere and add it as track file via git add path/to/xUnique.py, so all members could use the same script
  2. create a git hook: ln -s path/to/xUnique.py .git/hooks/pre-push
  3. Add permission chmod 555 .git/hooks/pre-push
    • use hook pre-push instead of pre-commit is a safe consideration: you decide to commit the newly generated project file or not
  4. In all your branches, uniquify project.pbxproj file in either way:
    • make some changes and commit. Try to push, git hook would be triggered
    • manually run script: python path/to/xUnique.py path/to/MyProject.xcodeproj and then committing changes.
  5. All Done;)


Python bottle support for JSONP



from bottle import response, request, install
def jsonp(callback):
    def wrapper(*args, **kwargs):
        resp = callback(*args, **kwargs)
        if isinstance(resp, (dict,list)):
            #response.charset='utf-8' # set property error , do not know why
            response.content_type = 'application/json;utf-8' # after added this line, we do not need to mess with character encoding in json.dumps; the commented out code is what i did before
            callback_arg = request.query.get('callback')
            if callback_arg:
                resp= '{}({})'.format(callback_arg, json.dumps(resp))#,ensure_ascii=False))#.encode('utf-8')
        return resp
    return wrapper

install(jsonp) # install the plugin in the bottle app


  • 最开始我是让json模块dumps处理的字符串进行解码,然后encode成utf-8,这样输出就正常了(代码见被注释掉的倒数第五行)
  • 后来发现只需要对返回的内容格式content-type限定为json和utf-8,就自动解析正常了(代码见倒数第八行)

Python Bottle+virtualenv+uWSGI+Nginx installation on Ubuntu 12.04.1 LTS


为了造福世界人民,我觉得还是用英语写吧 XD

Today I got a request to write a backend server to provide interface access from frontend. I determined to use Python and  RESTful api firstly . I hate writing Java code…

After some investigation, I picked up Bottle. It is very neat and small. And I also read that with nginx and uWSGI, the performance is good too.

My environment is Ubuntu 12.04.1 LTS; but after followed several posts, my environment still did not work. I want to share my findings to save others’ time:)

Let’s cut to the chase:

  • Note:

My application would be in below directory constructure, all following commands and configurations are based on below:
/var/www/myapp would be the root directory of my bottle app
/var/www/myapp/env would be the virtualenv for the app
/var/www/myapp/index.py would be main .py file of bottle

  • Install nginx and uwsgi:
sudo apt-get update
sudo apt-get install -y nginx uwsgi
sudo apt-get install uwsgi-plugin-python
  • Install pip to help install python modules
sudo apt-get install python-pip
  • Install virtualenv: virtualenv to seperate the Python environment for different deployments
sudo pip install virtualenv
  • Set up app virtualenv:
sudo mkdir -p /var/www/myapp
sudo virtualenv /var/www/myapp/env
source /var/www/myapp/env/bin/activate
pip install bottle
  • Change the permission of the app directory so that uWSGI can read it and Python can write in it
sudo chown -R www-data:www-data /var/www/myapp
  • OK, the most important part: the configuration of nginx and uWSGI. These two recipes would worth some money XD

1. nginx config:

sudo gedit /etc/nginx/sites-enabled/default

copy below config in opend file:

server {

     listen   80;
     charset utf-8;
     root /var/www/myapp;
     server_name localhost;

location / {
     include uwsgi_params;
     uwsgi_pass unix:/tmp/uwsgi.myapp.socket;
     uwsgi_param UWSGI_PYHOME /var/www/myapp/env;
     uwsgi_param UWSGI_CHIDIR /var/www/myapp;
     uwsgi_param UWSGI_SCRIPT index; # this should be the .py file name without suffix that your bottle will use to launch

2.uWSGI config:

sudo gedit /etc/uwsgi/apps-enabled/uwsgi.ini

copy below config in opend file:

  • Now we are one step to success. In order to verify the setup, we need a sample index.py file ( the file name must be consistent with the one in UWSGI_SCRIPT in nginx config).

Put index.py under /var/www/myapp

#!/usr/bin/env python
from bottle import route, run, default_app
def index():
    return "Aloha, world~"

if __name__ == "__main__":
    run(host="localhost", port=8081)
    application = default_app()
  • Finally, Restart/start nginx and uWSGI services:
sudo service nginx restart
sudo service uwsgi restart

Now “it’s the moment to witness the miracle!” 😀  Access http://localhost/ in your browser, you should  see “Aloha, world~”.  If not, comment below:)

Get lucky room IP address in Diablo 3 using Sikuli

Oct/7/2012 update:

I just wrote this for fun and did not want to be in any trouble so I did not upload the script. But it seems that many guys really typed it character by character, I think I should upload it 🙂

Here is the download link. Have fun. By the way, my battle tag is SeanWang#1150, usually play on US Server, also Asia Server sometimes.

After I noticed that guys  posted that certain servers of Diablo 3 have good drops (orginal post and battlenet quote) than others, I observed this ip address stuff when repeatedly running Warrior’s Rest using a monk with all MF items

My conclusion is that it is some sort of correct! especially the part about ” last number of the ip address that is over 80 is not good”.

certain servers have good drops and some have bad drops, each time you log in you are connected to a random server this is how you can find servers with better drops than others.
1) go to your cmd promt while logged into a game (not at the log in screen or at char screen but in a game)
2) type in “netstat -n” into your cmd promt to find what server you are connected to the last 4 digits of the ip are what matter. anything with 3 digits sucks and typically games with 2 digit ending in even numbers are good loot games. The best ones are “74:1119” and “76:1119” but 72-78 even work also, games like 46 also work.

So based on this theory, I wrote a Sikuli script to get the ip address less than 80. In my script, I did not judge for even number, because I think that it may be too long to get a even number AND less than 80. Too many times creating and quiting games may trigger the Blizzard anti-bot mechanism…

Here comes the script:)

NOTICE: Above script should only work in windowed game mode.

Have fun:)

“你画我猜”(draw something)单词猜测工具 – 升级版

前几天写的“你画我猜”(draw something)单词猜测工具,最后提到了有道已经做了相关工具。既然有大树了,俺们就可以直接乘凉了~


#!/usr/bin/env python
# -*- coding: utf-8 -*-
@author: Sina Weibo @SeganW
from __future__ import unicode_literals
import urllib
import lxml.html as lh
import sys

def query(char_str,num=None):
    if not None:
    except Exception as e:
        if con:
        raise SystemExit('[error] guess request failed: {}'.format(e))
    words=[i.text_content().lower() for i in doc.xpath("//span[@class='word']")]
    translates=[i.text_content() for i in doc.xpath("//div[@class='trans']")]
    return zip(words,translates)

if __name__ == '__main__':
    if len(args)==2:
        charstr= args[1]
    elif len(args)==3:
        charstr= args[1]
        raise SystemExit('usage: drawsomthing.py charstr [num]')
    if results:
        for sub_result in results:
            print '{}:\t{}'.format(*sub_result)
        print "No results found:("



drawsomething_updated.py char_str [num]


选择最快的appstore ip地址之Python版


苹果为 App Store 准备了 a1.phobos.apple.com 到 a2000.phobos.apple.com 这么一群服务器,美国、欧洲、日韩、港澳……就是没有中国。。。


注意:只写了Mac OS X版本的

#!/usr/bin/env python
# -*- coding: utf-8 -*-
@author: Sina weibo @SeganW
Only works in Mac OS X, I tested in Yosemite
from __future__ import unicode_literals
from subprocess import check_output, CalledProcessError
from re import compile as re_compile
from sys import getfilesystemencoding
from os import devnull
from multiprocessing.dummy import Pool 

URLS = ['a{}.phobos.apple.com'.format(i) for i in range(1,2001)]
IP_PTN = re_compile('\d+\.\d+\.\d+\.\d+')
AVG_PTN = re_compile('min/avg/max/stddev = \d+\.\d+/(\d+\.\d+)/')

def ping_test(url):
        with open(devnull, 'w') as null:
            output = check_output(['ping','-c','3', url], stderr=null).decode(getfilesystemencoding())
            ip = IP_PTN.search(output).group()
            avg = float(AVG_PTN.search(output).group(1))
    except CalledProcessError:
        ip = ""
        avg = ""
    print 'Server {}\t||\t Average Speed: {}ms'.format(url,avg)
    return {ip: avg}

if __name__ == '__main__':
    pool = Pool(25) #25 is process count, try increase or decrease it to find the best performance
    results = pool.map(ping_test, URLS)
    best = min(results,key=lambda x: x.values()[0])
    best_svr = results.index(best)
    print '***** Best server is a{}.phobos.apple.com, ip={}, avg speed={}ms *****'.format(best_svr, best.keys()[0],best.values()[0])



#!/usr/bin/env python
# -*- coding: utf-8 -*-
@author: Sina weibo @SeganW
from __future__ import unicode_literals
import subprocess
import re
import sys
import threading

URLS=map(lambda x: 'a{}.phobos.apple.com'.format(x), range(1,501))
BEST=[2**16,'',''] # a big number normally larger than average
SPEED_PTN=re.compile('平均 = (\d+)ms')

class Ping(threading.Thread):
    def __init__(self, url, lock):

    def run(self):
        except subprocess.CalledProcessError as cpe:
            print cpe.output
            avg='timed out'
        ip= IP_PTN.search(output).group(1)
        print 'Server {}\t||\t Average Speed: {}'.format(self.url,avg)
        if avg =='timed out':
        elif BEST[0] &amp;amp;gt; int(avg[:-2]):
            BEST[0] = int(avg[:-2])
            BEST[1] = ip
            BEST[2] = url
        global NUM
        if NUM==len(URLS):
            print 'Fastest server: {2} ( {1} ) fastest average speed: {0}ms'.format(*BEST)

if __name__ == '__main__':
        for url in URLS:
    except KeyboardInterrupt:


#!/usr/bin/env python
# -*- coding: utf-8 -*-
@author: Sina weibo @SeganW
from __future__ import unicode_literals
import subprocess
import re
import sys

urls=map(lambda x: 'a{}.phobos.apple.com'.format(x), range(1,2001))
best=[2**16,'',''] # a big number normally larger than average
speed_ptn=re.compile(r'平均 = (\d+)ms')
    for url in urls:
        output=subprocess.check_output('ping {}'.format(url),shell=True).decode(sys.getfilesystemencoding())
        output=[i for i in output.split('\r\n') if i]
        ip= ip_ptn.search(output[0]).group(1)
        print 'Server {}\t||\t Average Speed: {}ms'.format(url,avg)
        if best[0] &amp;amp;gt; avg:
            best[0] = avg
            best[1] = ip
            best[2] = url
except KeyboardInterrupt:
    print '\n'
print 'Fastest ip address:\n{1} {2}\nfastest speed: {0}ms'.format(*best)