├── .gitignore ├── README.md ├── adapter.sh ├── content-extractor ├── README └── bin │ ├── ContentExtractor.py │ ├── MultiTasker.py │ ├── PageParser.py │ ├── main.py │ ├── run │ └── run2 ├── data-aggregator └── bin │ ├── filter_data.sh │ ├── filter_img.sh │ ├── main.py │ ├── make_final.sh │ ├── run │ ├── sim.py │ └── wget_img.sh ├── dict ├── baidu.dict ├── common.dict ├── common.dict.3500 └── sougou.dict ├── house-refinery ├── README └── bin │ ├── HouseRefinery.py │ ├── TextParser.py │ ├── main.py │ └── run ├── libs ├── Browser.py ├── Utils.py ├── Utils.py2 ├── random_extraction.sh └── testawk.sh ├── link-spider ├── README └── bin │ ├── LinkSpider.py │ ├── LinkSpider.py2 │ ├── PageParser.py │ ├── main.py │ └── run ├── manage.sh ├── page-spider └── bin │ ├── PageSpider.py │ ├── main.py │ └── run ├── requirements ├── run.sh ├── screenshot.png ├── screenshot1.jpg ├── screenshot2.jpg ├── ui ├── README ├── app │ ├── __init__.py │ ├── admin.py │ ├── models.py │ ├── tests.py │ ├── urls.py │ └── views.py ├── manage.py ├── requirements ├── run_server.sh ├── static │ ├── bootstrap3 │ │ ├── css │ │ │ ├── bootstrap-theme.css │ │ │ ├── bootstrap-theme.css.map │ │ │ ├── bootstrap-theme.min.css │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.css.map │ │ │ └── bootstrap.min.css │ │ ├── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ └── glyphicons-halflings-regular.woff │ │ └── js │ │ │ ├── bootstrap.js │ │ │ └── bootstrap.min.js │ ├── css │ │ └── app.css │ ├── img │ │ ├── alipay.png │ │ ├── default_image.png │ │ ├── favicon.ico │ │ ├── invalid_image.png │ │ ├── logo-pink.png │ │ ├── logo-sm.png │ │ ├── logo.jpg │ │ ├── logo.png │ │ └── qr.jpg │ ├── imgdir │ ├── js │ │ ├── app.js │ │ ├── controllers.js │ │ ├── jquery-2.0.3.min.js │ │ ├── jquery-2.0.3.min.map │ │ ├── jquery.dotdotdot.min.js │ │ └── services.js │ └── partials │ │ ├── donate.html │ │ ├── empty.html │ │ ├── error.html │ │ ├── home.html │ │ ├── search.html │ │ └── statistic.html ├── templates │ ├── 404.html │ ├── 500.html │ └── index.html └── ui │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── uwsgi ├── dependencies ├── nginx.conf ├── run_server.sh ├── uwsgi.ini └── uwsgi_params ├── zhaoxinwo-android.gif └── zhaoxinwo-web.gif /.gitignore: -------------------------------------------------------------------------------- 1 | *.apk 2 | 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | log/ 13 | data/ 14 | output/ 15 | env/ 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | downloads/ 20 | eggs/ 21 | lib/ 22 | lib64/ 23 | parts/ 24 | sdist/ 25 | var/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | nohup.out 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .coverage 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | 56 | # Sphinx documentation 57 | docs/_build/ 58 | 59 | # PyBuilder 60 | target/ 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | zhaoxinwo source code 2 | === 3 | 4 | *Please contact me before commercial use.* 5 | *商业用途请先联系作者* 6 | 7 | Introduction 8 | --- 9 | 10 | zhaoxinwo can help you search douban rental data(e.g. ). Since we launched zhaoxinwo in October 2015, there are thousands of users used it. Now zhaoxinwo is open-source, including the backend services, android app and iOS app. 11 | 12 | Deployment 13 | --- 14 | 15 | 16 | 17 | Source codes 18 | --- 19 | 20 | - Backend services: 21 | - Android app: 22 | - iOS app: 23 | 24 | Website 25 | --- 26 | 27 | 28 | 29 | ![](screenshot.png) 30 | 31 | ![](zhaoxinwo-web.gif) 32 | 33 | Android 34 | --- 35 | 36 | 37 | 38 | ![](screenshot1.jpg) 39 | 40 | ![](screenshot2.jpg) 41 | 42 | ![](zhaoxinwo-android.gif) 43 | 44 | iOS 45 | --- 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | License 58 | --- 59 | 60 | MIT 61 | 62 | [@zhangxiaoyang](https://github.com/zhangxiaoyang) 63 | [@jiadebin](https://github.com/jiadebin) 64 | [@zhengbuqian](https://github.com/zhengbuqian) 65 | -------------------------------------------------------------------------------- /adapter.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # zhangxiaoyang.hit[at]gmail.com 3 | 4 | readonly WORKSPACE=$(pwd) 5 | readonly dbs=(\ 6 | "link.db"\ 7 | "link.meta"\ 8 | "pagelist"\ 9 | "content.db"\ 10 | "house.db"\ 11 | "imglist"\ 12 | "imglist.0"\ 13 | "imglist.diff"\ 14 | "final.db"\ 15 | "final.db.2"\ 16 | "zufang.house.json"\ 17 | "sim.db"\ 18 | ) 19 | readonly modules=(\ 20 | "link-spider"\ 21 | "link-spider"\ 22 | "page-spider"\ 23 | "content-extractor"\ 24 | "house-refinery"\ 25 | "data-aggregator"\ 26 | "data-aggregator"\ 27 | "data-aggregator"\ 28 | "data-aggregator"\ 29 | "data-aggregator"\ 30 | "data-aggregator"\ 31 | "data-aggregator"\ 32 | ) 33 | readonly opts=("import" "export") 34 | 35 | function nothing() 36 | { 37 | echo "do nothing... exit" 38 | exit 0; 39 | } 40 | 41 | function adapter() 42 | { 43 | if [[ ${opts[@]} =~ "$1" ]] 44 | then 45 | opt="$1" 46 | path="$2" 47 | else 48 | echo "Usage: ./adapter.sh [import/export] directory" 49 | nothing 50 | fi 51 | 52 | case "$opt" in 53 | "import" ) 54 | if [ -d "$path" ] 55 | then 56 | for ((i=0;i<${#dbs[@]};i++)) 57 | do 58 | db=${dbs[$i]} 59 | module=${modules[$i]} 60 | mkdir -p "$WORKSPACE/$module/output" 61 | echo "cp $path/$db -> $WORKSPACE/$module/output" 62 | cp "$path/$db" "$WORKSPACE/$module/output" 63 | done 64 | else 65 | nothing 66 | fi 67 | ;; 68 | "export" ) 69 | if [ -d "$path" ] 70 | then 71 | zufang="$path/zufang-$(date +%Y%m%d-%H%M%S)" 72 | mkdir -p "$zufang" 73 | for ((i=0;i<${#dbs[@]};i++)) 74 | do 75 | db=${dbs[$i]} 76 | module=${modules[$i]} 77 | echo "cp $WORKSPACE/$module/output/$db -> $zufang" 78 | cp "$WORKSPACE/$module/output/$db" "$zufang" 79 | done 80 | else 81 | nothing 82 | fi 83 | ;; 84 | * ) 85 | nothing 86 | ;; 87 | esac 88 | } 89 | 90 | # Main entrance 91 | adapter "$1" "$2" 92 | -------------------------------------------------------------------------------- /content-extractor/README: -------------------------------------------------------------------------------- 1 | content.db 2 | hashurl title author(json) images(json) links(json) text pub_time 3 | -------------------------------------------------------------------------------- /content-extractor/bin/ContentExtractor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | from PageParser import PageParser 5 | from Utils import Logger, DB 6 | import json 7 | 8 | class ContentExtractor(object): 9 | 10 | def __init__(self, **args): 11 | self._db = args['db'] 12 | 13 | def parse(self, **args): 14 | page = args['page'] 15 | source = args['source'] 16 | hashurl = args['hashurl'] 17 | ret = PageParser.parse(page, source) 18 | if ret.has_key('error'): 19 | Logger.info(hashurl+' '+ret['error']) 20 | return 21 | record = '\t'.join([ 22 | hashurl, 23 | ret['title2'] if ret['title2']\ 24 | else ret['title'], 25 | json.dumps(ret['author']), 26 | json.dumps(ret['images']), 27 | json.dumps(ret['links']), 28 | ret['text'], 29 | ret['pub_time'], 30 | ]).encode('utf-8') 31 | self._db.insert(record) 32 | -------------------------------------------------------------------------------- /content-extractor/bin/MultiTasker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | import Queue 5 | import threading 6 | import time 7 | import datetime 8 | 9 | class MultiTasker(object): 10 | 11 | def __init__(self, **args): 12 | self._in = Queue.Queue() 13 | self._callback = args['callback'] 14 | self._threadnum = args['threadnum'] 15 | self._outlimit = args['outlimit'] 16 | self._threads = [] 17 | for task in args['tasklist']: 18 | self._in.put(task) 19 | self._out = Queue.Queue() 20 | 21 | def _run(self): 22 | while True: 23 | if self._out.qsize() <= self._outlimit: 24 | try: 25 | task = self._in.get(block=False) 26 | except:#task empty 27 | break 28 | result = self._callback(task) 29 | self._out.put(result) 30 | self._in.task_done() 31 | else: 32 | pass 33 | #print 'full...' 34 | 35 | def run(self): 36 | if self._threadnum: 37 | for i in range(self._threadnum): 38 | self._threads.append(threading.Thread(target=self._run)) 39 | self._threads[i].start() 40 | self._in.join() 41 | else: 42 | self._run() 43 | #self._print_result() 44 | 45 | def stop(self): 46 | for thread in self._threads: 47 | thread.stop() 48 | 49 | def _print_result(self): 50 | pass#print self._out.qsize() 51 | 52 | if __name__ == '__main__': 53 | def callback(task): 54 | with open('tmp.'+str(task), 'w') as f: 55 | for i in range(1000): 56 | f.write('haha') 57 | return task 58 | 59 | for i in range(5): 60 | print '\nthreadnum = '+str(i) 61 | tasklist=range(10000) 62 | tasker = MultiTasker( 63 | tasklist=tasklist, 64 | callback=callback, 65 | outlimit=10000, 66 | threadnum=i 67 | ) 68 | starttime = datetime.datetime.now() 69 | tasker.run() 70 | endtime = datetime.datetime.now() 71 | print 'done! %lds' % (endtime-starttime).seconds 72 | -------------------------------------------------------------------------------- /content-extractor/bin/PageParser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | import re 5 | from BeautifulSoup import BeautifulSoup 6 | 7 | from Utils import Link, Logger 8 | 9 | class PageParser: 10 | 11 | @staticmethod 12 | def parse(page, source): 13 | return { 14 | 'douban':PageParser._parse_douban, 15 | 'shuimu':PageParser._parse_shuimu, 16 | 'ganji':PageParser._parse_ganji, 17 | 'soufun':PageParser._parse_soufun, 18 | '58':PageParser._parse_58, 19 | }[source](page) 20 | 21 | @staticmethod 22 | def _clean(s): 23 | return re.sub('\s+', ' ', s).strip() 24 | 25 | @staticmethod 26 | def _parse_douban(page): 27 | if page.strip() == '': 28 | return {'error':'empty page'} 29 | soup = BeautifulSoup(page) 30 | ret = {} 31 | try: 32 | ret.update({ 33 | 'title2': PageParser._clean(soup.find('div', {'class':'topic-doc'})\ 34 | .find('table', {'class':'infobox'})\ 35 | .find('td', {'class':'tablecc'})\ 36 | .contents[1]) 37 | }) 38 | except: 39 | ret.update({'title2':None}) 40 | try: 41 | content = soup.find('div', {'class':'topic-doc'})\ 42 | .find('div', {'id':'link-report'}) 43 | text = content.findAll('p') 44 | except: 45 | text = [] 46 | try: 47 | images = content.findAll('img') 48 | except: 49 | images = [] 50 | try: 51 | links = reduce(lambda x,y:x+y, [[j['href'] for j in i.findAll('a')] for i in text]) 52 | except: 53 | links = [] 54 | try: 55 | avatar = soup.find('div', {'class':'article'})\ 56 | .find('div', {'class':'user-face'})\ 57 | .find('a')\ 58 | .find('img')['src'] 59 | except: 60 | avatar = None 61 | try: 62 | authorid = PageParser._clean(soup.find('div', {'class':'topic-doc'})\ 63 | .find('h3')\ 64 | .find('span', {'class':'from'})\ 65 | .find('a')['href']\ 66 | .replace('http://www.douban.com/group/people', '')\ 67 | .replace('/', '')) 68 | authorname = PageParser._clean(soup.find('div', {'class':'topic-doc'})\ 69 | .find('h3')\ 70 | .find('span', {'class':'from'})\ 71 | .find('a')\ 72 | .contents[0]) 73 | except: 74 | authorid = None 75 | authorname = None 76 | try: 77 | ret.update({ 78 | 'title':PageParser._clean(soup.find('div', {'id':'content'})\ 79 | .find('h1')\ 80 | .contents[0]), 81 | 'text':PageParser._clean(' '.join([i.getText() for i in text])), 82 | 'pub_time':PageParser._clean(soup.find('div', {'class':'topic-doc'})\ 83 | .find('h3')\ 84 | .find('span', {'class':'color-green'})\ 85 | .contents[0]), 86 | #json string below 87 | 'author':{\ 88 | 'id':authorid, 89 | 'name':authorname, 90 | 'avatar':avatar 91 | }, 92 | 'images':[[i['src'], i['alt']] for i in images], 93 | 'links':[i for i in links], 94 | }) 95 | except Exception, e: 96 | ret = {'error':str(e)} 97 | return ret 98 | 99 | @staticmethod 100 | def _parse_shuimu(page): 101 | pass 102 | 103 | @staticmethod 104 | def _parse_ganji(page): 105 | pass 106 | 107 | @staticmethod 108 | def _parse_soufun(page): 109 | pass 110 | 111 | @staticmethod 112 | def _parse_58(page): 113 | pass 114 | -------------------------------------------------------------------------------- /content-extractor/bin/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | import time 5 | import os 6 | import datetime 7 | import sys 8 | 9 | from ContentExtractor import ContentExtractor 10 | from Utils import Logger, DB, backup 11 | 12 | def diff_task(alltask, donefile): 13 | donetask = [] 14 | with open(donefile, 'r') as f: 15 | for line in f: 16 | if not line: 17 | break 18 | hashurl = line.split('\t')[0] 19 | donetask.append(hashurl) 20 | 21 | exclude = set(donetask) 22 | return [task for task in alltask if task not in exclude] 23 | 24 | def process(pagedirs, contentdb): 25 | sources = os.listdir(pagedirs) 26 | ce = ContentExtractor( 27 | db=DB(contentdb) 28 | ) 29 | for source in sources: 30 | sourcedir = os.path.join(pagedirs, source) 31 | if not os.path.isdir(sourcedir): 32 | continue 33 | pagenames = os.listdir(sourcedir) 34 | pagenames = diff_task(pagenames, contentdb) 35 | for pagename in pagenames: 36 | hashurl = pagename 37 | pagename = os.path.join(sourcedir, pagename) 38 | with open(pagename, 'r') as f: 39 | ce.parse( 40 | page=f.read(), 41 | source=source, 42 | hashurl=hashurl 43 | ) 44 | 45 | def main(**args): 46 | modulepath = args['modulepath'] 47 | pagedirs = os.path.join(modulepath, '../data/') 48 | contentdb = os.path.join(modulepath, '../output/content.db') 49 | backup(contentdb) 50 | process(pagedirs, contentdb) 51 | 52 | if __name__ == '__main__': 53 | starttime = datetime.datetime.now() 54 | run = sys.argv[0] 55 | modulepath = os.path.dirname(run) 56 | main( 57 | modulepath=modulepath 58 | ) 59 | endtime = datetime.datetime.now() 60 | Logger.info('done! %lds' % (endtime-starttime).seconds) 61 | -------------------------------------------------------------------------------- /content-extractor/bin/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | thisdir=${0%/*} 4 | page_src="$thisdir/../../page-spider/output" 5 | page_dst="$thisdir/../data" 6 | 7 | function pull_page() 8 | { 9 | local page_src=$1 10 | local page_dst=$2 11 | rm -f "$page_dst"/* 12 | ln -s "$page_src"/* "$page_dst" 13 | } 14 | 15 | pull_page "$page_src" "$page_dst" 16 | python -u "$thisdir/main.py" >> "$thisdir/../log/log" 2>&1 17 | -------------------------------------------------------------------------------- /content-extractor/bin/run2: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | thisdir=${0%/*} 4 | page_src="$thisdir/../../page-spider/output" 5 | page_dst="$thisdir/../data" 6 | 7 | function pull_page() 8 | { 9 | local page_src=$1 10 | local page_dst=$2 11 | rm -f "$page_dst/*" 12 | ln -s "$page_src"/* "$page_dst" 13 | } 14 | 15 | : << SKIP 16 | function merge_page() 17 | { 18 | local page_dst=$1 19 | local mergefile 20 | local sourcedir 21 | local filename 22 | for src in `ls $page_dst` 23 | do 24 | sourcedir="$page_dst/$src" 25 | if [ -d "$sourcedir" ] 26 | then 27 | mergefile="$page_dst/$src.merge" 28 | rm -f "$mergefile" 29 | for hashurl in `ls $sourcedir` 30 | do 31 | filename="$sourcedir/$hashurl" 32 | if [ -f "$filename" ] 33 | then 34 | echo -e "$hashurl\t$src\t`cat $filename|tr '\r\n' '/n'`\n" >> "$mergefile" 35 | fi 36 | done 37 | fi 38 | done 39 | } 40 | SKIP 41 | 42 | pull_page "$page_src" "$page_dst" 43 | python "$thisdir/main.py" >> "$thisdir/../log/log" 2>&1 44 | -------------------------------------------------------------------------------- /data-aggregator/bin/filter_data.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | readonly finaldb="$1" 4 | readonly month_limit="$2" 5 | now=$(date "+%Y-%m-%d") 6 | 7 | awk -F "\t" ' 8 | BEGIN{ 9 | now = "'$now'"; 10 | month_limit = "'$month_limit'"+0; 11 | split(now, tmp_arr, " "); 12 | split(tmp_arr[1], now_arr, "-"); 13 | now_year = now_arr[1]; 14 | now_month = now_arr[2]; 15 | now_day = now_arr[3]; 16 | delete tmp_arr; 17 | } 18 | { 19 | # hashurl title author images links text pub_time 20 | # 1 2 3 4 5 6 7 21 | # jushi shouji zujin dizhi ditie url crawl_time source ext 22 | # 8 9 10 11 12 13 14 15 16 23 | 24 | pub_time=$7; 25 | split(pub_time, tmp_arr, " "); 26 | split(tmp_arr[1], date_arr, "-"); 27 | year = date_arr[1]; 28 | month = date_arr[2]; 29 | day = date_arr[3]; 30 | 31 | if((now_year-year)*12+(now_month-month)+1 <= month_limit) { 32 | print $0; 33 | } 34 | } 35 | ' "$finaldb" > "$finaldb.$month_limit" 36 | -------------------------------------------------------------------------------- /data-aggregator/bin/filter_img.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | readonly finaldb_cut="$1" 4 | readonly imglist="$2" 5 | 6 | #grep -o "http://[a-zA-Z0-9]*\.douban\.com/view/group_topic/large/public/[a-zA-Z0-9]*\.jpg" "$finaldb_cut" | sort | uniq > "$imglist" 7 | egrep -o 'http[s]?://[^\S:]*?/\w*?\.jpg' "$finaldb_cut" | sort | uniq > "$imglist" 8 | -------------------------------------------------------------------------------- /data-aggregator/bin/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | import time 5 | import os 6 | import datetime 7 | import json 8 | import sys 9 | 10 | from Utils import Logger, DB, backup 11 | 12 | def gen_house(finaldb_cut, jsondb, simdb): 13 | reject_list = [] 14 | sim = {} 15 | with open(simdb, 'r') as f: 16 | for line in f: 17 | if not line: 18 | break 19 | array = line.rstrip('\r\n').split('\t') 20 | hashurl, json_objects = array[0], json.loads(array[1]) 21 | sim[hashurl] = json_objects 22 | reject_list += [i[0] for i in json_objects] 23 | reject_list = set(reject_list) 24 | 25 | with open(finaldb_cut, 'r') as f: 26 | for line in f: 27 | if not line: 28 | break 29 | # hashurl title author images links text pub_time 30 | # 1 2 3 4 5 6 7 31 | # jushi shouji zujin dizhi ditie url crawl_time source ext 32 | # 8 9 10 11 12 13 14 15 16 33 | array = line.rstrip('\r\n').split('\t') 34 | hashurl=array[0] #string,key 35 | title=array[1] #string 36 | author=json.loads(array[2]) #json 37 | images=json.loads(array[3]) #json 38 | links=json.loads(array[4]) #json 39 | text=array[5] #string 40 | pub_time=array[6] #datetime 41 | jushi=array[7] #string 42 | shouji=array[8] #string 43 | zujin=array[9] #string 44 | dizhi=array[10] #string 45 | ditie=array[11] #string 46 | url=array[12] #string 47 | crawl_time=array[13] #string 48 | source=array[14] #string 49 | ext=array[15] #json 50 | 51 | if hashurl in reject_list: 52 | reject_list.remove(hashurl) 53 | print 'skip', hashurl 54 | continue #skip 55 | 56 | new_line = { 57 | "hashurl": hashurl, 58 | "title": title, 59 | "author": author, 60 | "images": images, 61 | "links": links, 62 | "text": text, 63 | "pub_time": pub_time, 64 | "jushi": jushi, 65 | "shouji": shouji, 66 | "zujin": zujin, 67 | "dizhi": dizhi, 68 | "ditie": ditie, 69 | "url": url, 70 | "crawl_time": crawl_time, 71 | "source": source, 72 | "ext": ext, 73 | "sim": sim[hashurl] if sim.has_key(hashurl) else [], 74 | } 75 | jsondb.insert(json.dumps(new_line)) 76 | 77 | def main(**args): 78 | modulepath = args['modulepath'] 79 | finaldb_cut = os.path.join(modulepath, '../output/final.db.2') 80 | jsondb_house = os.path.join(modulepath, '../output/zufang.house.json') 81 | simdb = os.path.join(modulepath, '../output/sim.db') 82 | if os.path.exists(jsondb_house): 83 | backup(jsondb_house) 84 | os.remove(jsondb_house) 85 | gen_house(finaldb_cut, DB(jsondb_house), simdb) 86 | 87 | if __name__ == '__main__': 88 | starttime = datetime.datetime.now() 89 | run = sys.argv[0] 90 | modulepath = os.path.dirname(run) 91 | main( 92 | modulepath=modulepath 93 | ) 94 | endtime = datetime.datetime.now() 95 | Logger.info('done! %lds' % (endtime-starttime).seconds) 96 | -------------------------------------------------------------------------------- /data-aggregator/bin/make_final.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | readonly contentdb=$1 4 | readonly housedb=$2 5 | readonly linkdb=$3 6 | readonly dst=$4 7 | readonly finaldb="$5" 8 | 9 | awk -F "\t" ' 10 | ARGIND==1{ 11 | hashurl=$1; 12 | title=$2; 13 | content=$3; 14 | jushi=$4; 15 | shouji=$5; 16 | zujin=$6; 17 | dizhi=$7; 18 | ditie=$8; 19 | house_arr1[hashurl]=jushi"\t"shouji"\t"zujin"\t"dizhi"\t"ditie; 20 | } 21 | ARGIND==2{ 22 | hashurl=$1; 23 | url=$2; 24 | crawl_time=$3; 25 | source=$4; 26 | ext=$5; 27 | house_arr2[hashurl]=url"\t"crawl_time"\t"source"\t"ext; 28 | } 29 | ARGIND==3{ 30 | line=$0; 31 | hashurl=$1; 32 | title=$2; 33 | author=$3; 34 | images=$4; 35 | links=$5; 36 | text=$6; 37 | pub_time=$7; 38 | # hashurl title author images links text pub_time 39 | # 1 2 3 4 5 6 7 40 | # jushi shouji zujin dizhi ditie url crawl_time source ext 41 | # 8 9 10 11 12 13 14 15 16 42 | if(!(hashurl in house_arr1)) 43 | { 44 | next; 45 | } 46 | if(!(hashurl in house_arr2)) 47 | { 48 | next; 49 | } 50 | print line"\t"house_arr1[hashurl]"\t"house_arr2[hashurl]; 51 | } 52 | ' "$dst/$housedb" "$dst/$linkdb" "$dst/$contentdb" > "$finaldb" 53 | -------------------------------------------------------------------------------- /data-aggregator/bin/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | thisdir=${0%/*} 4 | contentdb="content.db" 5 | contentdb_src="$thisdir/../../content-extractor/output" 6 | housedb="house.db" 7 | housedb_src="$thisdir/../../house-refinery/output" 8 | linkdb="link.db" 9 | linkdb_src="$thisdir/../../link-spider/output" 10 | dst="$thisdir/../data" 11 | 12 | function pull_housedb() 13 | { 14 | local housedb=$1 15 | local housedb_src=$2 16 | local housedb_dst=$3 17 | rm -f "$housedb_dst/$housedb" 18 | ln -s "$housedb_src/$housedb" "$housedb_dst" 19 | } 20 | 21 | function pull_contentdb() 22 | { 23 | local contentdb=$1 24 | local contentdb_src=$2 25 | local contentdb_dst=$3 26 | rm -f "$contentdb_dst/$contentdb" 27 | ln -s "$contentdb_src/$contentdb" "$contentdb_dst" 28 | } 29 | 30 | function pull_linkdb() 31 | { 32 | local linkdb=$1 33 | local linkdb_src=$2 34 | local linkdb_dst=$3 35 | rm -f "$linkdb_dst/$linkdb" 36 | ln -s "$linkdb_src/$linkdb" "$linkdb_dst" 37 | } 38 | 39 | pull_contentdb "$contentdb" "$contentdb_src" "$dst" 40 | pull_housedb "$housedb" "$housedb_src" "$dst" 41 | pull_linkdb "$linkdb" "$linkdb_src" "$dst" 42 | 43 | ## Make final 44 | finaldb="$thisdir/../output/final.db" 45 | bash "$thisdir/make_final.sh" "$contentdb" "$housedb" "$linkdb" "$dst" "$finaldb" 46 | 47 | ## Filter data 48 | month_limit=2 49 | bash "$thisdir/filter_data.sh" "$finaldb" "$month_limit" 50 | 51 | ## Filter img 52 | imglist="$thisdir/../output/imglist" 53 | imglist0="$imglist.0" 54 | imglist_diff="$imglist.diff" 55 | imgdir="$thisdir/../output/imgdir" 56 | touch "$imglist0" 57 | mv "$imglist" "$imglist0" 58 | bash "$thisdir/filter_img.sh" "$finaldb.$month_limit" "$imglist" 59 | echo "Find diff: `diff "$imglist" "$imglist0" | wc -l`" 60 | diff "$imglist" "$imglist0" | awk '{if($2){print $2;}}' > "$imglist_diff" 61 | 62 | ## Wget img 63 | bash "$thisdir/wget_img.sh" "$imglist_diff" "$imgdir" 64 | 65 | ## Generate sim.db 66 | python -u "$thisdir/sim.py" >> "$thisdir/../log/log" 2>&1 67 | 68 | ## Generate json file(sent to server) 69 | python -u "$thisdir/main.py" >> "$thisdir/../log/log" 2>&1 70 | -------------------------------------------------------------------------------- /data-aggregator/bin/sim.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | import time 5 | import os 6 | import datetime 7 | import json 8 | import sys 9 | 10 | import simhash 11 | from simhash import Simhash, SimhashIndex 12 | 13 | from Utils import Logger, DB, backup 14 | 15 | def sim_merge(finaldb_cut, simdb): 16 | d = {} 17 | index_list = [] 18 | hashurl2sim = {} 19 | max_distance = 10 20 | with open(finaldb_cut, 'r') as f: 21 | for line in f: 22 | if not line: 23 | break 24 | # hashurl title author images links text pub_time 25 | # 1 2 3 4 5 6 7 26 | # jushi shouji zujin dizhi ditie url crawl_time source ext 27 | # 8 9 10 11 12 13 14 15 16 28 | array = line.rstrip('\r\n').split('\t') 29 | hashurl=array[0] #string,key 30 | title=array[1] #string 31 | text=array[5] #string 32 | pub_time=array[6] #string 33 | url=array[12] #string 34 | 35 | s = Simhash((title+text).decode('utf-8')) 36 | d.update({ 37 | hashurl:(title, url, pub_time) 38 | }) 39 | sim = Simhash((title+text).decode('utf-8')) 40 | index_list.append((hashurl, sim)) 41 | hashurl2sim.update({hashurl:sim}) 42 | 43 | index = SimhashIndex(index_list, k=max_distance) 44 | merged = {} 45 | while d: 46 | hashurl, (title, url, pub_time) = d.popitem() 47 | merged[hashurl] = (title, url, pub_time) 48 | sim_list = index.get_near_dups(hashurl2sim[hashurl]) 49 | buf_list = [] 50 | for h in sim_list: 51 | if h != hashurl: 52 | if d.has_key(h): 53 | title2, url2, pub_time2 = d.pop(h) 54 | merged[h] = (title2, url2, pub_time2) 55 | else: 56 | title2, url2, pub_time2 = merged[h] 57 | else: 58 | title2, url2, pub_time2 = title, url, pub_time 59 | buf_list.append((h, title2, url2, pub_time2)) 60 | if len(buf_list) > 1: 61 | buf_list = sorted(buf_list, key=lambda i:i[3], reverse=True) 62 | simdb.insert('\t'.join( 63 | [buf_list[0][0], json.dumps(buf_list[1:])] 64 | )) 65 | 66 | def main(**args): 67 | modulepath = args['modulepath'] 68 | finaldb_cut = os.path.join(modulepath, '../output/final.db.2') 69 | simdb = os.path.join(modulepath, '../output/sim.db') 70 | if os.path.exists(simdb): 71 | backup(simdb) 72 | os.remove(simdb) 73 | sim_merge(finaldb_cut, DB(simdb)) 74 | 75 | if __name__ == '__main__': 76 | starttime = datetime.datetime.now() 77 | run = sys.argv[0] 78 | modulepath = os.path.dirname(run) 79 | main( 80 | modulepath=modulepath 81 | ) 82 | endtime = datetime.datetime.now() 83 | Logger.info('done! %lds' % (endtime-starttime).seconds) 84 | -------------------------------------------------------------------------------- /data-aggregator/bin/wget_img.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | readonly imglist="$1" 4 | readonly imgdir="$2" 5 | readonly agents=(\ 6 | "Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11"\ 7 | "Opera/9.25 (Windows NT 5.1; U; en)"\ 8 | "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"\ 9 | "Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.5 (like Gecko) (Kubuntu)"\ 10 | "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.12) Gecko/20070731 Ubuntu/dapper-security Firefox/1.5.0.12"\ 11 | "Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 GNUTLS/1.2.9"\ 12 | "Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.7 (KHTML, like Gecko) Ubuntu/11.04 Chromium/16.0.912.77 Chrome/16.0.912.77 Safari/535.7"\ 13 | "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:10.0) Gecko/20100101 Firefox/10.0"\ 14 | ) 15 | arr_len="${#agents[@]}" 16 | 17 | mkdir -p "$imgdir" 18 | while read url 19 | do 20 | imgname=`echo -n "$url" | cut -d "/" -f 8` 21 | imgname="$imgdir/$imgname" 22 | if [ -s "$imgname" ] 23 | then 24 | echo "skip $url" 25 | continue 26 | fi 27 | 28 | ((index=RANDOM%arr_len)) 29 | ua=${agents[$index]} 30 | wget --user-agent="$ua" --no-check-certificate --tries=5 --quiet --timeout=20 -O "$imgname" "$url" 31 | if [ ! -f "$imgname" ] 32 | then 33 | echo "wget failed $url" 34 | continue 35 | fi 36 | 37 | sleep 0.5 38 | done < "$imglist" 39 | -------------------------------------------------------------------------------- /dict/common.dict: -------------------------------------------------------------------------------- 1 | 一 2 | 在 3 | 者 4 | 找 5 | 和 6 | 与 7 | 招 8 | 中 9 | 有 10 | 张 11 | 章 12 | 阅 13 | 月 14 | 元 15 | 要 16 | 用 17 | 号 18 | 好 19 | 页 20 | 站 21 | 之 22 | 学 23 | 听 24 | 无 25 | 县 26 | 我 27 | 网 28 | 王 29 | 万 30 | 物 31 | 天 32 | 下 33 | 为 34 | 图 35 | 数 36 | 三 37 | 售 38 | 室 39 | 日 40 | 搜 41 | 上 42 | 商 43 | 书 44 | 人 45 | 市 46 | 是 47 | 水 48 | 省 49 | 型 50 | 新 51 | 小 52 | 区 53 | 名 54 | 能 55 | 买 56 | 器 57 | 年 58 | 了 59 | 男 60 | 吗 61 | 你 62 | 路 63 | 来 64 | 城 65 | 称 66 | 车 67 | 厂 68 | 产 69 | 查 70 | 不 71 | 部 72 | 管 73 | 购 74 | 卷 75 | 尽 76 | 叫 77 | 金 78 | 价 79 | 家 80 | 及 81 | 房 82 | 二 83 | 多 84 | 读 85 | 第 86 | 店 87 | 点 88 | 的 89 | 到 90 | 吧 91 | 版 92 | 爱 93 | 啊 94 | 最 95 | 租 96 | 机 97 | 会 98 | 花 99 | 表 100 | 比 101 | 报 102 | 宝 103 | 库 104 | 看 105 | 高 106 | 个 107 | 歌 108 | 大 109 | 超 110 | 没 111 | 建 112 | 试 113 | 期 114 | 对 115 | 想 116 | 业 117 | 社 118 | 等 119 | 品 120 | 美 121 | 起 122 | 四 123 | 谁 124 | 集 125 | 后 126 | 本 127 | 将 128 | 做 129 | 局 130 | 就 131 | 这 132 | 分 133 | 成 134 | 李 135 | 发 136 | 女 137 | 六 138 | 已 139 | 乐 140 | 师 141 | 给 142 | 都 143 | 全 144 | 厅 145 | 总 146 | 您 147 | 五 148 | 节 149 | 去 150 | 播 151 | 文 152 | 快 153 | 让 154 | 类 155 | 酒 156 | 性 157 | 款 158 | 梦 159 | 说 160 | 被 161 | 真 162 | 请 163 | 股 164 | 楼 165 | 测 166 | 药 167 | 才 168 | 生 169 | 游 170 | 种 171 | 易 172 | 里 173 | 装 174 | 修 175 | 打 176 | 化 177 | 也 178 | 办 179 | 心 180 | 出 181 | 园 182 | 通 183 | 该 184 | 线 185 | 题 186 | 间 187 | 风 188 | 字 189 | 料 190 | 进 191 | 国 192 | 道 193 | 周 194 | 过 195 | 长 196 | 帮 197 | 镇 198 | 式 199 | 地 200 | 可 201 | 海 202 | 开 203 | 龙 204 | 飞 205 | 评 206 | 次 207 | 红 208 | 山 209 | 钱 210 | 很 211 | 法 212 | 华 213 | 非 214 | 刘 215 | 陈 216 | 门 217 | 米 218 | 黑 219 | 台 220 | 街 221 | 卡 222 | 包 223 | 事 224 | 安 225 | 馆 226 | 七 227 | 原 228 | 堂 229 | 行 230 | 老 231 | 双 232 | 员 233 | 得 234 | 子 235 | 病 236 | 眼 237 | 写 238 | 片 239 | 八 240 | 加 241 | 手 242 | 绿 243 | 友 244 | 色 245 | 白 246 | 级 247 | 从 248 | 漫 249 | 西 250 | 时 251 | 北 252 | 问 253 | 回 254 | 所 255 | 清 256 | 那 257 | 带 258 | 智 259 | 电 260 | 两 261 | 钢 262 | 送 263 | 强 264 | 港 265 | 又 266 | 村 267 | 选 268 | 情 269 | 九 270 | 油 271 | 单 272 | 十 273 | 正 274 | 豆 275 | 诗 276 | 样 277 | 黄 278 | 魔 279 | 防 280 | 泡 281 | 百 282 | 前 283 | 变 284 | 再 285 | 鞋 286 | 几 287 | 转 288 | 儿 289 | 套 290 | 神 291 | 林 292 | 见 293 | 篇 294 | 还 295 | 话 296 | 班 297 | 求 298 | 们 299 | 客 300 | 更 301 | 力 302 | 吃 303 | 治 304 | 雨 305 | 各 306 | 帖 307 | 火 308 | 记 309 | 院 310 | 关 311 | 近 312 | 玩 313 | 处 314 | 常 315 | 把 316 | 传 317 | 景 318 | 唱 319 | 窝 320 | 内 321 | 同 322 | 流 323 | 于 324 | 卫 325 | 课 326 | 自 327 | 画 328 | 只 329 | 铁 330 | 拍 331 | 岁 332 | 呢 333 | 东 334 | 或 335 | 杨 336 | 条 337 | 论 338 | 换 339 | 首 340 | 鱼 341 | 舞 342 | 系 343 | 球 344 | 译 345 | 收 346 | 代 347 | 狗 348 | 当 349 | 猫 350 | 星 351 | 破 352 | 场 353 | 卖 354 | 团 355 | 达 356 | 雪 357 | 他 358 | 笑 359 | 马 360 | 明 361 | 词 362 | 圈 363 | 票 364 | 牛 365 | 改 366 | 受 367 | 界 368 | 丁 369 | 低 370 | 以 371 | 谈 372 | 秀 373 | 太 374 | 信 375 | 贴 376 | 届 377 | 岛 378 | 证 379 | 头 380 | 博 381 | 光 382 | 主 383 | 像 384 | 如 385 | 走 386 | 口 387 | 亿 388 | 养 389 | 若 390 | 云 391 | 方 392 | 板 393 | 录 394 | 件 395 | 组 396 | 猪 397 | 剧 398 | 至 399 | 群 400 | 何 401 | 盘 402 | 座 403 | 向 404 | 死 405 | 秋 406 | 工 407 | 军 408 | 入 409 | 战 410 | 外 411 | 未 412 | 队 413 | 灯 414 | 科 415 | 兽 416 | 源 417 | 石 418 | 制 419 | 声 420 | 礼 421 | 酷 422 | 衣 423 | 热 424 | 获 425 | 仙 426 | 命 427 | 度 428 | 教 429 | 货 430 | 越 431 | 欧 432 | 印 433 | 着 434 | 击 435 | 南 436 | 乡 437 | 粉 438 | 短 439 | 桥 440 | 吴 441 | 量 442 | 解 443 | 屋 444 | 德 445 | 算 446 | 树 447 | 蓝 448 | 茶 449 | 假 450 | 语 451 | 啦 452 | 旧 453 | 叶 454 | 赛 455 | 配 456 | 订 457 | 增 458 | 古 459 | 半 460 | 别 461 | 曾 462 | 她 463 | 考 464 | 河 465 | 缘 466 | 虫 467 | 而 468 | 平 469 | 句 470 | 曲 471 | 罗 472 | 杯 473 | 史 474 | 洗 475 | 特 476 | 夜 477 | 血 478 | 哪 479 | 奖 480 | 仪 481 | 位 482 | 深 483 | 江 484 | 银 485 | 演 486 | 居 487 | 祝 488 | 副 489 | 由 490 | 香 491 | 服 492 | 费 493 | 但 494 | 玉 495 | 千 496 | 率 497 | 农 498 | 重 499 | 疯 500 | 纸 501 | 应 502 | 唐 503 | 难 504 | 今 505 | 创 506 | 影 507 | 连 508 | 定 509 | 设 510 | 经 511 | 作 512 | 供 513 | 精 514 | 少 515 | 虎 516 | 错 517 | 赵 518 | 交 519 | 段 520 | 紫 521 | 思 522 | 木 523 | 初 524 | 族 525 | 住 526 | 营 527 | 谢 528 | 共 529 | 急 530 | 纯 531 | 含 532 | 青 533 | 放 534 | 康 535 | 杀 536 | 钻 537 | 知 538 | 观 539 | 按 540 | 先 541 | 动 542 | 父 543 | 志 544 | 肉 545 | 面 546 | 跟 547 | 刚 548 | 宋 549 | 例 550 | 静 551 | 剂 552 | 促 553 | 春 554 | 胡 555 | 满 556 | 良 557 | 登 558 | 并 559 | 极 560 | 孙 561 | 鸟 562 | 编 563 | 此 564 | 湖 565 | 英 566 | 体 567 | 喜 568 | 任 569 | 利 570 | 令 571 | 彩 572 | 剑 573 | 现 574 | 苏 575 | 每 576 | 毛 577 | 佳 578 | 刀 579 | 阿 580 | 干 581 | 留 582 | 鬼 583 | 谷 584 | 降 585 | 户 586 | 感 587 | 宇 588 | 联 589 | 拉 590 | 徐 591 | 需 592 | 牌 593 | 广 594 | 反 595 | 顶 596 | 因 597 | 克 598 | 合 599 | 职 600 | 望 601 | 微 602 | 熊 603 | 迷 604 | 草 605 | 空 606 | 富 607 | 展 608 | 夏 609 | 些 610 | 母 611 | 穿 612 | 寻 613 | 忧 614 | 糖 615 | 相 616 | 仍 617 | 士 618 | 却 619 | 意 620 | 亚 621 | 公 622 | 仅 623 | 涨 624 | 么 625 | 布 626 | 盒 627 | 远 628 | 烟 629 | 旺 630 | 尚 631 | 其 632 | 底 633 | 必 634 | 域 635 | 约 636 | 升 637 | 随 638 | 气 639 | 峰 640 | 榜 641 | 案 642 | 铺 643 | 立 644 | 灰 645 | 田 646 | 顺 647 | 层 648 | 边 649 | 笔 650 | 指 651 | 盛 652 | 朱 653 | 取 654 | 皮 655 | 灵 656 | 册 657 | 京 658 | 减 659 | 欲 660 | 炎 661 | 武 662 | 权 663 | 亮 664 | 齐 665 | 派 666 | 雷 667 | 采 668 | 调 669 | 呀 670 | 码 671 | 落 672 | 爆 673 | 福 674 | 零 675 | 除 676 | 刻 677 | 余 678 | 直 679 | 言 680 | 宁 681 | 菜 682 | 久 683 | 胶 684 | 架 685 | 追 686 | 汇 687 | 医 688 | 使 689 | 著 690 | 领 691 | 冷 692 | 恋 693 | 奥 694 | 钟 695 | 艺 696 | 伤 697 | 梁 698 | 封 699 | 翻 700 | 币 701 | 照 702 | 项 703 | 箱 704 | 戏 705 | 傻 706 | 兴 707 | 足 708 | 矿 709 | 世 710 | 轮 711 | 离 712 | 冲 713 | 州 714 | 它 715 | 输 716 | 乱 717 | 免 718 | 步 719 | 党 720 | 孔 721 | 船 722 | 味 723 | 奇 724 | 波 725 | 赚 726 | 兵 727 | 音 728 | 征 729 | 形 730 | 民 731 | 基 732 | 存 733 | 亦 734 | 郑 735 | 素 736 | 宫 737 | 块 738 | 折 739 | 丝 740 | 泪 741 | 优 742 | 痛 743 | 松 744 | 轻 745 | 镜 746 | 讲 747 | 饭 748 | 保 749 | 雅 750 | 软 751 | 税 752 | 许 753 | 煤 754 | 狼 755 | 补 756 | 份 757 | 准 758 | 琴 759 | 哈 760 | 角 761 | 结 762 | 计 763 | 端 764 | 左 765 | 附 766 | 宏 767 | 早 768 | 症 769 | 汤 770 | 身 771 | 圣 772 | 另 773 | 拿 774 | 官 775 | 聚 776 | 救 777 | 活 778 | 哭 779 | 汉 780 | 致 781 | 占 782 | 缺 783 | 某 784 | 冰 785 | 哥 786 | 众 787 | 则 788 | 圆 789 | 值 790 | 完 791 | 弄 792 | 即 793 | 丰 794 | 载 795 | 遭 796 | 斗 797 | 懂 798 | 庄 799 | 专 800 | 液 801 | 沙 802 | 校 803 | 兰 804 | 梅 805 | 炒 806 | 接 807 | 返 808 | 羊 809 | 提 810 | 委 811 | 亲 812 | 妻 813 | 露 814 | 诚 815 | 果 816 | 君 817 | 环 818 | 遇 819 | 喝 820 | 烧 821 | 毒 822 | 温 823 | 塔 824 | 且 825 | 怕 826 | 链 827 | 藏 828 | 夹 829 | 鸡 830 | 坐 831 | 狂 832 | 阳 833 | 跳 834 | 胜 835 | 鲁 836 | 差 837 | 质 838 | 妖 839 | 推 840 | 土 841 | 细 842 | 宽 843 | 袋 844 | 窗 845 | 企 846 | 均 847 | 既 848 | 抗 849 | 忘 850 | 属 851 | 贵 852 | 坏 853 | 待 854 | 珠 855 | 停 856 | 寺 857 | 帅 858 | 睡 859 | 脑 860 | 朝 861 | 独 862 | 掉 863 | 助 864 | 寒 865 | 退 866 | 旁 867 | 丽 868 | 挂 869 | 较 870 | 便 871 | 压 872 | 往 873 | 闻 874 | 荣 875 | 视 876 | 趣 877 | 怪 878 | 归 879 | 废 880 | 川 881 | 造 882 | 腿 883 | 投 884 | 排 885 | 具 886 | 跌 887 | 靠 888 | 湾 889 | 删 890 | 姐 891 | 冬 892 | 倒 893 | 根 894 | 格 895 | 盖 896 | 异 897 | 宜 898 | 兔 899 | 食 900 | 莫 901 | 永 902 | 晚 903 | 伟 904 | 维 905 | 术 906 | 鼠 907 | 脸 908 | 吨 909 | 杜 910 | 抓 911 | 右 912 | 支 913 | 愿 914 | 洋 915 | 理 916 | 够 917 | 脚 918 | 兼 919 | 倍 920 | 显 921 | 刷 922 | 续 923 | 签 924 | 批 925 | 据 926 | 锦 927 | 嘉 928 | 季 929 | 甲 930 | 凡 931 | 滴 932 | 爸 933 | 敢 934 | 赴 935 | 讯 936 | 墙 937 | 柳 938 | 潮 939 | 驾 940 | 吉 941 | 范 942 | 状 943 | 运 944 | 赢 945 | 斯 946 | 散 947 | 枪 948 | 慢 949 | 绝 950 | 标 951 | 背 952 | 偶 953 | 杰 954 | 盐 955 | 末 956 | 莲 957 | 故 958 | 稿 959 | 搞 960 | 益 961 | 裙 962 | 抢 963 | 奶 964 | 程 965 | 呈 966 | 断 967 | 薄 968 | 扣 969 | 晓 970 | 乳 971 | 实 972 | 庆 973 | 跑 974 | 陆 975 | 帽 976 | 健 977 | 嫁 978 | 驻 979 | 赠 980 | 依 981 | 纹 982 | 容 983 | 粮 984 | 骨 985 | 弹 986 | 棒 987 | 床 988 | 整 989 | 吸 990 | 闪 991 | 须 992 | 敏 993 | 宗 994 | 俊 995 | 寸 996 | 戴 997 | 尾 998 | 欣 999 | 切 1000 | 灭 1001 | 皆 1002 | 姜 1003 | 辉 1004 | 止 1005 | 野 1006 | 燕 1007 | 涛 1008 | 锁 1009 | 似 1010 | 忙 1011 | 乘 1012 | 复 1013 | 厚 1014 | 疼 1015 | 限 1016 | 象 1017 | 速 1018 | 碎 1019 | 仔 1020 | 注 1021 | 洪 1022 | 迎 1023 | 牙 1024 | 沈 1025 | 爬 1026 | 练 1027 | 畅 1028 | 净 1029 | 仿 1030 | 针 1031 | 硬 1032 | 善 1033 | 然 1034 | 瓶 1035 | 池 1036 | 插 1037 | 借 1038 | 敌 1039 | 淡 1040 | 逼 1041 | 吹 1042 | 核 1043 | 义 1044 | 列 1045 | 目 1046 | 财 1047 | 键 1048 | 虽 1049 | 序 1050 | 临 1051 | 额 1052 | 恩 1053 | 洞 1054 | 丹 1055 | 败 1056 | 暗 1057 | 付 1058 | 引 1059 | 终 1060 | 瘦 1061 | 酸 1062 | 秒 1063 | 隆 1064 | 菌 1065 | 芳 1066 | 耳 1067 | 混 1068 | 浅 1069 | 累 1070 | 飘 1071 | 抽 1072 | 惊 1073 | 禁 1074 | 简 1075 | 佛 1076 | 丢 1077 | 罪 1078 | 裤 1079 | 颜 1080 | 扬 1081 | 舒 1082 | 施 1083 | 胸 1084 | 麦 1085 | 妈 1086 | 陪 1087 | 凉 1088 | 距 1089 | 柏 1090 | 般 1091 | 抱 1092 | 负 1093 | 司 1094 | 券 1095 | 念 1096 | 沟 1097 | 功 1098 | 竟 1099 | 董 1100 | 巴 1101 | 醉 1102 | 护 1103 | 苦 1104 | 答 1105 | 挑 1106 | 失 1107 | 肩 1108 | 夫 1109 | 蛋 1110 | 嘴 1111 | 跨 1112 | 阵 1113 | 持 1114 | 顾 1115 | 肺 1116 | 鼻 1117 | 肝 1118 | 害 1119 | 溪 1120 | 密 1121 | 妹 1122 | 亩 1123 | 巨 1124 | 争 1125 | 恨 1126 | 爽 1127 | 巧 1128 | 劲 1129 | 幅 1130 | 番 1131 | 舍 1132 | 牵 1133 | 侧 1134 | 桌 1135 | 咱 1136 | 脱 1137 | 湿 1138 | 普 1139 | 浪 1140 | 档 1141 | 粗 1142 | 严 1143 | 透 1144 | 挺 1145 | 晒 1146 | 耐 1147 | 阁 1148 | 竹 1149 | 疑 1150 | 腰 1151 | 祥 1152 | 守 1153 | 骑 1154 | 偏 1155 | 蒙 1156 | 肥 1157 | 府 1158 | 阴 1159 | 岩 1160 | 汪 1161 | 吐 1162 | 胃 1163 | 审 1164 | 适 1165 | 凭 1166 | 觉 1167 | 恶 1168 | 框 1169 | 赞 1170 | 勇 1171 | 偷 1172 | 弱 1173 | 稍 1174 | 识 1175 | 剩 1176 | 效 1177 | 闹 1178 | 孟 1179 | 摆 1180 | 撞 1181 | 滑 1182 | 蜜 1183 | 骂 1184 | 暖 1185 | 肌 1186 | 暴 1187 | 甘 1188 | 椅 1189 | 惹 1190 | 私 1191 | 犯 1192 | 斑 1193 | 摇 1194 | 甜 1195 | 忍 1196 | 尸 1197 | 胖 1198 | 辆 1199 | 猜 1200 | 继 1201 | 寄 1202 | 挡 1203 | 伴 1204 | 婚 1205 | 控 1206 | 告 1207 | 晕 1208 | 添 1209 | 稳 1210 | 托 1211 | 替 1212 | 休 1213 | 猛 1214 | 炉 1215 | 备 1216 | 颗 1217 | 误 1218 | 甚 1219 | 穷 1220 | 膜 1221 | 踩 1222 | 患 1223 | 遍 1224 | 汗 1225 | 潜 1226 | 擦 1227 | 紧 1228 | 堆 1229 | 煮 1230 | 威 1231 | 响 1232 | 喂 1233 | 烦 1234 | 胆 1235 | 咬 1236 | 挖 1237 | 逃 1238 | 肠 1239 | 顿 1240 | 振 1241 | 认 1242 | 摸 1243 | 冒 1244 | 举 1245 | 闭 1246 | 肯 1247 | 棵 1248 | 搭 1249 | 醒 1250 | 骗 1251 | 烂 1252 | 呆 1253 | 责 1254 | 拖 1255 | 索 1256 | 怎 1257 | 臭 1258 | 狠 1259 | 喊 1260 | 围 1261 | 熟 1262 | 漏 1263 | 俩 1264 | 搬 1265 | 横 1266 | 填 1267 | 吓 1268 | 泉 1269 | 埋 1270 | 抖 1271 | 赶 1272 | 躲 1273 | 忠 1274 | 蛮 1275 | 懒 1276 | 栏 1277 | 丑 1278 | 冠 1279 | 饿 1280 | 唉 1281 | 柔 1282 | 担 1283 | 握 1284 | 隔 1285 | 躺 1286 | 乃 1287 | 妨 1288 | 慧 1289 | 堪 1290 | 铜 1291 | 摄 1292 | 弃 1293 | 撑 1294 | 洁 1295 | 剪 1296 | 贺 1297 | 判 1298 | 滚 1299 | 略 1300 | 艳 1301 | 坊 1302 | 震 1303 | 氏 1304 | 瑞 1305 | 赖 1306 | 操 1307 | 锋 1308 | 唇 1309 | 杂 1310 | 墓 1311 | 恒 1312 | 消 1313 | 锅 1314 | 霜 1315 | 碰 1316 | 庙 1317 | 触 1318 | 鲜 1319 | 讨 1320 | 润 1321 | 岗 1322 | 邮 1323 | 栋 1324 | 童 1325 | 什 1326 | 黎 1327 | 郎 1328 | 惨 1329 | 饮 1330 | 贤 1331 | 抛 1332 | 罚 1333 | 踢 1334 | 困 1335 | 漆 1336 | 盯 1337 | 洲 1338 | 餐 1339 | 挤 1340 | 扔 1341 | 怀 1342 | 夺 1343 | 肾 1344 | 置 1345 | 欠 1346 | 辣 1347 | 劝 1348 | 虚 1349 | 挥 1350 | 祖 1351 | 姨 1352 | 晴 1353 | 凶 1354 | 己 1355 | 犬 1356 | 嫩 1357 | 捉 1358 | 惠 1359 | 贝 1360 | 叹 1361 | 泰 1362 | 倾 1363 | 臂 1364 | 议 1365 | 岭 1366 | 晨 1367 | 晶 1368 | 陶 1369 | 亭 1370 | 势 1371 | 斤 1372 | 符 1373 | 羽 1374 | 隐 1375 | 残 1376 | 浓 1377 | 享 1378 | 蛇 1379 | 沉 1380 | 盗 1381 | 迅 1382 | 予 1383 | 柜 1384 | 渐 1385 | 绑 1386 | 拔 1387 | 幸 1388 | 斜 1389 | 塘 1390 | 磨 1391 | 呼 1392 | 塞 1393 | 闲 1394 | 染 1395 | 欢 1396 | 氧 1397 | 申 1398 | 划 1399 | 魂 1400 | 贼 1401 | 麻 1402 | 否 1403 | 浩 1404 | 拼 1405 | 悦 1406 | 辛 1407 | 敲 1408 | 劫 1409 | 绕 1410 | 模 1411 | 赌 1412 | 刺 1413 | 雄 1414 | 裂 1415 | 邪 1416 | 访 1417 | 奔 1418 | 政 1419 | 撒 1420 | 葛 1421 | 姓 1422 | 妙 1423 | 毁 1424 | 芝 1425 | 攻 1426 | 眉 1427 | 仁 1428 | 泥 1429 | 怒 1430 | 腹 1431 | 始 1432 | 敬 1433 | 凤 1434 | 伞 1435 | 烤 1436 | 纳 1437 | 愁 1438 | 尊 1439 | 昌 1440 | 豪 1441 | 详 1442 | 乔 1443 | 串 1444 | 预 1445 | 闷 1446 | 旋 1447 | 踏 1448 | 娘 1449 | 涂 1450 | 尘 1451 | 焦 1452 | 捧 1453 | 导 1454 | 乎 1455 | 移 1456 | 庭 1457 | 楚 1458 | 研 1459 | 堡 1460 | 堵 1461 | 皇 1462 | 尿 1463 | 吵 1464 | 柱 1465 | 扑 1466 | 帝 1467 | 虾 1468 | 井 1469 | 训 1470 | 坡 1471 | 碗 1472 | 赏 1473 | 脖 1474 | 津 1475 | 缝 1476 | 险 1477 | 淘 1478 | 射 1479 | 扶 1480 | 诸 1481 | 孕 1482 | 锐 1483 | 趁 1484 | 谋 1485 | 饱 1486 | 筒 1487 | 摔 1488 | 粒 1489 | 互 1490 | 姿 1491 | 扯 1492 | 惜 1493 | 探 1494 | 勤 1495 | 刮 1496 | 雕 1497 | 笨 1498 | 桂 1499 | 毕 1500 | 育 1501 | 承 1502 | 垫 1503 | 炸 1504 | 鸭 1505 | 凝 1506 | 衫 1507 | 扎 1508 | 旗 1509 | 帘 1510 | 戒 1511 | 纪 1512 | 拆 1513 | 嫌 1514 | 迟 1515 | 凯 1516 | 巷 1517 | 损 1518 | 仓 1519 | 技 1520 | 萍 1521 | 颈 1522 | 扇 1523 | 棋 1524 | 境 1525 | 棉 1526 | 疤 1527 | 泽 1528 | 森 1529 | 启 1530 | 墨 1531 | 充 1532 | 悲 1533 | 织 1534 | 沿 1535 | 携 1536 | 杆 1537 | 肿 1538 | 桶 1539 | 泛 1540 | 拥 1541 | 牧 1542 | 暂 1543 | 谱 1544 | 猴 1545 | 途 1546 | 扫 1547 | 喷 1548 | 闯 1549 | 唯 1550 | 俗 1551 | 弯 1552 | 咳 1553 | 掌 1554 | 确 1555 | 奉 1556 | 怨 1557 | 勿 1558 | 盆 1559 | 愈 1560 | 痕 1561 | 雾 1562 | 涌 1563 | 固 1564 | 壁 1565 | 凑 1566 | 抹 1567 | 催 1568 | 橡 1569 | 拨 1570 | 尖 1571 | 坑 1572 | 粘 1573 | 舌 1574 | 迁 1575 | 积 1576 | 吼 1577 | 融 1578 | 砖 1579 | 耍 1580 | 捡 1581 | 睁 1582 | 脏 1583 | 抵 1584 | 悔 1585 | 尝 1586 | 渡 1587 | 拳 1588 | 苗 1589 | 壮 1590 | 资 1591 | 桃 1592 | 赔 1593 | 缴 1594 | 鹰 1595 | 滩 1596 | 席 1597 | 盼 1598 | 饰 1599 | 槽 1600 | 晋 1601 | 翼 1602 | 烫 1603 | 抬 1604 | 捏 1605 | 霸 1606 | 阀 1607 | 朵 1608 | 衰 1609 | 慎 1610 | 甩 1611 | 乖 1612 | 勾 1613 | 帐 1614 | 皱 1615 | 执 1616 | 汁 1617 | 坛 1618 | 幕 1619 | 献 1620 | 赤 1621 | 爷 1622 | 虹 1623 | 腾 1624 | 鼓 1625 | 吊 1626 | 陷 1627 | 鸣 1628 | 规 1629 | 拜 1630 | 割 1631 | 幻 1632 | 参 1633 | 摘 1634 | 浮 1635 | 伸 1636 | 灌 1637 | 检 1638 | 妇 1639 | 御 1640 | 谜 1641 | 尺 1642 | 趴 1643 | 霞 1644 | 渔 1645 | 厨 1646 | 扁 1647 | 眠 1648 | 尤 1649 | 务 1650 | 邀 1651 | 逢 1652 | 痒 1653 | 尼 1654 | 瓦 1655 | 忆 1656 | 盈 1657 | 龟 1658 | 壳 1659 | 叠 1660 | 傲 1661 | 韵 1662 | 缠 1663 | 娇 1664 | 拒 1665 | 枝 1666 | 翁 1667 | 俱 1668 | 粥 1669 | 朗 1670 | 逆 1671 | 咸 1672 | 束 1673 | 冻 1674 | 碑 1675 | 株 1676 | 屑 1677 | 伯 1678 | 宅 1679 | 歪 1680 | 息 1681 | 砍 1682 | 袭 1683 | 稀 1684 | 傅 1685 | 铸 1686 | 臣 1687 | 亏 1688 | 挣 1689 | 逐 1690 | 沾 1691 | 丸 1692 | 伏 1693 | 避 1694 | 债 1695 | 蝶 1696 | 纱 1697 | 碧 1698 | 饼 1699 | 珍 1700 | 材 1701 | 籍 1702 | 遮 1703 | 孤 1704 | 截 1705 | 介 1706 | 绣 1707 | 耻 1708 | 济 1709 | 缩 1710 | 肚 1711 | 航 1712 | 延 1713 | 孝 1714 | 哲 1715 | 徒 1716 | 谦 1717 | 储 1718 | 屯 1719 | 辜 1720 | 拾 1721 | 茅 1722 | 捆 1723 | 毅 1724 | 刑 1725 | 协 1726 | 历 1727 | 柴 1728 | 验 1729 | 悟 1730 | 乙 1731 | 劳 1732 | 幼 1733 | 屈 1734 | 瞧 1735 | 殿 1736 | 犹 1737 | 激 1738 | 逗 1739 | 岸 1740 | 涉 1741 | 洒 1742 | 鹿 1743 | 递 1744 | 销 1745 | 亡 1746 | 坚 1747 | 翠 1748 | 斩 1749 | 桑 1750 | 铃 1751 | 忽 1752 | 蜂 1753 | 恐 1754 | 椒 1755 | 灾 1756 | 殖 1757 | 浴 1758 | 突 1759 | 佩 1760 | 旅 1761 | 决 1762 | 捐 1763 | 寿 1764 | 愧 1765 | 驴 1766 | 偿 1767 | 抄 1768 | 酱 1769 | 窄 1770 | 希 1771 | 跪 1772 | 纵 1773 | 昨 1774 | 吞 1775 | 罐 1776 | 警 1777 | 滨 1778 | 坝 1779 | 纲 1780 | 映 1781 | 畏 1782 | 炮 1783 | 盾 1784 | 蹲 1785 | 祸 1786 | 宣 1787 | 挨 1788 | 矮 1789 | 寨 1790 | 卧 1791 | 悬 1792 | 脉 1793 | 乏 1794 | 喘 1795 | 喉 1796 | 盟 1797 | 阶 1798 | 监 1799 | 扮 1800 | 缓 1801 | 膏 1802 | 押 1803 | 惯 1804 | 疾 1805 | 刊 1806 | 垂 1807 | 摊 1808 | 炼 1809 | 箭 1810 | 卸 1811 | 帆 1812 | 遥 1813 | 伪 1814 | 律 1815 | 脂 1816 | 缸 1817 | 哄 1818 | 贪 1819 | 秘 1820 | 晃 1821 | 罩 1822 | 贱 1823 | 辞 1824 | 蒸 1825 | 薪 1826 | 腔 1827 | 兄 1828 | 盲 1829 | 忌 1830 | 锡 1831 | 饶 1832 | 廉 1833 | 荐 1834 | 钓 1835 | 伍 1836 | 态 1837 | 勒 1838 | 茂 1839 | 捷 1840 | 耀 1841 | 示 1842 | 迈 1843 | 弟 1844 | 筑 1845 | 壶 1846 | 乌 1847 | 扭 1848 | 舟 1849 | 荷 1850 | 趟 1851 | 瞎 1852 | 绳 1853 | 蒜 1854 | 狮 1855 | 培 1856 | 诉 1857 | 驰 1858 | 统 1859 | 菊 1860 | 煎 1861 | 弦 1862 | 溜 1863 | 龄 1864 | 辰 1865 | 窃 1866 | 宴 1867 | 袜 1868 | 袖 1869 | 典 1870 | 裹 1871 | 径 1872 | 灶 1873 | 宿 1874 | 爹 1875 | 仰 1876 | 娃 1877 | 弓 1878 | 婆 1879 | 钉 1880 | 岂 1881 | 瓜 1882 | 习 1883 | 塑 1884 | 朋 1885 | 繁 1886 | 醋 1887 | 狐 1888 | 屿 1889 | 轰 1890 | 罢 1891 | 耗 1892 | 兆 1893 | 驱 1894 | 陵 1895 | 辈 1896 | 扩 1897 | 烈 1898 | 芬 1899 | 淋 1900 | 捞 1901 | 燃 1902 | 荡 1903 | 爪 1904 | 磁 1905 | 枕 1906 | 址 1907 | 仗 1908 | 穴 1909 | 渣 1910 | 禾 1911 | 浙 1912 | 遗 1913 | 摩 1914 | 卜 1915 | 夸 1916 | 释 1917 | 揉 1918 | 撤 1919 | 揪 1920 | 筋 1921 | 概 1922 | 咽 1923 | 荒 1924 | 跃 1925 | 贸 1926 | 裁 1927 | 疏 1928 | 竞 1929 | 阻 1930 | 辨 1931 | 葱 1932 | 掩 1933 | 午 1934 | 朴 1935 | 揭 1936 | 柄 1937 | 咏 1938 | 裕 1939 | 默 1940 | 拌 1941 | 慌 1942 | 辅 1943 | 贷 1944 | 植 1945 | 际 1946 | 崖 1947 | 泄 1948 | 萌 1949 | 策 1950 | 择 1951 | 危 1952 | 辽 1953 | 齿 1954 | 澡 1955 | 掏 1956 | 叔 1957 | 碍 1958 | 脆 1959 | 胀 1960 | 劈 1961 | 慕 1962 | 喇 1963 | 钩 1964 | 鸽 1965 | 丛 1966 | 授 1967 | 奏 1968 | 候 1969 | 闸 1970 | 逝 1971 | 梨 1972 | 绘 1973 | 衡 1974 | 妥 1975 | 邻 1976 | 仇 1977 | 覆 1978 | 撕 1979 | 蓄 1980 | 铅 1981 | 芒 1982 | 窜 1983 | 雁 1984 | 泻 1985 | 屡 1986 | 坟 1987 | 膝 1988 | 彼 1989 | 娱 1990 | 糟 1991 | 誓 1992 | 拦 1993 | 孩 1994 | 竖 1995 | 拐 1996 | 惧 1997 | 哀 1998 | 糊 1999 | 栽 2000 | 夕 2001 | 贞 2002 | 披 2003 | 漂 2004 | 浆 2005 | 抚 2006 | 挽 2007 | 昆 2008 | 彻 2009 | 搏 2010 | 召 2011 | 葬 2012 | 炭 2013 | 芹 2014 | 攀 2015 | 奴 2016 | 阔 2017 | 笼 2018 | 聪 2019 | 厌 2020 | 颂 2021 | 搂 2022 | 睛 2023 | 浇 2024 | 谨 2025 | 慈 2026 | 昏 2027 | 葵 2028 | 浸 2029 | 蹦 2030 | 倚 2031 | 汽 2032 | 舰 2033 | 眨 2034 | 塌 2035 | 羞 2036 | 苍 2037 | 悠 2038 | 蚊 2039 | 棚 2040 | 匹 2041 | 眯 2042 | 巩 2043 | 伐 2044 | 丘 2045 | 丙 2046 | 述 2047 | 辱 2048 | 杏 2049 | 况 2050 | 樱 2051 | 掀 2052 | 侍 2053 | 翅 2054 | 扛 2055 | 聋 2056 | 撇 2057 | 昂 2058 | 宾 2059 | 梯 2060 | 鉴 2061 | 唤 2062 | 窑 2063 | 篮 2064 | 叉 2065 | 轨 2066 | 猎 2067 | 泊 2068 | 枯 2069 | 宪 2070 | 歇 2071 | 牢 2072 | 棍 2073 | 枣 2074 | 呜 2075 | 巾 2076 | 蠢 2077 | 勺 2078 | 泼 2079 | 崇 2080 | 拣 2081 | 迹 2082 | 堤 2083 | 丈 2084 | 暮 2085 | 鹅 2086 | 屠 2087 | 穗 2088 | 渠 2089 | 筹 2090 | 捕 2091 | 伙 2092 | 宰 2093 | 坦 2094 | 究 2095 | 削 2096 | 刃 2097 | 察 2098 | 锤 2099 | 巡 2100 | 析 2101 | 扰 2102 | 趋 2103 | 恰 2104 | 卵 2105 | 颤 2106 | 舱 2107 | 鞠 2108 | 禽 2109 | 囊 2110 | 贩 2111 | 污 2112 | 峡 2113 | 艘 2114 | 姑 2115 | 桐 2116 | 搅 2117 | 瓣 2118 | 衬 2119 | 芽 2120 | 扒 2121 | 诊 2122 | 央 2123 | 剥 2124 | 恭 2125 | 嚼 2126 | 腐 2127 | 丧 2128 | 冤 2129 | 脾 2130 | 构 2131 | 搁 2132 | 怜 2133 | 倦 2134 | 革 2135 | 芦 2136 | 厉 2137 | 滤 2138 | 肤 2139 | 贫 2140 | 笋 2141 | 踪 2142 | 笛 2143 | 轿 2144 | 廊 2145 | 欺 2146 | 燥 2147 | 侨 2148 | 霉 2149 | 纤 2150 | 疆 2151 | 挪 2152 | 迫 2153 | 绒 2154 | 叮 2155 | 骆 2156 | 盏 2157 | 梳 2158 | 叼 2159 | 誉 2160 | 匀 2161 | 滋 2162 | 纺 2163 | 颠 2164 | 貌 2165 | 援 2166 | 奸 2167 | 棕 2168 | 违 2169 | 辟 2170 | 狱 2171 | 酿 2172 | 络 2173 | 绍 2174 | 羡 2175 | 粪 2176 | 袍 2177 | 蓬 2178 | 役 2179 | 厘 2180 | 叙 2181 | 拢 2182 | 侵 2183 | 弊 2184 | 耕 2185 | 愚 2186 | 辩 2187 | 傍 2188 | 诱 2189 | 痰 2190 | 茎 2191 | 畜 2192 | 陕 2193 | 循 2194 | 绵 2195 | 焰 2196 | 寇 2197 | 渗 2198 | 灿 2199 | 戚 2200 | 砌 2201 | 泳 2202 | 瞒 2203 | 允 2204 | 雀 2205 | 旦 2206 | 掠 2207 | 斥 2208 | 贯 2209 | 钞 2210 | 估 2211 | 铲 2212 | 悄 2213 | 惑 2214 | 渴 2215 | 冶 2216 | 虑 2217 | 逮 2218 | 厦 2219 | 贡 2220 | 馅 2221 | 蜡 2222 | 嫂 2223 | 筛 2224 | 艇 2225 | 哑 2226 | 谊 2227 | 疗 2228 | 僵 2229 | 嚷 2230 | 陡 2231 | 蛙 2232 | 滥 2233 | 稠 2234 | 稻 2235 | 橘 2236 | 杠 2237 | 俯 2238 | 沫 2239 | 冈 2240 | 挠 2241 | 览 2242 | 纷 2243 | 沃 2244 | 遣 2245 | 栗 2246 | 锈 2247 | 督 2248 | 匪 2249 | 绪 2250 | 脊 2251 | 悉 2252 | 倡 2253 | 淹 2254 | 遵 2255 | 艰 2256 | 鞭 2257 | 匠 2258 | 旬 2259 | 酬 2260 | 螺 2261 | 凳 2262 | 熔 2263 | 姻 2264 | 劣 2265 | 剖 2266 | 毯 2267 | 疲 2268 | 榆 2269 | 绞 2270 | 蚀 2271 | 斧 2272 | 驶 2273 | 妄 2274 | 哨 2275 | 恼 2276 | 衔 2277 | 蚕 2278 | 絮 2279 | 旱 2280 | 茧 2281 | 殊 2282 | 浊 2283 | 垮 2284 | 庸 2285 | 旨 2286 | 钳 2287 | 毫 2288 | 匙 2289 | 仆 2290 | 烛 2291 | 骄 2292 | 垒 2293 | 询 2294 | 拘 2295 | 魄 2296 | 槐 2297 | 障 2298 | 哗 2299 | 糕 2300 | 秤 2301 | 浑 2302 | 描 2303 | 宵 2304 | 剃 2305 | 驳 2306 | 奋 2307 | 皂 2308 | 肃 2309 | 锯 2310 | 矩 2311 | 腊 2312 | 慰 2313 | 绩 2314 | 掘 2315 | 躁 2316 | 矛 2317 | 谎 2318 | 沸 2319 | 昼 2320 | 胞 2321 | 肆 2322 | 纽 2323 | 萝 2324 | 洽 2325 | 诵 2326 | 胁 2327 | 竭 2328 | 茫 2329 | 械 2330 | 括 2331 | 馋 2332 | 熄 2333 | 筐 2334 | 轧 2335 | 腥 2336 | 暑 2337 | 漠 2338 | 旷 2339 | 拴 2340 | 毙 2341 | 饥 2342 | 炕 2343 | 蚁 2344 | 励 2345 | 榨 2346 | 捎 2347 | 煌 2348 | 婶 2349 | 骤 2350 | 犁 2351 | 躬 2352 | 裳 2353 | 愤 2354 | 努 2355 | 诞 2356 | 疮 2357 | 桨 2358 | 锻 2359 | 葡 2360 | 歉 2361 | 驼 2362 | 膨 2363 | 乞 2364 | 摧 2365 | 蔽 2366 | 谣 2367 | 隙 2368 | 玻 2369 | 纠 2370 | 伶 2371 | 蕉 2372 | 锄 2373 | 绢 2374 | 睬 2375 | 蛾 2376 | 虏 2377 | 茄 2378 | 顷 2379 | 挎 2380 | 谅 2381 | 狭 2382 | 薯 2383 | 蹄 2384 | 厕 2385 | 梢 2386 | 恳 2387 | 勉 2388 | 舅 2389 | 郊 2390 | 倘 2391 | 竿 2392 | 肢 2393 | 敞 2394 | 辫 2395 | 俭 2396 | 啄 2397 | 垦 2398 | 筝 2399 | 烘 2400 | 鸦 2401 | 疫 2402 | 叛 2403 | 骡 2404 | 侦 2405 | 乒 2406 | 惩 2407 | 侄 2408 | 缎 2409 | 顽 2410 | 岔 2411 | 佣 2412 | 怖 2413 | 歼 2414 | 绸 2415 | 狸 2416 | 讽 2417 | 锣 2418 | 秃 2419 | 隶 2420 | 苹 2421 | 悼 2422 | 蔬 2423 | 宙 2424 | 袄 2425 | 愉 2426 | 嘱 2427 | 饲 2428 | 怠 2429 | 蝇 2430 | 垄 2431 | 滔 2432 | 鹊 2433 | 俘 2434 | 璃 2435 | 钥 2436 | 践 2437 | 秧 2438 | 柿 2439 | 恢 2440 | 崭 2441 | 壤 2442 | 慨 2443 | 糠 2444 | 膀 2445 | 秩 2446 | 朽 2447 | 鄙 2448 | 涝 2449 | 粱 2450 | 稼 2451 | 嗓 2452 | 蹈 2453 | 膛 2454 | 箩 2455 | 碌 2456 | 蛛 2457 | 榴 2458 | 镰 2459 | 叨 2460 | 贿 2461 | 惭 2462 | 饺 2463 | 牲 2464 | 惰 2465 | 耽 2466 | 僻 2467 | 殃 2468 | 秆 2469 | 炊 2470 | 膊 2471 | 僚 2472 | 础 2473 | 乓 2474 | 姥 2475 | 狡 2476 | 侮 2477 | 锹 2478 | 嗽 2479 | 匆 2480 | 蔑 2481 | 帜 2482 | 惕 2483 | 垃 2484 | 晌 2485 | 菠 2486 | 蝴 2487 | 蜓 2488 | 雹 2489 | 圾 2490 | 蚂 2491 | 溉 2492 | 馒 2493 | 牺 2494 | 萄 2495 | 蜘 2496 | 吩 2497 | 咐 2498 | 猾 2499 | 胳 2500 | 蜻 2501 | -------------------------------------------------------------------------------- /house-refinery/README: -------------------------------------------------------------------------------- 1 | house.db 2 | hashurl title content jushi(居室类型) shouji(手机号) zujin(租金) dizhi(地址标签) 3 | -------------------------------------------------------------------------------- /house-refinery/bin/HouseRefinery.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | from TextParser import TextParser 5 | from Utils import Logger, DB 6 | 7 | class HouseRefinery(object): 8 | 9 | def __init__(self, **args): 10 | self._db = args['db'] 11 | 12 | def parse(self, **args): 13 | hashurl = args['hashurl'] 14 | title = args['title'] 15 | text = args['text'] 16 | ret = TextParser.parse(title+' '+text) 17 | if ret.has_key('error'): 18 | Logger.info(hashurl+' '+ret['error']) 19 | return 20 | record = '\t'.join([ 21 | hashurl, 22 | title, 23 | text, 24 | ret['jushi'], 25 | ret['shouji'], 26 | ret['zujin'], 27 | ret['dizhi'], 28 | ret['ditie'], 29 | ]) 30 | self._db.insert(record) 31 | -------------------------------------------------------------------------------- /house-refinery/bin/TextParser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | from Utils import Link, Logger 5 | import re 6 | import jieba 7 | import jieba.posseg as pseg 8 | 9 | jieba.load_userdict('dict/baidu.dict') 10 | jieba.load_userdict('dict/sougou.dict') 11 | 12 | class TextParser: 13 | 14 | @staticmethod 15 | def _jushi(text): 16 | def _norm(word): 17 | word_map = { 18 | u'1':u'一', u'2':u'二', u'3':u'三', u'4':u'四', u'5':u'五',\ 19 | u'6':u'六', u'7':u'七', u'8':u'八', u'9':u'九', u'0':u'零',\ 20 | u'两':u'二' 21 | } 22 | if word_map.has_key(word): 23 | return word_map[word] 24 | else: 25 | return word 26 | 27 | core = ur'([0-9一二两三四五六七八九])室([0-9一二两三四五六七八九])厅|([0-9一二两三四五六七八九])居[室]{0,1}' 28 | p = re.compile(core, re.UNICODE) 29 | matches = p.findall(text) 30 | jushi = {} 31 | for i, j, k in matches: 32 | i = _norm(i) 33 | j = _norm(j) 34 | k = _norm(k) 35 | if i and j: 36 | if jushi.has_key(i): 37 | if j not in jushi[i]: 38 | jushi[i].add(j) 39 | else: 40 | jushi[i] = set(j) 41 | if k: 42 | if not jushi.has_key(k): 43 | jushi[k] = set() 44 | ret = [] 45 | for i in jushi: 46 | if jushi[i]: 47 | for j in jushi[i]: 48 | ret.append(u'%s室%s厅' % (i, j)) 49 | else: 50 | ret.append(u'%s居室' % (i)) 51 | if ret: return u','.join(ret) 52 | else: return u'' 53 | 54 | @staticmethod 55 | def _shouji(text): 56 | core = ur'(1[3|4|5|8]\d{9})|(1[3|4|5|8]\d[\- ]\d{3}[\- ]\d{5})|(1[3|4|5|8]\d[\- ]\d{4}[\- ]\d{4})' 57 | p = re.compile(core, re.UNICODE) 58 | matches = p.findall(text) 59 | ret = set() 60 | for i in matches: 61 | for j in i: 62 | if j: 63 | ret.add(re.sub(ur'\D', u'', j)) 64 | if ret: return u','.join(ret) 65 | else: return u'' 66 | 67 | @staticmethod 68 | def _zujin(text): 69 | core = ur'(\d{3,4}[元]?[/每]?月)|((价格|租金)\D?\d{3,4}\D)' 70 | p = re.compile(core, re.UNICODE) 71 | matches = p.findall(text) 72 | ret = set() 73 | for i in matches: 74 | for j in i: 75 | j = re.sub(ur'\D', u'', j) 76 | if j: 77 | ret.add(int(j)) 78 | if len(ret) == 1: 79 | return u'%d元' % (ret.pop()) 80 | elif len(ret) > 1: 81 | return u'%d-%d元' % (min(ret), max(ret)) 82 | else: return u'' 83 | 84 | @staticmethod 85 | def _dizhi(text): 86 | def find_place(text): 87 | ret = set() 88 | segs = pseg.cut(text) 89 | for i, seg in enumerate(segs): 90 | if seg.flag in ['bd', 'sg']: 91 | ret.add(seg.word) 92 | return ret 93 | 94 | """ 95 | core = ur'[0-9a-zA-Z\u4E00-\u9FA5]{2,}' 96 | p = re.compile(core, re.UNICODE) 97 | matches = p.findall(text) 98 | text = u''.join([ i for i in matches if len(i)>3]) 99 | ret = set() 100 | for i in matches: 101 | if i: 102 | place = find_place(i) 103 | if place: 104 | ret.add(place) 105 | return u'||'.join([ i for i in ret]) 106 | """ 107 | return u','.join(find_place(text)) 108 | 109 | @staticmethod 110 | def _ditie(text): 111 | def _norm(word): 112 | word_map = { 113 | u'一':u'1', u'二':u'2', u'三':u'3', u'四':u'4', u'五':u'5',\ 114 | u'六':u'6', u'七':u'7', u'八':u'8', u'九':u'9', u'十':u'10',\ 115 | u'十一':u'11', u'十二':u'12', u'十三':u'13', u'十四':u'14', u'十五':u'15', 116 | } 117 | if word_map.has_key(word): 118 | return word_map[word] 119 | else: 120 | return word 121 | core = ur'(1|2|4|5|6|8|9|10|13|14|15|一|二|四|五|六|八|九|十|十三|十四|十五|十五)号线|(八通|昌平|亦庄|房山|机场)线' 122 | p = re.compile(core, re.UNICODE) 123 | matches = p.findall(text) 124 | ret = set() 125 | for i, k in matches: 126 | if i: ret.add(u'%s号线' % _norm(i)) 127 | if k: ret.add(u'%s线' % k) 128 | if ret: return u','.join(ret) 129 | else: return u'' 130 | 131 | @staticmethod 132 | def parse(text): 133 | unicode_string = text.decode('utf-8') 134 | return { 135 | 'jushi': TextParser._jushi(unicode_string).encode('utf-8'), 136 | 'shouji': TextParser._shouji(unicode_string).encode('utf-8'), 137 | 'zujin': TextParser._zujin(unicode_string).encode('utf-8'), 138 | 'dizhi': TextParser._dizhi(unicode_string).encode('utf-8'), 139 | 'ditie': TextParser._ditie(unicode_string).encode('utf-8'), 140 | } 141 | 142 | @staticmethod 143 | def _parse_shuimu(text): 144 | pass 145 | 146 | @staticmethod 147 | def _parse_ganji(text): 148 | pass 149 | 150 | @staticmethod 151 | def _parse_soufun(text): 152 | pass 153 | 154 | @staticmethod 155 | def _parse_58(text): 156 | pass 157 | -------------------------------------------------------------------------------- /house-refinery/bin/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | import time 5 | import os 6 | import datetime 7 | import sys 8 | 9 | from HouseRefinery import HouseRefinery 10 | from Utils import Logger, DB, backup 11 | 12 | def diff_task(taskfile, donefile): 13 | alltask = [] 14 | donetask = [] 15 | with open(taskfile, 'r') as f: 16 | for line in f: 17 | if not line: 18 | break 19 | hashurl = line.split('\t')[0] 20 | alltask.append(hashurl) 21 | with open(donefile, 'r') as f: 22 | for line in f: 23 | if not line: 24 | break 25 | hashurl = line.split('\t')[0] 26 | donetask.append(hashurl) 27 | 28 | exclude = set(donetask) 29 | return [task for task in alltask if task not in exclude] 30 | 31 | def process(contentdb, housedb): 32 | hr = HouseRefinery( 33 | db=DB(housedb) 34 | ) 35 | hashurls = diff_task(contentdb, housedb) 36 | with open(contentdb, 'r') as f: 37 | for line in f: 38 | if not line: 39 | break 40 | hashurl, title, _, _, _, text = line.split('\t')[:6] 41 | if hashurl in hashurls: 42 | hr.parse( 43 | hashurl=hashurl, 44 | title=title, 45 | text=text 46 | ) 47 | hashurls.remove(hashurl) 48 | 49 | def main(**args): 50 | modulepath = args['modulepath'] 51 | contentdb = os.path.join(modulepath, '../data/content.db') 52 | housedb = os.path.join(modulepath, '../output/house.db') 53 | backup(housedb) 54 | process(contentdb, housedb) 55 | 56 | if __name__ == '__main__': 57 | starttime = datetime.datetime.now() 58 | run = sys.argv[0] 59 | modulepath = os.path.dirname(run) 60 | main( 61 | modulepath=modulepath 62 | ) 63 | endtime = datetime.datetime.now() 64 | Logger.info('done! %lds' % (endtime-starttime).seconds) 65 | -------------------------------------------------------------------------------- /house-refinery/bin/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | thisdir=${0%/*} 4 | contentdb="content.db" 5 | contentdb_src="$thisdir/../../content-extractor/output" 6 | contentdb_dst="$thisdir/../data" 7 | 8 | function pull_contentdb() 9 | { 10 | local contentdb=$1 11 | local contentdb_src=$2 12 | local contentdb_dst=$3 13 | rm -f "$contentdb_dst/$contentdb" 14 | ln -s "$contentdb_src/$contentdb" "$contentdb_dst" 15 | } 16 | pull_contentdb "$contentdb" "$contentdb_src" "$contentdb_dst" 17 | 18 | python -u "$thisdir/main.py" >> "$thisdir/../log/log" 2>&1 19 | -------------------------------------------------------------------------------- /libs/Browser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | import mechanize 5 | import cookielib 6 | import urllib2 7 | import time 8 | import random 9 | 10 | from Utils import Logger 11 | 12 | class NoHistory(object): 13 | def add(self, *a, **k):pass 14 | def clear(self):pass 15 | 16 | class Interval: 17 | _interval = 0 18 | @staticmethod 19 | def val(): 20 | Interval._interval += 1 21 | if Interval._interval*Interval._interval > 1000: 22 | return 1000 23 | else: 24 | return Interval._interval*Interval._interval 25 | @staticmethod 26 | def reset(): 27 | Interval._interval = 0 28 | 29 | class Agent: 30 | _agents = [ 31 | 'Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11', 32 | 'Opera/9.25 (Windows NT 5.1; U; en)', 33 | 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)', 34 | 'Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.5 (like Gecko) (Kubuntu)', 35 | 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.12) Gecko/20070731 Ubuntu/dapper-security Firefox/1.5.0.12', 36 | 'Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 GNUTLS/1.2.9', 37 | 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.7 (KHTML, like Gecko) Ubuntu/11.04 Chromium/16.0.912.77 Chrome/16.0.912.77 Safari/535.7', 38 | 'Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:10.0) Gecko/20100101 Firefox/10.0' 39 | ] 40 | @staticmethod 41 | def random_agent(): 42 | return random.choice(Agent._agents) 43 | 44 | class Browser(object): 45 | _interval = 1 46 | def __init__(self, **args): 47 | if args.has_key('history') and args['history']: 48 | self.br = mechanize.Browser() 49 | else: 50 | self.br = mechanize.Browser(history=NoHistory()) 51 | self.br.set_handle_equiv(True) 52 | self.br.set_handle_gzip(True) 53 | self.br.set_handle_redirect(True) 54 | self.br.set_handle_referer(True) 55 | self.br.set_handle_robots(False) 56 | self.br.set_handle_refresh(mechanize._http.HTTPRefreshProcessor(), max_time=1) 57 | self.br.set_cookiejar(mechanize.CookieJar()) 58 | self.br.addheaders = [( 59 | 'User-Agent', 60 | #'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko/2008071615 Fedora/3.0.1-1.fc9 Firefox/3.0.1' 61 | Agent.random_agent() 62 | )] 63 | 64 | def open(self, url, delay=0.1): 65 | response = None 66 | try: 67 | response = self.br.open(url, timeout=20.0) 68 | except urllib2.HTTPError, e: 69 | while e.code != 404: 70 | interval = Interval.val() 71 | time.sleep(interval) 72 | Logger.info('sleep %ds error %d %s' % (interval, e.code, url)) 73 | try: 74 | response = self.br.open(url, timeout=20.0) 75 | Logger.info('skip 403 ' + url) 76 | break 77 | except urllib2.HTTPError, e: 78 | if e.code != 404: 79 | continue 80 | except: 81 | Logger.info('cannot handle browser error!') 82 | break 83 | Interval.reset() 84 | except: 85 | pass 86 | time.sleep(delay) 87 | if response: 88 | page = response.read() 89 | else: 90 | page = '' 91 | return page 92 | 93 | def close(self): 94 | return self.br.close() 95 | 96 | def follow_link(self, **args): 97 | text = args['text'] 98 | return self.br.follow_link(text=text) 99 | -------------------------------------------------------------------------------- /libs/Utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | import time 5 | import json 6 | import re 7 | import shutil 8 | import os 9 | 10 | def backup(filename): 11 | newfile = filename+'.bak' 12 | if os.path.exists(filename): 13 | if os.path.isfile(filename): 14 | try: os.remove(newfile) 15 | except: pass 16 | shutil.copy(filename, newfile) 17 | elif os.path.isdir(filename): 18 | try: shutil.rmtree(newfile) 19 | except: pass 20 | shutil.copytree(filename, newfile) 21 | 22 | class Logger: 23 | 24 | @staticmethod 25 | def warn(msg): 26 | status = 'WARN' 27 | Logger.printf(msg, status) 28 | 29 | @staticmethod 30 | def error(msg): 31 | status = 'ERROR' 32 | Logger.printf(msg, status) 33 | 34 | @staticmethod 35 | def info(msg): 36 | status = 'INFO' 37 | Logger.printf(msg, status) 38 | 39 | @staticmethod 40 | def printf(msg, status): 41 | print '[%s] %s %s' % ( 42 | status, 43 | time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())), 44 | msg 45 | ) 46 | 47 | class Link(object): 48 | hashurl = '' 49 | url = '' 50 | reply_time = 0 51 | 52 | def __init__(self, **args): 53 | self.hashurl = args['hashurl'] 54 | self.url = args['url'] 55 | self.reply_time = args['reply_time'] 56 | 57 | def __str__(self): 58 | return '\t'.join([ 59 | self.hashurl, 60 | self.url, 61 | str(self.reply_time) 62 | ]) 63 | 64 | 65 | class DB(object): 66 | _dbstream = None 67 | _NEWLINE = '\n' 68 | 69 | def __init__(self, dbname): 70 | if type(dbname) == str: 71 | self.dbname = dbname 72 | self._dbstream = open(dbname, 'a', 0) 73 | elif type(dbname) == DB: 74 | db = dbname 75 | self.dbname = db.dbname 76 | self._dbstream = open(db.dbname, 'r') 77 | 78 | def __del__(self): 79 | self._dbstream.close() 80 | 81 | def insert(self, record): 82 | self._dbstream.write(record+self._NEWLINE) 83 | 84 | def fetchone(self): 85 | line = self._dbstream.readline() 86 | return re.sub(self._NEWLINE+'$', '', line) 87 | 88 | class Meta(object): 89 | _meta = {} 90 | 91 | def __init__(self, metaname): 92 | self.metaname = metaname 93 | self.load(metaname) 94 | 95 | def load(self, metaname): 96 | try: 97 | with open(metaname, 'r') as f: 98 | data = json.loads(f.read()) 99 | if type(data) == dict and len(data) > 0: 100 | self._meta = data 101 | return True 102 | except: 103 | return False 104 | 105 | def set(self, *argv): 106 | self._meta[':'.join(argv[:-1])] = argv[-1] 107 | 108 | def get(self, *argv): 109 | key = ':'.join(argv) 110 | try: 111 | return self._meta[key] 112 | except: 113 | return None 114 | 115 | def has(self, *argv): 116 | key = ':'.join(argv) 117 | if self._meta.has_key(key): 118 | return True 119 | else: 120 | return False 121 | 122 | def write(self, metaname=None): 123 | if not metaname: 124 | metaname = self.metaname 125 | with open(metaname, 'w', 0) as f: 126 | f.write(json.dumps(self._meta)) 127 | -------------------------------------------------------------------------------- /libs/Utils.py2: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | import time 5 | import json 6 | import sys 7 | import fcntl 8 | import re 9 | 10 | class Logger: 11 | 12 | @staticmethod 13 | def warn(msg): 14 | status = 'WARN' 15 | Logger.printf(msg, status) 16 | 17 | @staticmethod 18 | def error(msg): 19 | status = 'ERROR' 20 | Logger.printf(msg, status) 21 | 22 | @staticmethod 23 | def info(msg): 24 | status = 'INFO' 25 | Logger.printf(msg, status) 26 | 27 | @staticmethod 28 | def printf(msg, status): 29 | print '[%s] %s %s' % ( 30 | status, 31 | time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())), 32 | msg 33 | ) 34 | sys.stdout.flush() 35 | 36 | class Link(object): 37 | hashurl = '' 38 | url = '' 39 | reply_time = 0 40 | 41 | def __init__(self, **args): 42 | self.hashurl = args['hashurl'] 43 | self.url = args['url'] 44 | self.reply_time = args['reply_time'] 45 | 46 | def __str__(self): 47 | return '\t'.join([ 48 | self.hashurl, 49 | self.url, 50 | str(self.reply_time) 51 | ]) 52 | 53 | 54 | class DB(object): 55 | _dbstream = None 56 | _NEWLINE = '\n' 57 | _BUFMAX = 500 58 | 59 | def __init__(self, dbname): 60 | if type(dbname) == str: 61 | self.dbname = dbname 62 | self._dbstream = open(dbname, 'a') 63 | self._count = 0 64 | self._buf = '' 65 | elif type(dbname) == DB: 66 | db = dbname 67 | self.dbname = db.dbname 68 | self._dbstream = open(db.dbname, 'r') 69 | self._count = 0 70 | self._buf = '' 71 | 72 | def __del__(self): 73 | if self._buf: 74 | self._dbstream.write(self._buf) 75 | self._buf = '' 76 | self._dbstream.close() 77 | 78 | def insert(self, record): 79 | self._count += 1 80 | self._buf += record + self._NEWLINE 81 | if self._count >= self._BUFMAX: 82 | self._dbstream.write(self._buf) 83 | self._buf = '' 84 | self._count = 0 85 | #self._dbstream.write(record+self._NEWLINE) 86 | 87 | def fetchone(self): 88 | line = self._dbstream.readline() 89 | return re.sub(self._NEWLINE+'$', '', line) 90 | 91 | class Meta(object): 92 | _meta = {} 93 | 94 | def __init__(self, metaname): 95 | self.metaname = metaname 96 | self.load(metaname) 97 | 98 | def load(self, metaname): 99 | try: 100 | with open(metaname, 'r') as f: 101 | data = json.loads(f.read()) 102 | if type(data) == dict and len(data) > 0: 103 | self._meta = data 104 | return True 105 | except: 106 | return False 107 | 108 | def set(self, *argv): 109 | self._meta[':'.join(argv[:-1])] = argv[-1] 110 | 111 | def get(self, *argv): 112 | key = ':'.join(argv) 113 | try: 114 | return self._meta[key] 115 | except: 116 | return None 117 | 118 | def has(self, *argv): 119 | key = ':'.join(argv) 120 | if self._meta.has_key(key): 121 | return True 122 | else: 123 | return False 124 | 125 | def write(self, metaname=None): 126 | if not metaname: 127 | metaname = self.metaname 128 | with open(metaname, 'w') as f: 129 | f.write(json.dumps(self._meta)) 130 | -------------------------------------------------------------------------------- /libs/random_extraction.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | number=$1 4 | filename=$2 5 | 6 | count=`wc -l "$filename" | awk '{print $1;}'` 7 | rand_array=() 8 | 9 | function in_array() 10 | { 11 | local rand_array=$1 12 | local rand=$2 13 | local i 14 | for i in ${rand_array[@]} 15 | do 16 | if [ "$i" = "$rand" ] 17 | then 18 | return 0 19 | fi 20 | done 21 | return 1 22 | } 23 | # Generate random line number(count from 1). 24 | for i in $(seq "$number") 25 | do 26 | let rand=$RANDOM*$RANDOM%$count+1 27 | tmp_array=`echo ${rand_array[@]}` 28 | while true 29 | do 30 | in_array "$tmp_array" "$rand" 31 | if [ $? = 0 ] 32 | then 33 | let rand=$RANDOM*$RANDOM%$count+1 34 | else 35 | break 36 | fi 37 | done 38 | #echo "add " $i $rand 39 | rand_array[$i]=$rand 40 | done 41 | 42 | # Extract lines. 43 | string=`echo ${rand_array[@]} | awk ' 44 | { 45 | gsub(" ", "p;", $0); 46 | print $0"p"; 47 | } 48 | '` 49 | eval "sed -n" "'${string}'" "$filename" 50 | -------------------------------------------------------------------------------- /libs/testawk.sh: -------------------------------------------------------------------------------- 1 | : 2 | # testawk - test awk features (stv, 5/98) 3 | # $Id: testawk.sh,v 1.5 2003/01/30 03:02:29 heiner Exp $ 4 | # 5 | # usage: testawk [awk_path ...] 6 | # 7 | # Thanks to 8 | # Raffaele Guide Della Valle 9 | # Ian P. Springer 10 | # for feature tests and bug reports 11 | 12 | email="heiner.steven@shelldorado.com" 13 | PN=`basename "$0"` # Program name 14 | LOGFILE=/tmp/testawk.log # Default log file 15 | 16 | if [ $# -gt 0 ] 17 | then 18 | AWKList="$@" 19 | else 20 | AWKList=" " 21 | for path in `echo "$PATH" | sed 's|^:|./ |;s|:$| ./|;s|:| |g'` 22 | do 23 | for awk in "$path"/*awk* 24 | do 25 | case "$awk" in 26 | *.exe|*.com|*.bat) ;; # DOS/Windows 27 | *.*) continue ;; # ignore "script.awk" 28 | esac 29 | [ X"$awk" = X"$path/*awk*" ] && continue # no awk found 30 | [ X"`basename \"$awk\"`" = X"$PN" ] && continue 31 | if [ -x "$awk" ] 32 | then 33 | case "$AWKList" in 34 | *" $awk "*) ;; # awk already in list 35 | *) AWKList="${AWKList}$awk " ;; 36 | esac 37 | fi 38 | done 39 | done 40 | [ -z "$AWKList" ] && 41 | exec echo "no AWK found - please specify a path on the command line" 42 | fi 43 | 44 | Script="${TMPDIR:=/tmp}/scr$$.awk" # Temporary AWK script 45 | Input="$TMPDIR/in$$" # AWK input (a newline) 46 | Output="$TMPDIR/out$$" # Resulting output 47 | Result="$TMPDIR/res$$" 48 | 49 | # Automatically remove temporary files at program termination 50 | trap 'rm -f "$Script" "$Input" "$Output" "$Result" >/dev/null 2>&1' 0 51 | trap "exit 2" 1 2 3 13 15 52 | 53 | uname -a > "$Result" 54 | 55 | for AWK in $AWKList 56 | do 57 | Status="$AWK -v option" 58 | 59 | # 60 | # check for "-v" command line argument 61 | # 62 | 63 | echo > "$Input" 64 | cat <<-! > "$Script" 65 | { 66 | print variable 67 | } 68 | ! 69 | 70 | echo >&2 "-v option" 71 | if TZ= "$AWK" -v variable=A -f "$Script" "$Input" > "$Output" 2>/dev/null 72 | then 73 | if [ -s "$Output" ] && [ X`cat "$Output"` = X"A" ] 74 | then 75 | Status="$Status +" 76 | echo >&2 " $AWK +" 77 | else 78 | Status="$Status -" 79 | echo >&2 " $AWK -" 80 | fi 81 | else 82 | Status="$Status -" 83 | echo >&2 " $AWK -" 84 | fi 85 | 86 | echo "$Status" >> "$Result" 87 | 88 | # 89 | # Check if variable=value pairs work on the command line 90 | # 91 | 92 | Status="$AWK var=val pairs" 93 | echo >&2 "variable=value arguments" 94 | 95 | if TZ= "$AWK" -f "$Script" variable=A "$Input" > "$Output" 2>/dev/null 96 | then 97 | if [ -s "$Output" ] && [ X`cat "$Output"` = X"A" ] 98 | then 99 | Status="$Status +" 100 | echo >&2 " $AWK +" 101 | else 102 | Status="$Status -" 103 | echo >&2 " $AWK -" 104 | fi 105 | else 106 | Status="$Status -" 107 | echo >&2 " $AWK -" 108 | fi 109 | echo "$Status" >> "$Result" 110 | 111 | # 112 | # User defined functions 113 | # 114 | 115 | Status="$AWK functions" 116 | echo >&2 "functions" 117 | 118 | echo 1 > "$Input" 119 | cat <<-! > "$Script" 120 | function mydouble(x) { return 2*x } 121 | { 122 | print mydouble(\$0) 123 | } 124 | ! 125 | 126 | 127 | if TZ= "$AWK" -f "$Script" "$Input" > "$Output" 2>/dev/null 128 | then 129 | if [ -s "$Output" ] && [ X`cat "$Output"` = X"2" ] 130 | then 131 | Status="$Status +" 132 | echo >&2 " $AWK +" 133 | else 134 | Status="$Status -" 135 | echo >&2 " $AWK -" 136 | fi 137 | else 138 | Status="$Status -" 139 | echo >&2 " $AWK -" 140 | fi 141 | echo "$Status" >> "$Result" 142 | 143 | # 144 | # exit() function 145 | # 146 | 147 | Status="$AWK exit()" 148 | echo >&2 "exit()" 149 | "$AWK" '{ exit(99) }' "$Input" 2>/dev/null 150 | if [ $? -eq 99 ] 151 | then 152 | Status="$Status +" 153 | echo >&2 " $AWK +" 154 | else 155 | Status="$Status -" 156 | echo >&2 " $AWK -" 157 | fi 158 | echo "$Status" >> "$Result" 159 | done 160 | 161 | # Test the listed features. 162 | # Format: 163 | # string_to_printawk_commandexpected_output 164 | 165 | for func in \ 166 | 'ARGIND if ( !ARGIND ) exit (1)' \ 167 | 'ERRNO getline s < "/"; if ( !ERRNO ) exit (1)' \ 168 | 'ENVIRON if ( !ENVIRON["PATH"] ) exit (1)' \ 169 | 'IGNORECASE IGNORECASE = 1; if ( !("A" ~ "a") ) exit (1)' \ 170 | '\x escapes if ( "\x41" != "A" ) exit (1)' \ 171 | 'assignment to $0 $0 = "a b"; print $2 b' \ 172 | 'array delete elem a[1]=1; delete a[1]; if (a[1]!=0) exit (1)' \ 173 | 'array delete a[1]=1; delete a; if (a[1]!=0) exit (1)' \ 174 | 'array "in" i="x"; a[i]="1"; if (! (i in a)) exit (1)' \ 175 | 'assoc array a ["i"] = "x"; print a ["i"] x' \ 176 | 'atan2() print atan2 (0, 1) 0' \ 177 | 'cos() print cos(0) 1' \ 178 | 'exp() print exp(0) 1' \ 179 | 'getline "echo 1" | getline; if ( $0 != "1" ) exit (1)' \ 180 | 'int() print int(1.5) 1' \ 181 | 'index() print index("AB", "B") 2' \ 182 | 'length() print length("A") 1' \ 183 | 'log() print log(1) 0' \ 184 | 'gensub() print gensub (/u/, "x", "g", "uu") xx' \ 185 | 'gsub() s = "AB"; gsub(/./, "X", s); print s XX' \ 186 | 'match() print match("ab", /b/) 2' \ 187 | 'operator ** print 2**2 4' \ 188 | 'operator ^ print 2^2 4' \ 189 | 'printf() printf("%s\n", "X") X' \ 190 | 'rand() print rand()' \ 191 | 'sin() print sin(0) 0' \ 192 | 'split() print split ("A B", a, " ") 2' \ 193 | 'sprintf() print sprintf("%.1s", "AB") A' \ 194 | 'sqrt() print sqrt(1) 1' \ 195 | 'srand() srand()' \ 196 | 'sub() s = "AB"; sub(/./, "X", s); print s XB' \ 197 | 'substr() print substr ("AB", 2, 1) B' \ 198 | 'system() system (":")' \ 199 | 'systime() print systime()' \ 200 | 'strftime() print strftime("%d.%m.%y", 0) 01.01.70' \ 201 | 'conditional exp a=(1)?("y"):("n"); print a y' \ 202 | 'toupper() print toupper("a") A' \ 203 | 'tolower() print tolower("A") a' \ 204 | 'var regexp r="x"; if ( "x" ~ r ) print "yes" yes' 205 | do 206 | OIFS="$IFS" 207 | IFS=" " export IFS 208 | set -- $func 209 | IFS="$OIFS" 210 | 211 | case "$#" in 212 | 2) msg="$1"; func="$2"; result=;; 213 | 3) msg="$1"; func="$2"; result="$3";; 214 | *) echo >&2 "invalid awk test: $*" 215 | exit 2;; 216 | esac 217 | 218 | echo >&2 "$msg" 219 | echo > "$Input" 220 | 221 | cat <<-EOT > "$Script" 222 | { 223 | $func 224 | } 225 | EOT 226 | 227 | for AWK in $AWKList 228 | do 229 | Status="$AWK $msg" 230 | if TZ= "$AWK" -f "$Script" "$Input" > "$Output" 2>&1 231 | then # AWK returned success 232 | if [ -n "$result" ] 233 | then # Check result string 234 | if [ -s "$Output" ] 235 | then 236 | if [ X"$result" = X"`cat $Output`" ] 237 | then 238 | Status="$Status +" 239 | echo >&2 " $AWK +" 240 | else 241 | Status="$Status !" 242 | echo >&2 " $AWK - (expected <$result>, got <`cat $Output`>)" 243 | fi 244 | else 245 | Status="$Status -" 246 | echo >&2 " $AWK did not produce output" 247 | fi 248 | else 249 | Status="$Status +" 250 | echo >&2 " $AWK +" 251 | fi 252 | else 253 | Status="$Status -" 254 | echo >&2 " $AWK -" 255 | fi 256 | echo "$Status" >> "$Result" 257 | done 258 | done 259 | 260 | if [ -s "$Result" ] 261 | then 262 | # Create a table containing all results 263 | 264 | sort < "$Result" | 265 | awk -F' ' ' 266 | NF != 3 { print " ! " $0 } 267 | NF == 3 { 268 | if ( awks [$1] == "" ) { 269 | awks [$1] = $1 270 | if ( Header == "" ) Header = " " 271 | Header = Header " " $1 272 | } 273 | if ( F [$2] != "" ) F [$2] = F [$2] " " 274 | F [$2] = F [$2] $3 275 | } 276 | END { 277 | print Header 278 | for ( i in F ) { 279 | print i " " F [i] 280 | } 281 | } 282 | ' | 283 | sort | 284 | tee "$LOGFILE" 285 | fi 286 | 287 | echo >&2 " 288 | A copy of the test results were written to the file 289 | $LOGFILE 290 | 291 | Please send an e-mail with the contents of the file to the 292 | following address: 293 | 294 | $email 295 | " 296 | 297 | exit 0 298 | -------------------------------------------------------------------------------- /link-spider/README: -------------------------------------------------------------------------------- 1 | link.db 2 | hashurl url crawl_time source ext 3 | -------------------------------------------------------------------------------- /link-spider/bin/LinkSpider.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | from Browser import Browser 5 | from PageParser import PageParser 6 | import json 7 | 8 | from Utils import DB, Logger 9 | 10 | class LinkSpider(object): 11 | 12 | def __init__(self, **args): 13 | self.baseurl = args['baseurl'] 14 | self.db = args['db'] 15 | 16 | def crawl(self, **args): 17 | source = args['source'] 18 | ext = args['ext'] 19 | reply_time = args['reply_time'] 20 | br = Browser() 21 | page = br.open(self.baseurl) 22 | new_reply_time = reply_time 23 | while True: 24 | links = PageParser.parse(page, source) 25 | for i, link in enumerate(links): 26 | if reply_time < link.reply_time: 27 | if i is 0: 28 | new_reply_time = link.reply_time 29 | self.db.insert('\t'.join([str(link), source, json.dumps(ext)])) 30 | else: 31 | return new_reply_time 32 | try: 33 | page = br.follow_link(text='后页>') 34 | except: 35 | Logger.info('finished!') 36 | break 37 | return new_reply_time 38 | -------------------------------------------------------------------------------- /link-spider/bin/LinkSpider.py2: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | from Browser import Browser 5 | from PageParser import PageParser 6 | import json 7 | 8 | from Utils import DB, Logger 9 | 10 | class LinkSpider(object): 11 | 12 | def __init__(self, **args): 13 | self.baseurl = args['baseurl'] 14 | self.db = args['db'] 15 | self.br = Browser() 16 | 17 | def crawl(self, **args): 18 | source = args['source'] 19 | ext = args['ext'] 20 | reply_time = args['reply_time'] 21 | print '>>>>', self.baseurl 22 | page = self.br.open(self.baseurl, 0.9) 23 | new_reply_time = reply_time 24 | while True: 25 | links, nexturl = PageParser.parse(page, source) 26 | for i, link in enumerate(links): 27 | if reply_time < link.reply_time: 28 | if i == 0: 29 | new_reply_time = link.reply_time 30 | self.db.insert('\t'.join([str(link), source, json.dumps(ext)])) 31 | else: 32 | return new_reply_time 33 | if nexturl: 34 | page = self.br.open(nexturl, 0.9) 35 | print '>>>>', nexturl 36 | else: 37 | Logger.info('finished!') 38 | break 39 | return new_reply_time 40 | -------------------------------------------------------------------------------- /link-spider/bin/PageParser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | from BeautifulSoup import BeautifulSoup 5 | import time 6 | import hashlib 7 | 8 | from Utils import Link, Logger 9 | 10 | class PageParser: 11 | 12 | @staticmethod 13 | def parse(page, source): 14 | return { 15 | 'douban':PageParser._parse_douban, 16 | 'shuimu':PageParser._parse_shuimu, 17 | 'ganji':PageParser._parse_ganji, 18 | 'soufun':PageParser._parse_soufun, 19 | '58':PageParser._parse_58, 20 | }[source](page) 21 | 22 | 23 | @staticmethod 24 | def _clean(soup): 25 | new_list = [] 26 | for i in soup: 27 | if str(i).strip(): 28 | new_list.append(i) 29 | return new_list 30 | 31 | @staticmethod 32 | def _parse_douban(page): 33 | soup = BeautifulSoup(page) 34 | ret = [] 35 | try: 36 | table = soup.findAll('table', {'class':'olt'})[0] 37 | ''' 38 | nexturl = soup.findAll('div', {'class':'paginator'})[0]\ 39 | .findAll('span', {'class':'next'})[0] 40 | try: 41 | nexturl = nexturl.findAll('link')[0]['href'] 42 | except: 43 | nexturl = '' 44 | ''' 45 | for row in PageParser._clean(table)[1:]: #skip table header 46 | try: 47 | url, _, _, reply_time = PageParser._clean(row) 48 | except: 49 | continue 50 | url = PageParser._clean(url)[0]['href'].strip() 51 | reply_time = PageParser._clean(reply_time)[0].strip() 52 | if ':' in reply_time: 53 | year = time.strftime('%Y-',time.localtime(time.time())) 54 | reply_time = time.strptime(year+reply_time, '%Y-%m-%d %H:%M') 55 | else: 56 | reply_time = time.strptime(reply_time, '%Y-%m-%d') 57 | reply_time = int(time.mktime(reply_time)) 58 | hashurl = hashlib.md5(url).hexdigest() 59 | ret.append(Link( 60 | hashurl=hashurl, 61 | url=url, 62 | reply_time=reply_time 63 | )) 64 | except IndexError: 65 | Logger.error('index error!') 66 | return ret #, nexturl 67 | 68 | @staticmethod 69 | def _parse_shuimu(page): 70 | pass 71 | 72 | @staticmethod 73 | def _parse_ganji(page): 74 | pass 75 | 76 | @staticmethod 77 | def _parse_soufun(page): 78 | pass 79 | 80 | @staticmethod 81 | def _parse_58(page): 82 | pass 83 | -------------------------------------------------------------------------------- /link-spider/bin/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | import time 5 | import os 6 | import datetime 7 | import json 8 | import sys 9 | 10 | from LinkSpider import LinkSpider 11 | from Utils import Logger, DB, Meta, backup 12 | 13 | def run_linkspider(db, meta): 14 | source = 'douban' 15 | baseurls = [ 16 | 'http://www.douban.com/group/beijingzufang/discussion', 17 | 'http://www.douban.com/group/fangzi/discussion', 18 | 'http://www.douban.com/group/262626/discussion', 19 | 'http://www.douban.com/group/276176/discussion', 20 | 'http://www.douban.com/group/26926/discussion', 21 | 'http://www.douban.com/group/sweethome/discussion', 22 | 'http://www.douban.com/group/242806/discussion', 23 | 'http://www.douban.com/group/257523/discussion', 24 | 'http://www.douban.com/group/279962/discussion', 25 | 'http://www.douban.com/group/334449/discussion', 26 | ] 27 | 28 | for baseurl in baseurls: 29 | Logger.info('start '+baseurl) 30 | groupid = baseurl\ 31 | .replace('http://www.douban.com/group/', '')\ 32 | .replace('/discussion', '') 33 | reply_time = 0 34 | if meta.has(source, groupid)\ 35 | and meta.get(source, groupid).has_key('reply_time'): 36 | reply_time = meta.get(source, groupid)['reply_time'] 37 | linkspider = LinkSpider( 38 | baseurl=baseurl, 39 | db=db, 40 | ) 41 | reply_time = linkspider.crawl( 42 | source=source, 43 | reply_time=reply_time, 44 | ext={ 45 | 'groupid':groupid 46 | } 47 | ) 48 | meta.set(source, groupid, { 49 | 'reply_time':reply_time 50 | }) 51 | meta.write() 52 | 53 | def main(**args): 54 | modulepath = args['modulepath'] 55 | linkdb = os.path.join(modulepath, '../output/link.db') 56 | backup(linkdb) 57 | 58 | linkmeta = os.path.join(modulepath, '../output/link.meta') 59 | backup(linkmeta) 60 | run_linkspider(DB(linkdb), Meta(linkmeta)) 61 | 62 | if __name__ == '__main__': 63 | starttime = datetime.datetime.now() 64 | run = sys.argv[0] 65 | modulepath = os.path.dirname(run) 66 | main( 67 | modulepath=modulepath 68 | ) 69 | endtime = datetime.datetime.now() 70 | Logger.info('done! %lds' % (endtime-starttime).seconds) 71 | -------------------------------------------------------------------------------- /link-spider/bin/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | thisdir=${0%/*} 3 | python -u "$thisdir/main.py" >> "$thisdir/../log/log" 2>&1 4 | -------------------------------------------------------------------------------- /manage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # zhangxiaoyang.hit[at]gmail.com 3 | 4 | #################################################### 5 | # I take control of all the modules >_> 6 | # 7 | # Usage: 8 | # ./manage.sh [run/clean/status/kill] [modulename] 9 | # ./manage.sh [run/clean] all 10 | # 11 | # Note: 12 | # `clean all` will DELETE all the data! 13 | # Use `ctrl+z` to hang me up 14 | # then use `bg` to make me run in the background. 15 | # 16 | # Flow: 17 | # ----------------------------------------------- 18 | # link-spider -> page-spider -> content-extractor 19 | # -> house-refinery -> data-aggregator 20 | # ----------------------------------------------- 21 | # | 22 | # adapter.sh 23 | # / \ 24 | # import export 25 | #################################################### 26 | 27 | readonly WORKSPACE=$(pwd) 28 | readonly modules=("link-spider" "page-spider" "content-extractor" "house-refinery" "data-aggregator") 29 | readonly opts=(${modules[@]} "all") 30 | export PYTHONPATH="$WORKSPACE/libs" 31 | 32 | function run_module() 33 | { 34 | echo "run $modulepath" 35 | local modulepath=$1 36 | mkdir -p "$modulepath/data" 37 | mkdir -p "$modulepath/output" 38 | mkdir -p "$modulepath/log" 39 | eval "$modulepath/bin/run" 40 | } 41 | 42 | function clean_module() 43 | { 44 | echo "clean $modulepath" 45 | local modulepath=$1 46 | rm -rf "$modulepath/data" 47 | rm -rf "$modulepath/output" 48 | rm -rf "$modulepath/log" 49 | } 50 | 51 | function kill_module() 52 | { 53 | local modulepath=$1 54 | local pid=`ps aux|grep $modulepath|head -1|awk '{print $2;}'` 55 | kill -9 "$pid" 56 | local pid=`ps aux|grep $modulepath|head -1|awk '{print $2;}'` 57 | kill -9 "$pid" 58 | echo "kill $pid $modulepath" 59 | ps aux|grep $modulepath 60 | } 61 | 62 | function run_all() 63 | { 64 | echo "run all" 65 | for module in ${modules[@]} 66 | do 67 | modulepath="$WORKSPACE/$module" 68 | run_module "$modulepath" 69 | done 70 | } 71 | 72 | function clean_all() 73 | { 74 | echo "clean all" 75 | for module in ${modules[@]} 76 | do 77 | modulepath="$WORKSPACE/$module" 78 | clean_module "$modulepath" 79 | done 80 | } 81 | 82 | function kill_all() 83 | { 84 | echo "kill all" 85 | for module in ${modules[@]} 86 | do 87 | modulepath="$WORKSPACE/$module" 88 | kill_module "$modulepath" 89 | done 90 | } 91 | 92 | function nothing() 93 | { 94 | echo "do nothing... exit" 95 | exit 0; 96 | } 97 | 98 | function manage() 99 | { 100 | if [[ ${opts[@]} =~ "$2" ]] 101 | then 102 | module="$2" 103 | modulepath="$WORKSPACE/$module" 104 | else 105 | nothing 106 | fi 107 | 108 | case "$1" in 109 | "clean" ) 110 | if [ "$2" = "all" ] 111 | then 112 | clean_all 113 | elif [[ "$2" && ${modules[@]} =~ "$2" ]] 114 | then 115 | clean_module "$modulepath" 116 | else 117 | nothing 118 | fi 119 | ;; 120 | "run" ) 121 | if [ "$2" = "all" ] 122 | then 123 | run_all 124 | elif [[ "$2" && ${modules[@]} =~ "$2" ]] 125 | then 126 | run_module "$modulepath" 127 | else 128 | nothing 129 | fi 130 | ;; 131 | "status" ) 132 | if [[ "$2" && ${modules[@]} =~ "$2" ]] 133 | then 134 | ps aux | grep "$2" | head -1 135 | cat "$2"/log/log 136 | else 137 | nothing 138 | fi 139 | ;; 140 | "kill" ) 141 | if [ "$2" = "all" ] 142 | then 143 | kill_all 144 | elif [[ "$2" && ${modules[@]} =~ "$2" ]] 145 | then 146 | kill_module "$modulepath" 147 | else 148 | nothing 149 | fi 150 | ;; 151 | * ) 152 | if [[ "$1" && ${modules[@]} =~ "$1" ]] 153 | then 154 | module="$1" 155 | modulepath="$WORKSPACE/$module" 156 | run_module "$modulepath" 157 | else 158 | nothing 159 | fi 160 | ;; 161 | esac 162 | } 163 | 164 | # Main entrance 165 | manage "$1" "$2" 166 | -------------------------------------------------------------------------------- /page-spider/bin/PageSpider.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | import os 5 | 6 | from Browser import Browser 7 | from Utils import Logger 8 | 9 | class PageSpider(object): 10 | 11 | def __init__(self, **args): 12 | pass 13 | 14 | def crawl(self, **args): 15 | url = args['url'] 16 | br = Browser() 17 | return br.open(url, 0.9) 18 | 19 | def crawl_to_file(self, **args): 20 | url = args['url'] 21 | path = args['path'] 22 | filename = args['filename'] 23 | with open(os.path.join(path, filename), 'w') as f: 24 | page = self.crawl(url=url) 25 | f.write(page) 26 | -------------------------------------------------------------------------------- /page-spider/bin/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | import time 5 | import os 6 | import datetime 7 | import sys 8 | 9 | from PageSpider import PageSpider 10 | from Utils import Logger, DB 11 | 12 | def diff_task(linkdb, output, pagelist): 13 | page_filenames = [] 14 | #trick :) 15 | if os.path.exists(pagelist): 16 | Logger.info('Use pagelist indead of page files!') 17 | with open(pagelist, 'r') as f: 18 | for line in f: 19 | line = line.strip() 20 | if not line: 21 | break 22 | filename = line 23 | page_filenames.append(filename) 24 | else: 25 | Logger.info('CANNOT find pagelist file: %s' % pagelist) 26 | 27 | tasks = {} 28 | sources = [] 29 | with open(linkdb, 'r') as f: 30 | for line in f: 31 | line = line.strip() 32 | if line: 33 | try: 34 | hashurl, url, reply_time, source = line.split('\t')[:4] 35 | except: continue 36 | filename = '%s' % (hashurl) 37 | tasks.update({ 38 | filename:{ 39 | 'url':url, 40 | 'source':source 41 | } 42 | }) 43 | sources.append(source) 44 | 45 | if not pagelist: 46 | for source in set(sources): 47 | source = os.path.join(output, source) 48 | if os.path.exists(source): 49 | filenames = os.listdir(source) 50 | for filename in filenames: 51 | tasks.pop(filename) 52 | else: 53 | os.mkdir(source) 54 | else: 55 | for source in set(sources): 56 | source = os.path.join(output, source) 57 | if not os.path.exists(source): 58 | os.mkdir(source) 59 | for filename in page_filenames: 60 | try: 61 | tasks.pop(filename) 62 | except: 63 | print 'Skip', filename 64 | return tasks 65 | 66 | def main(**args): 67 | modulepath = args['modulepath'] 68 | linkdb = os.path.join(modulepath, '../data/link.db') 69 | path = os.path.join(modulepath, '../output/') 70 | pagelist = os.path.join(path, 'pagelist') 71 | 72 | pagespider = PageSpider() 73 | tasks = diff_task(linkdb, path, pagelist) 74 | 75 | db_pagelist = DB(pagelist) 76 | for filename in tasks: 77 | pagespider.crawl_to_file( 78 | url=tasks[filename]['url'], 79 | path=os.path.join(path, tasks[filename]['source']), 80 | filename=filename 81 | ) 82 | db_pagelist.insert(filename) 83 | 84 | if __name__ == '__main__': 85 | starttime = datetime.datetime.now() 86 | run = sys.argv[0] 87 | modulepath = os.path.dirname(run) 88 | main( 89 | modulepath=modulepath 90 | ) 91 | endtime = datetime.datetime.now() 92 | Logger.info('done! %lds' % (endtime-starttime).seconds) 93 | -------------------------------------------------------------------------------- /page-spider/bin/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | thisdir=${0%/*} 4 | linkdb="link.db" 5 | linkdb_src="$thisdir/../../link-spider/output" 6 | linkdb_dst="$thisdir/../data" 7 | 8 | function pull_linkdb() 9 | { 10 | local linkdb=$1 11 | local linkdb_src=$2 12 | local linkdb_dst=$3 13 | rm -f "$linkdb_dst/$linkdb" 14 | ln -s "$linkdb_src/$linkdb" "$linkdb_dst" 15 | } 16 | pull_linkdb "$linkdb" "$linkdb_src" "$linkdb_dst" 17 | 18 | python -u "$thisdir/main.py" >> "$thisdir/../log/log" 2>&1 19 | -------------------------------------------------------------------------------- /requirements: -------------------------------------------------------------------------------- 1 | BeautifulSoup==3.2.1 2 | Django==1.7 3 | argparse==1.2.1 4 | distribute==0.6.24 5 | jieba==0.32 6 | mechanize==0.2.5 7 | mongoengine==0.8.7 8 | pymongo==2.7.2 9 | simhash==1.4.6 10 | wsgiref==0.1.2 11 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # zhangxiaoyang.hit[at]gmail.com 3 | 4 | imgdir="../db/imgdir" 5 | mongopath="../db" 6 | imglist="data-aggregator/output/imglist" 7 | pagedir="page-spider/output/douban" 8 | 9 | function load_env() 10 | { 11 | source env/bin/activate 12 | } 13 | 14 | function clean_img_cache() 15 | { 16 | local imglist="$1" 17 | local imgdir="$2" 18 | 19 | while read url 20 | do 21 | imgname=`echo -n "$url" | cut -d "/" -f 8` 22 | mv "$imgdir/$imgname" "$imgdir/$imgname.bak" 23 | done < "$imglist" 24 | 25 | for imgname in `ls $imgdir | grep -v "bak$"` 26 | do 27 | rm -f "$imgdir/$imgname" 28 | done 29 | 30 | for imgname in `ls $imgdir` 31 | do 32 | newname=`echo $imgname | sed 's/\.bak$//'` 33 | mv "$imgdir/$imgname" "$imgdir/$newname" 34 | done 35 | } 36 | 37 | function clean_page_cache() 38 | { 39 | local pagedir="$1" 40 | rm -rf "$pagedir" 41 | } 42 | 43 | echo "START: $(date '+%Y-%m-%d %H:%M:%S')" 44 | load_env 45 | 46 | lastestCmd=`ps aux | grep "zufang.*run\|manage.sh" | grep -v "runserver" | grep -v grep` 47 | if [ "$lastestCmd" == "" ] 48 | then 49 | echo "Updating ..." 50 | bash manage.sh run all 51 | 52 | echo "Moving images ..." 53 | #mv data-aggregator/output/imgdir/* "$imgdir" 54 | find data-aggregator/output/imgdir/ -name '*.*' | xargs -i mv {} "$imgdir" 55 | 56 | echo "Cleaning img cache ..." 57 | clean_img_cache "$imglist" "$imgdir" 58 | 59 | echo "Cleaning page cache ..." 60 | clean_page_cache "$pagedir" 61 | 62 | echo "Cleaning DB ..." 63 | "$mongopath/mongo" zufang --eval "db.dropDatabase()" 64 | 65 | echo "Pushing DB ..." 66 | "$mongopath/mongoimport" -d zufang -c house data-aggregator/output/zufang.house.json 67 | else 68 | echo "Stopped" 69 | fi 70 | echo "DONE: $(date '+%Y-%m-%d %H:%M:%S')" 71 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxiaoyang/zufang/49400b213cee2d328b9fe1363e0774655872cbeb/screenshot.png -------------------------------------------------------------------------------- /screenshot1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxiaoyang/zufang/49400b213cee2d328b9fe1363e0774655872cbeb/screenshot1.jpg -------------------------------------------------------------------------------- /screenshot2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxiaoyang/zufang/49400b213cee2d328b9fe1363e0774655872cbeb/screenshot2.jpg -------------------------------------------------------------------------------- /ui/README: -------------------------------------------------------------------------------- 1 | final.db 2 | hashurl title author(json) images(json) links(json) text pub_time jushi shouji zujin dizhi 3 | 1 2 3 4 5 6 7 8 9 10 11 4 | 5 | mining.db 6 | # hashurl title content jushi(居室类型) shouji(手机号) zujin(租金) dizhi(地址标签) 7 | -------------------------------------------------------------------------------- /ui/app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxiaoyang/zufang/49400b213cee2d328b9fe1363e0774655872cbeb/ui/app/__init__.py -------------------------------------------------------------------------------- /ui/app/admin.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | from django.contrib import admin 3 | 4 | # Register your models here. 5 | -------------------------------------------------------------------------------- /ui/app/models.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | from mongoengine import * 3 | 4 | class House(Document): 5 | hashurl = StringField(max_length=32) 6 | title = StringField() 7 | author = DictField() 8 | images = ListField() 9 | links = ListField() 10 | text = StringField() 11 | pub_time = StringField(max_length=19) 12 | jushi = StringField() 13 | shouji = StringField(max_length=20) 14 | zujin = StringField() 15 | dizhi = StringField() 16 | ditie = StringField() 17 | url = StringField() 18 | crawl_time = IntField() 19 | source = StringField() 20 | ext = DictField() 21 | sim = ListField() 22 | # hashurl title author images links text pub_time 23 | # 1 2 3 4 5 6 7 24 | # jushi shouji zujin dizhi ditie url crawl_time source ext sim 25 | # 8 9 10 11 12 13 14 15 16 17 26 | -------------------------------------------------------------------------------- /ui/app/tests.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | from django.test import TestCase 3 | 4 | # Create your tests here. 5 | -------------------------------------------------------------------------------- /ui/app/urls.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | from django.conf.urls import patterns, include, url 3 | from django.conf import settings 4 | 5 | urlpatterns = patterns('app.views', 6 | url(r'^$', 'index'), 7 | url(r'download/$', 'download'), 8 | 9 | url(r'^apis/update/$', 'update'), 10 | url(r'^apis/search/(.*?)/(\d+)/$', 'search'), 11 | url(r'^apis/search/(.*?)/$', 'search'), 12 | ) 13 | if settings.DEBUG == False: 14 | urlpatterns += patterns('', 15 | url(r'^static/(?P.*)$', 'django.views.static.serve', {'document_root': settings.STATIC_ROOT}), 16 | ) 17 | -------------------------------------------------------------------------------- /ui/app/views.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | from django.shortcuts import render 3 | from django.http import JsonResponse, HttpResponseRedirect, HttpResponse 4 | from models import House 5 | from mongoengine import * 6 | import operator 7 | import re 8 | import os 9 | from ui.settings import BASE_DIR 10 | 11 | def index(request): 12 | return render(request, 'index.html', locals()) 13 | 14 | def download(request): 15 | apks = os.listdir(os.path.join(BASE_DIR, 'static/apks')) 16 | latest_apk = sorted(apks)[-1] 17 | latest_version = re.sub(r'\.\w+$', '', latest_apk.split('_')[-1]) 18 | return HttpResponseRedirect('/static/apks/' + latest_apk) 19 | 20 | def update(request): 21 | apks = os.listdir(os.path.join(BASE_DIR, 'static/apks')) 22 | latest_apk = sorted(apks)[-1] 23 | latest_version = re.sub(r'\.\w+$', '', latest_apk.split('_')[-1]) 24 | return HttpResponse(latest_version) 25 | 26 | def make_query(query): 27 | querys = re.split(r'\s+', query) 28 | new_query = [] 29 | count = 1 30 | for i in querys: 31 | if len(i) > 1: 32 | if count > 3: 33 | break 34 | core = ur'[0-9a-zA-Z\u4E00-\u9FA5]{2,}' 35 | p = re.compile(core, re.UNICODE) 36 | query = ''.join(re.findall(p, i)) 37 | if new_query: 38 | new_query.append(Q(title__contains=query)) 39 | new_query.append(Q(text__contains=query)) 40 | else: 41 | new_query = [Q(title__contains=query), Q(text__contains=query)] 42 | count += 1 43 | return reduce(operator.or_, new_query) 44 | 45 | def search(request, query, page_num=1): 46 | new_query = make_query(query) 47 | if not new_query: 48 | return JsonResponse({'error':'Invalid query'}) 49 | 50 | page_size = 5 51 | page_num = int(page_num) 52 | if page_num < 1: 53 | return JsonResponse({'error':'Invalid page_num'}) 54 | 55 | house_model = House.objects.filter(new_query).order_by('-pub_time') 56 | count = house_model.count() 57 | page_count = count/page_size+1 if count%page_size else count/page_size 58 | page_next = page_num+1 if page_num < page_count else -1 59 | page_prev = page_num-1 if page_num > 1 else -1 60 | houses = house_model.skip((page_num-1)*page_size).limit(page_size) 61 | 62 | ret = [] 63 | for h in houses: 64 | images = [] 65 | for i in h.images: 66 | image_src, image_alt = i 67 | if image_src: 68 | images.append(('/static/imgdir/'+image_src.split('/')[-1], image_alt)) 69 | dizhi = [i for i in h.dizhi.split(',') if i] 70 | ditie = [i for i in h.ditie.split(',') if i] 71 | 72 | ret.append({ 73 | "hashurl":h.hashurl, 74 | "title":h.title, 75 | "author":h.author, 76 | "images":images, 77 | "links":h.links, 78 | "text":h.text, 79 | "pub_time":h.pub_time, 80 | "jushi":h.jushi, 81 | "shouji":h.shouji, 82 | "zujin":h.zujin, 83 | "dizhi":dizhi, 84 | "ditie":ditie, 85 | "url":h.url, 86 | "crawl_time":h.crawl_time, 87 | "source":h.source, 88 | "ext":h.ext, 89 | "sim":h.sim, 90 | }) 91 | 92 | return JsonResponse({ 93 | 'result':ret, 94 | 'page_num':page_num, 95 | 'page_count':page_count, 96 | 'page_prev':page_prev, 97 | 'page_next':page_next, 98 | 'query':query, 99 | }) 100 | -------------------------------------------------------------------------------- /ui/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ui.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /ui/requirements: -------------------------------------------------------------------------------- 1 | Django==1.7 2 | argparse==1.2.1 3 | distribute==0.6.24 4 | mongoengine==0.8.7 5 | pymongo==2.7.2 6 | wsgiref==0.1.2 7 | -------------------------------------------------------------------------------- /ui/run_server.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | python manage.py runserver 0.0.0.0:8090 4 | -------------------------------------------------------------------------------- /ui/static/bootstrap3/css/bootstrap-theme.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.2.0 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | .btn-default, 8 | .btn-primary, 9 | .btn-success, 10 | .btn-info, 11 | .btn-warning, 12 | .btn-danger { 13 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .2); 14 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 15 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 16 | } 17 | .btn-default:active, 18 | .btn-primary:active, 19 | .btn-success:active, 20 | .btn-info:active, 21 | .btn-warning:active, 22 | .btn-danger:active, 23 | .btn-default.active, 24 | .btn-primary.active, 25 | .btn-success.active, 26 | .btn-info.active, 27 | .btn-warning.active, 28 | .btn-danger.active { 29 | -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 30 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 31 | } 32 | .btn:active, 33 | .btn.active { 34 | background-image: none; 35 | } 36 | .btn-default { 37 | text-shadow: 0 1px 0 #fff; 38 | background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%); 39 | background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%); 40 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0)); 41 | background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%); 42 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); 43 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 44 | background-repeat: repeat-x; 45 | border-color: #dbdbdb; 46 | border-color: #ccc; 47 | } 48 | .btn-default:hover, 49 | .btn-default:focus { 50 | background-color: #e0e0e0; 51 | background-position: 0 -15px; 52 | } 53 | .btn-default:active, 54 | .btn-default.active { 55 | background-color: #e0e0e0; 56 | border-color: #dbdbdb; 57 | } 58 | .btn-default:disabled, 59 | .btn-default[disabled] { 60 | background-color: #e0e0e0; 61 | background-image: none; 62 | } 63 | .btn-primary { 64 | background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%); 65 | background-image: -o-linear-gradient(top, #428bca 0%, #2d6ca2 100%); 66 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#2d6ca2)); 67 | background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%); 68 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0); 69 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 70 | background-repeat: repeat-x; 71 | border-color: #2b669a; 72 | } 73 | .btn-primary:hover, 74 | .btn-primary:focus { 75 | background-color: #2d6ca2; 76 | background-position: 0 -15px; 77 | } 78 | .btn-primary:active, 79 | .btn-primary.active { 80 | background-color: #2d6ca2; 81 | border-color: #2b669a; 82 | } 83 | .btn-primary:disabled, 84 | .btn-primary[disabled] { 85 | background-color: #2d6ca2; 86 | background-image: none; 87 | } 88 | .btn-success { 89 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); 90 | background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%); 91 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641)); 92 | background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); 93 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); 94 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 95 | background-repeat: repeat-x; 96 | border-color: #3e8f3e; 97 | } 98 | .btn-success:hover, 99 | .btn-success:focus { 100 | background-color: #419641; 101 | background-position: 0 -15px; 102 | } 103 | .btn-success:active, 104 | .btn-success.active { 105 | background-color: #419641; 106 | border-color: #3e8f3e; 107 | } 108 | .btn-success:disabled, 109 | .btn-success[disabled] { 110 | background-color: #419641; 111 | background-image: none; 112 | } 113 | .btn-info { 114 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 115 | background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 116 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2)); 117 | background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); 118 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); 119 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 120 | background-repeat: repeat-x; 121 | border-color: #28a4c9; 122 | } 123 | .btn-info:hover, 124 | .btn-info:focus { 125 | background-color: #2aabd2; 126 | background-position: 0 -15px; 127 | } 128 | .btn-info:active, 129 | .btn-info.active { 130 | background-color: #2aabd2; 131 | border-color: #28a4c9; 132 | } 133 | .btn-info:disabled, 134 | .btn-info[disabled] { 135 | background-color: #2aabd2; 136 | background-image: none; 137 | } 138 | .btn-warning { 139 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 140 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 141 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316)); 142 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); 143 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); 144 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 145 | background-repeat: repeat-x; 146 | border-color: #e38d13; 147 | } 148 | .btn-warning:hover, 149 | .btn-warning:focus { 150 | background-color: #eb9316; 151 | background-position: 0 -15px; 152 | } 153 | .btn-warning:active, 154 | .btn-warning.active { 155 | background-color: #eb9316; 156 | border-color: #e38d13; 157 | } 158 | .btn-warning:disabled, 159 | .btn-warning[disabled] { 160 | background-color: #eb9316; 161 | background-image: none; 162 | } 163 | .btn-danger { 164 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 165 | background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 166 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a)); 167 | background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); 168 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); 169 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 170 | background-repeat: repeat-x; 171 | border-color: #b92c28; 172 | } 173 | .btn-danger:hover, 174 | .btn-danger:focus { 175 | background-color: #c12e2a; 176 | background-position: 0 -15px; 177 | } 178 | .btn-danger:active, 179 | .btn-danger.active { 180 | background-color: #c12e2a; 181 | border-color: #b92c28; 182 | } 183 | .btn-danger:disabled, 184 | .btn-danger[disabled] { 185 | background-color: #c12e2a; 186 | background-image: none; 187 | } 188 | .thumbnail, 189 | .img-thumbnail { 190 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 191 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 192 | } 193 | .dropdown-menu > li > a:hover, 194 | .dropdown-menu > li > a:focus { 195 | background-color: #e8e8e8; 196 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 197 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 198 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 199 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 200 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 201 | background-repeat: repeat-x; 202 | } 203 | .dropdown-menu > .active > a, 204 | .dropdown-menu > .active > a:hover, 205 | .dropdown-menu > .active > a:focus { 206 | background-color: #357ebd; 207 | background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); 208 | background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%); 209 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd)); 210 | background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); 211 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); 212 | background-repeat: repeat-x; 213 | } 214 | .navbar-default { 215 | background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%); 216 | background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%); 217 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8)); 218 | background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%); 219 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); 220 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 221 | background-repeat: repeat-x; 222 | border-radius: 4px; 223 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 224 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 225 | } 226 | .navbar-default .navbar-nav > .active > a { 227 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%); 228 | background-image: -o-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%); 229 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f3f3f3)); 230 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%); 231 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0); 232 | background-repeat: repeat-x; 233 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 234 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 235 | } 236 | .navbar-brand, 237 | .navbar-nav > li > a { 238 | text-shadow: 0 1px 0 rgba(255, 255, 255, .25); 239 | } 240 | .navbar-inverse { 241 | background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%); 242 | background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%); 243 | background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222)); 244 | background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%); 245 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); 246 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 247 | background-repeat: repeat-x; 248 | } 249 | .navbar-inverse .navbar-nav > .active > a { 250 | background-image: -webkit-linear-gradient(top, #222 0%, #282828 100%); 251 | background-image: -o-linear-gradient(top, #222 0%, #282828 100%); 252 | background-image: -webkit-gradient(linear, left top, left bottom, from(#222), to(#282828)); 253 | background-image: linear-gradient(to bottom, #222 0%, #282828 100%); 254 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0); 255 | background-repeat: repeat-x; 256 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 257 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 258 | } 259 | .navbar-inverse .navbar-brand, 260 | .navbar-inverse .navbar-nav > li > a { 261 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .25); 262 | } 263 | .navbar-static-top, 264 | .navbar-fixed-top, 265 | .navbar-fixed-bottom { 266 | border-radius: 0; 267 | } 268 | .alert { 269 | text-shadow: 0 1px 0 rgba(255, 255, 255, .2); 270 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 271 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 272 | } 273 | .alert-success { 274 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 275 | background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 276 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc)); 277 | background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); 278 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); 279 | background-repeat: repeat-x; 280 | border-color: #b2dba1; 281 | } 282 | .alert-info { 283 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 284 | background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 285 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0)); 286 | background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); 287 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); 288 | background-repeat: repeat-x; 289 | border-color: #9acfea; 290 | } 291 | .alert-warning { 292 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 293 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 294 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0)); 295 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); 296 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); 297 | background-repeat: repeat-x; 298 | border-color: #f5e79e; 299 | } 300 | .alert-danger { 301 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 302 | background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 303 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3)); 304 | background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); 305 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); 306 | background-repeat: repeat-x; 307 | border-color: #dca7a7; 308 | } 309 | .progress { 310 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 311 | background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 312 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5)); 313 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); 314 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); 315 | background-repeat: repeat-x; 316 | } 317 | .progress-bar { 318 | background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%); 319 | background-image: -o-linear-gradient(top, #428bca 0%, #3071a9 100%); 320 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#3071a9)); 321 | background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%); 322 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0); 323 | background-repeat: repeat-x; 324 | } 325 | .progress-bar-success { 326 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); 327 | background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%); 328 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44)); 329 | background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); 330 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); 331 | background-repeat: repeat-x; 332 | } 333 | .progress-bar-info { 334 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 335 | background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 336 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5)); 337 | background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); 338 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); 339 | background-repeat: repeat-x; 340 | } 341 | .progress-bar-warning { 342 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 343 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 344 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f)); 345 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); 346 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); 347 | background-repeat: repeat-x; 348 | } 349 | .progress-bar-danger { 350 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); 351 | background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%); 352 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c)); 353 | background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); 354 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); 355 | background-repeat: repeat-x; 356 | } 357 | .progress-bar-striped { 358 | background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 359 | background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 360 | background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 361 | } 362 | .list-group { 363 | border-radius: 4px; 364 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 365 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 366 | } 367 | .list-group-item.active, 368 | .list-group-item.active:hover, 369 | .list-group-item.active:focus { 370 | text-shadow: 0 -1px 0 #3071a9; 371 | background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%); 372 | background-image: -o-linear-gradient(top, #428bca 0%, #3278b3 100%); 373 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#3278b3)); 374 | background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%); 375 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0); 376 | background-repeat: repeat-x; 377 | border-color: #3278b3; 378 | } 379 | .panel { 380 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 381 | box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 382 | } 383 | .panel-default > .panel-heading { 384 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 385 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 386 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 387 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 388 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 389 | background-repeat: repeat-x; 390 | } 391 | .panel-primary > .panel-heading { 392 | background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); 393 | background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%); 394 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd)); 395 | background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); 396 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); 397 | background-repeat: repeat-x; 398 | } 399 | .panel-success > .panel-heading { 400 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 401 | background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 402 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6)); 403 | background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); 404 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); 405 | background-repeat: repeat-x; 406 | } 407 | .panel-info > .panel-heading { 408 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 409 | background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 410 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3)); 411 | background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); 412 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); 413 | background-repeat: repeat-x; 414 | } 415 | .panel-warning > .panel-heading { 416 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 417 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 418 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc)); 419 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); 420 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); 421 | background-repeat: repeat-x; 422 | } 423 | .panel-danger > .panel-heading { 424 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 425 | background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 426 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc)); 427 | background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); 428 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); 429 | background-repeat: repeat-x; 430 | } 431 | .well { 432 | background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 433 | background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 434 | background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5)); 435 | background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); 436 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); 437 | background-repeat: repeat-x; 438 | border-color: #dcdcdc; 439 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 440 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 441 | } 442 | /*# sourceMappingURL=bootstrap-theme.css.map */ 443 | -------------------------------------------------------------------------------- /ui/static/bootstrap3/css/bootstrap-theme.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"bootstrap-theme.css","sources":["less/theme.less","less/mixins/vendor-prefixes.less","bootstrap-theme.css","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"AAeA;;;;;;EAME,0CAAA;EC+CA,6FAAA;EACQ,qFAAA;EC5DT;AFiBC;;;;;;;;;;;;EC0CA,0DAAA;EACQ,kDAAA;EC7CT;AFqCC;;EAEE,wBAAA;EEnCH;AFwCD;EG/CI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EA+B2C,2BAAA;EAA2B,oBAAA;EE7BvE;AFAC;;EAEE,2BAAA;EACA,8BAAA;EEEH;AFCC;;EAEE,2BAAA;EACA,uBAAA;EECH;AFEC;;EAEE,2BAAA;EACA,wBAAA;EEAH;AFeD;EGhDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EE0BD;AFxBC;;EAEE,2BAAA;EACA,8BAAA;EE0BH;AFvBC;;EAEE,2BAAA;EACA,uBAAA;EEyBH;AFtBC;;EAEE,2BAAA;EACA,wBAAA;EEwBH;AFRD;EGjDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EEkDD;AFhDC;;EAEE,2BAAA;EACA,8BAAA;EEkDH;AF/CC;;EAEE,2BAAA;EACA,uBAAA;EEiDH;AF9CC;;EAEE,2BAAA;EACA,wBAAA;EEgDH;AF/BD;EGlDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EE0ED;AFxEC;;EAEE,2BAAA;EACA,8BAAA;EE0EH;AFvEC;;EAEE,2BAAA;EACA,uBAAA;EEyEH;AFtEC;;EAEE,2BAAA;EACA,wBAAA;EEwEH;AFtDD;EGnDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EEkGD;AFhGC;;EAEE,2BAAA;EACA,8BAAA;EEkGH;AF/FC;;EAEE,2BAAA;EACA,uBAAA;EEiGH;AF9FC;;EAEE,2BAAA;EACA,wBAAA;EEgGH;AF7ED;EGpDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EE0HD;AFxHC;;EAEE,2BAAA;EACA,8BAAA;EE0HH;AFvHC;;EAEE,2BAAA;EACA,uBAAA;EEyHH;AFtHC;;EAEE,2BAAA;EACA,wBAAA;EEwHH;AF7FD;;ECbE,oDAAA;EACQ,4CAAA;EC8GT;AFvFD;;EGvEI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHsEF,2BAAA;EE6FD;AF3FD;;;EG5EI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH4EF,2BAAA;EEiGD;AFvFD;EG1FI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ECnBF,qEAAA;EJ4GA,oBAAA;EC9CA,6FAAA;EACQ,qFAAA;EC4IT;AFlGD;EG1FI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EF2CF,0DAAA;EACQ,kDAAA;ECqJT;AF/FD;;EAEE,gDAAA;EEiGD;AF7FD;EG5GI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ECnBF,qEAAA;EFgOD;AFrGD;EG5GI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EF2CF,yDAAA;EACQ,iDAAA;EC0KT;AF9GD;;EAWI,2CAAA;EEuGH;AFlGD;;;EAGE,kBAAA;EEoGD;AF1FD;EACE,+CAAA;EC3FA,4FAAA;EACQ,oFAAA;ECwLT;AFlFD;EGtJI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH8IF,uBAAA;EE8FD;AFzFD;EGvJI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH8IF,uBAAA;EEsGD;AFhGD;EGxJI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH8IF,uBAAA;EE8GD;AFvGD;EGzJI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH8IF,uBAAA;EEsHD;AFtGD;EGlKI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED2QH;AFnGD;EG5KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDkRH;AFzGD;EG7KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDyRH;AF/GD;EG9KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDgSH;AFrHD;EG/KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDuSH;AF3HD;EGhLI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED8SH;AF9HD;EGnJI,+MAAA;EACA,0MAAA;EACA,uMAAA;EDoRH;AF1HD;EACE,oBAAA;EC/IA,oDAAA;EACQ,4CAAA;EC4QT;AF3HD;;;EAGE,+BAAA;EGpME,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHkMF,uBAAA;EEiID;AFvHD;ECjKE,mDAAA;EACQ,2CAAA;EC2RT;AFjHD;EG1NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED8UH;AFvHD;EG3NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDqVH;AF7HD;EG5NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED4VH;AFnID;EG7NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDmWH;AFzID;EG9NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED0WH;AF/ID;EG/NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDiXH;AF9ID;EGvOI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHqOF,uBAAA;EC1LA,2FAAA;EACQ,mFAAA;EC+UT","sourcesContent":["\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n\n &:disabled,\n &[disabled] {\n background-color: darken(@btn-color, 12%);\n background-image: none;\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-bg, 5%); @end-color: darken(@navbar-default-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-bg; @end-color: lighten(@navbar-inverse-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255,255,255,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n// Reset the striped class because our mixins don't do multiple gradients and\n// the above custom styles override the new `.progress-bar-striped` in v3.2.0.\n.progress-bar-striped {\n #gradient > .striped();\n}\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n}\n\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They will be removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility){\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n &::-moz-placeholder { color: @color; // Firefox\n opacity: 1; } // See https://github.com/twbs/bootstrap/pull/11526\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n",null,"// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n"]} -------------------------------------------------------------------------------- /ui/static/bootstrap3/css/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.2.0 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default:disabled,.btn-default[disabled]{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-o-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#2d6ca2));background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#2b669a}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-primary:disabled,.btn-primary[disabled]{background-color:#2d6ca2;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-success:disabled,.btn-success[disabled]{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.btn-info:disabled,.btn-info[disabled]{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-warning:disabled,.btn-warning[disabled]{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.btn-danger:disabled,.btn-danger[disabled]{background-color:#c12e2a;background-image:none}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#357ebd;background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f3f3f3));background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#222 0,#282828 100%);background-image:-o-linear-gradient(top,#222 0,#282828 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#222),to(#282828));background-image:linear-gradient(to bottom,#222 0,#282828 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-o-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3071a9));background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-o-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3278b3));background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);background-repeat:repeat-x;border-color:#3278b3}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} -------------------------------------------------------------------------------- /ui/static/bootstrap3/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxiaoyang/zufang/49400b213cee2d328b9fe1363e0774655872cbeb/ui/static/bootstrap3/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /ui/static/bootstrap3/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxiaoyang/zufang/49400b213cee2d328b9fe1363e0774655872cbeb/ui/static/bootstrap3/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /ui/static/bootstrap3/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxiaoyang/zufang/49400b213cee2d328b9fe1363e0774655872cbeb/ui/static/bootstrap3/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /ui/static/css/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: "微软雅黑", Arial, sans-serif; 3 | } 4 | 5 | .header { 6 | border-bottom: 1px solid #e5e5e5; 7 | margin-bottom: 30px; 8 | } 9 | 10 | .footer { 11 | border-top: 1px solid #e5e5e5; 12 | color: #777777; 13 | margin-top: 30px; 14 | padding-top: 19px; 15 | } 16 | 17 | /* 18 | * Fancybox nav arrorws permanent 19 | */ 20 | .fancybox-nav span { 21 | visibility: visible; 22 | } 23 | -------------------------------------------------------------------------------- /ui/static/img/alipay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxiaoyang/zufang/49400b213cee2d328b9fe1363e0774655872cbeb/ui/static/img/alipay.png -------------------------------------------------------------------------------- /ui/static/img/default_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxiaoyang/zufang/49400b213cee2d328b9fe1363e0774655872cbeb/ui/static/img/default_image.png -------------------------------------------------------------------------------- /ui/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxiaoyang/zufang/49400b213cee2d328b9fe1363e0774655872cbeb/ui/static/img/favicon.ico -------------------------------------------------------------------------------- /ui/static/img/invalid_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxiaoyang/zufang/49400b213cee2d328b9fe1363e0774655872cbeb/ui/static/img/invalid_image.png -------------------------------------------------------------------------------- /ui/static/img/logo-pink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxiaoyang/zufang/49400b213cee2d328b9fe1363e0774655872cbeb/ui/static/img/logo-pink.png -------------------------------------------------------------------------------- /ui/static/img/logo-sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxiaoyang/zufang/49400b213cee2d328b9fe1363e0774655872cbeb/ui/static/img/logo-sm.png -------------------------------------------------------------------------------- /ui/static/img/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxiaoyang/zufang/49400b213cee2d328b9fe1363e0774655872cbeb/ui/static/img/logo.jpg -------------------------------------------------------------------------------- /ui/static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxiaoyang/zufang/49400b213cee2d328b9fe1363e0774655872cbeb/ui/static/img/logo.png -------------------------------------------------------------------------------- /ui/static/img/qr.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxiaoyang/zufang/49400b213cee2d328b9fe1363e0774655872cbeb/ui/static/img/qr.jpg -------------------------------------------------------------------------------- /ui/static/imgdir: -------------------------------------------------------------------------------- 1 | /home/zhy/db/imgdir/ -------------------------------------------------------------------------------- /ui/static/js/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var app = angular.module('uiApp', []); 4 | 5 | app.config(function ($routeProvider) { 6 | $routeProvider 7 | .when('/home', 8 | { 9 | controller: 'HomeController', 10 | templateUrl: '/static/partials/home.html' 11 | }) 12 | .when('/search/:query', 13 | { 14 | controller: 'SearchController', 15 | templateUrl: '/static/partials/search.html' 16 | }) 17 | .when('/search/:query/:page_num', 18 | { 19 | controller: 'SearchController', 20 | templateUrl: '/static/partials/search.html' 21 | }) 22 | .when('/empty', 23 | { 24 | controller: 'EmptyController', 25 | templateUrl: '/static/partials/empty.html' 26 | }) 27 | .when('/donate', 28 | { 29 | templateUrl: '/static/partials/donate.html' 30 | }) 31 | .when('/statistic', 32 | { 33 | templateUrl: '/static/partials/statistic.html' 34 | }) 35 | .otherwise( 36 | { 37 | redirectTo: '/home' 38 | }); 39 | }); 40 | 41 | app.filter('escape', function($window) { 42 | return $window.encodeURIComponent; 43 | }); 44 | 45 | // Handle error image 46 | app.directive('errSrc', function() { 47 | return { 48 | link: function(scope, element, attrs) { 49 | element.bind('error', function() { 50 | if (attrs.src != attrs.errSrc) { 51 | attrs.$set('src', attrs.errSrc); 52 | } 53 | }); 54 | } 55 | } 56 | }); 57 | -------------------------------------------------------------------------------- /ui/static/js/controllers.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | app.controller('NavbarController', function($scope, $routeParams, $location) { 4 | if($routeParams.query < 2 | $routeParams > 50) { 5 | $location.path('/home'); 6 | return; 7 | } 8 | 9 | $scope.$on('$routeChangeSuccess', function (event, current, previous) { 10 | $scope.query = current.pathParams.query; 11 | }); 12 | 13 | $scope.go = function(query) { 14 | $location.path(query); 15 | }; 16 | }); 17 | 18 | app.controller('HomeController', function($rootScope, $scope, $location) { 19 | $scope.go = function(query) { 20 | $location.path(query); 21 | }; 22 | 23 | $rootScope.is_homepage = function() { 24 | return true; 25 | } 26 | }); 27 | 28 | app.controller('EmptyController', function($rootScope, $scope, $location) { 29 | $scope.go = function(query) { 30 | $location.path(query); 31 | }; 32 | 33 | $rootScope.is_homepage = function() { 34 | return true; 35 | } 36 | }); 37 | 38 | app.controller('SearchController', function($rootScope, $scope, $location, $routeParams, House) { 39 | if($routeParams.query < 2 | $routeParams > 50) { 40 | $location.path('/home'); 41 | return; 42 | } 43 | 44 | House.search($routeParams.query, $routeParams.page_num, function(data) { 45 | if(!data.page_count) 46 | $location.path('empty'); 47 | $scope.query = data.query; 48 | $scope.page_count = data.page_count; 49 | $scope.page_num = data.page_num; 50 | $scope.page_next = data.page_next; 51 | $scope.page_prev = data.page_prev; 52 | $scope.houses = data.result; 53 | }); 54 | 55 | $rootScope.is_homepage = function() { 56 | return false; 57 | } 58 | }); 59 | -------------------------------------------------------------------------------- /ui/static/js/jquery.dotdotdot.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery dotdotdot 1.6.16 3 | * 4 | * Copyright (c) Fred Heusschen 5 | * www.frebsite.nl 6 | * 7 | * Plugin website: 8 | * dotdotdot.frebsite.nl 9 | * 10 | * Dual licensed under the MIT and GPL licenses. 11 | * http://en.wikipedia.org/wiki/MIT_License 12 | * http://en.wikipedia.org/wiki/GNU_General_Public_License 13 | */ 14 | !function(t,e){function n(t,e,n){var r=t.children(),o=!1;t.empty();for(var i=0,d=r.length;d>i;i++){var l=r.eq(i);if(t.append(l),n&&t.append(n),a(t,e)){l.remove(),o=!0;break}n&&n.detach()}return o}function r(e,n,i,d,l){var s=!1,c="table, thead, tbody, tfoot, tr, col, colgroup, object, embed, param, ol, ul, dl, blockquote, select, optgroup, option, textarea, script, style",u="script, .dotdotdot-keep";return e.contents().detach().each(function(){var f=this,h=t(f);if("undefined"==typeof f||3==f.nodeType&&0==t.trim(f.data).length)return!0;if(h.is(u))e.append(h);else{if(s)return!0;e.append(h),l&&e[e.is(c)?"after":"append"](l),a(i,d)&&(s=3==f.nodeType?o(h,n,i,d,l):r(h,n,i,d,l),s||(h.detach(),s=!0)),s||l&&l.detach()}}),s}function o(e,n,r,o,d){var c=e[0];if(!c)return!1;var f=s(c),h=-1!==f.indexOf(" ")?" ":" ",p="letter"==o.wrap?"":h,g=f.split(p),v=-1,w=-1,b=0,y=g.length-1;for(o.fallbackToLetter&&0==b&&0==y&&(p="",g=f.split(p),y=g.length-1);y>=b&&(0!=b||0!=y);){var m=Math.floor((b+y)/2);if(m==w)break;w=m,l(c,g.slice(0,w+1).join(p)+o.ellipsis),a(r,o)?(y=w,o.fallbackToLetter&&0==b&&0==y&&(p="",g=g[0].split(p),v=-1,w=-1,b=0,y=g.length-1)):(v=w,b=w)}if(-1==v||1==g.length&&0==g[0].length){var x=e.parent();e.detach();var T=d&&d.closest(x).length?d.length:0;x.contents().length>T?c=u(x.contents().eq(-1-T),n):(c=u(x,n,!0),T||x.detach()),c&&(f=i(s(c),o),l(c,f),T&&d&&t(c).parent().append(d))}else f=i(g.slice(0,v+1).join(p),o),l(c,f);return!0}function a(t,e){return t.innerHeight()>e.maxHeight}function i(e,n){for(;t.inArray(e.slice(-1),n.lastCharacter.remove)>-1;)e=e.slice(0,-1);return t.inArray(e.slice(-1),n.lastCharacter.noEllipsis)<0&&(e+=n.ellipsis),e}function d(t){return{width:t.innerWidth(),height:t.innerHeight()}}function l(t,e){t.innerText?t.innerText=e:t.nodeValue?t.nodeValue=e:t.textContent&&(t.textContent=e)}function s(t){return t.innerText?t.innerText:t.nodeValue?t.nodeValue:t.textContent?t.textContent:""}function c(t){do t=t.previousSibling;while(t&&1!==t.nodeType&&3!==t.nodeType);return t}function u(e,n,r){var o,a=e&&e[0];if(a){if(!r){if(3===a.nodeType)return a;if(t.trim(e.text()))return u(e.contents().last(),n)}for(o=c(a);!o;){if(e=e.parent(),e.is(n)||!e.length)return!1;o=c(e[0])}if(o)return u(t(o),n)}return!1}function f(e,n){return e?"string"==typeof e?(e=t(e,n),e.length?e:!1):e.jquery?e:!1:!1}function h(t){for(var e=t.innerHeight(),n=["paddingTop","paddingBottom"],r=0,o=n.length;o>r;r++){var a=parseInt(t.css(n[r]),10);isNaN(a)&&(a=0),e-=a}return e}if(!t.fn.dotdotdot){t.fn.dotdotdot=function(e){if(0==this.length)return t.fn.dotdotdot.debug('No element found for "'+this.selector+'".'),this;if(this.length>1)return this.each(function(){t(this).dotdotdot(e)});var o=this;o.data("dotdotdot")&&o.trigger("destroy.dot"),o.data("dotdotdot-style",o.attr("style")||""),o.css("word-wrap","break-word"),"nowrap"===o.css("white-space")&&o.css("white-space","normal"),o.bind_events=function(){return o.bind("update.dot",function(e,d){e.preventDefault(),e.stopPropagation(),l.maxHeight="number"==typeof l.height?l.height:h(o),l.maxHeight+=l.tolerance,"undefined"!=typeof d&&(("string"==typeof d||d instanceof HTMLElement)&&(d=t("
").append(d).contents()),d instanceof t&&(i=d)),g=o.wrapInner('
').children(),g.contents().detach().end().append(i.clone(!0)).find("br").replaceWith("
").end().css({height:"auto",width:"auto",border:"none",padding:0,margin:0});var c=!1,u=!1;return s.afterElement&&(c=s.afterElement.clone(!0),c.show(),s.afterElement.detach()),a(g,l)&&(u="children"==l.wrap?n(g,l,c):r(g,o,g,l,c)),g.replaceWith(g.contents()),g=null,t.isFunction(l.callback)&&l.callback.call(o[0],u,i),s.isTruncated=u,u}).bind("isTruncated.dot",function(t,e){return t.preventDefault(),t.stopPropagation(),"function"==typeof e&&e.call(o[0],s.isTruncated),s.isTruncated}).bind("originalContent.dot",function(t,e){return t.preventDefault(),t.stopPropagation(),"function"==typeof e&&e.call(o[0],i),i}).bind("destroy.dot",function(t){t.preventDefault(),t.stopPropagation(),o.unwatch().unbind_events().contents().detach().end().append(i).attr("style",o.data("dotdotdot-style")||"").data("dotdotdot",!1)}),o},o.unbind_events=function(){return o.unbind(".dot"),o},o.watch=function(){if(o.unwatch(),"window"==l.watch){var e=t(window),n=e.width(),r=e.height();e.bind("resize.dot"+s.dotId,function(){n==e.width()&&r==e.height()&&l.windowResizeFix||(n=e.width(),r=e.height(),u&&clearInterval(u),u=setTimeout(function(){o.trigger("update.dot")},100))})}else c=d(o),u=setInterval(function(){if(o.is(":visible")){var t=d(o);(c.width!=t.width||c.height!=t.height)&&(o.trigger("update.dot"),c=t)}},500);return o},o.unwatch=function(){return t(window).unbind("resize.dot"+s.dotId),u&&clearInterval(u),o};var i=o.contents(),l=t.extend(!0,{},t.fn.dotdotdot.defaults,e),s={},c={},u=null,g=null;return l.lastCharacter.remove instanceof Array||(l.lastCharacter.remove=t.fn.dotdotdot.defaultArrays.lastCharacter.remove),l.lastCharacter.noEllipsis instanceof Array||(l.lastCharacter.noEllipsis=t.fn.dotdotdot.defaultArrays.lastCharacter.noEllipsis),s.afterElement=f(l.after,o),s.isTruncated=!1,s.dotId=p++,o.data("dotdotdot",!0).bind_events().trigger("update.dot"),l.watch&&o.watch(),o},t.fn.dotdotdot.defaults={ellipsis:"... ",wrap:"word",fallbackToLetter:!0,lastCharacter:{},tolerance:0,callback:null,after:null,height:null,watch:!1,windowResizeFix:!0},t.fn.dotdotdot.defaultArrays={lastCharacter:{remove:[" "," ",",",";",".","!","?"],noEllipsis:[]}},t.fn.dotdotdot.debug=function(){};var p=1,g=t.fn.html;t.fn.html=function(n){return n!=e&&!t.isFunction(n)&&this.data("dotdotdot")?this.trigger("update",[n]):g.apply(this,arguments)};var v=t.fn.text;t.fn.text=function(n){return n!=e&&!t.isFunction(n)&&this.data("dotdotdot")?(n=t("
").text(n).html(),this.trigger("update",[n])):v.apply(this,arguments)}}}(jQuery); -------------------------------------------------------------------------------- /ui/static/js/services.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | app.factory('House', function($http) { 4 | var debug = false; 5 | 6 | if(debug) var api = 'http://127.0.0.1:8090/apis'; 7 | else var api = 'http://182.92.159.73/apis'; 8 | 9 | return { 10 | search: function(query, page_num, callback) { 11 | var uri = api + '/search/' + query; 12 | if(page_num == undefined) uri += '/1'; 13 | else uri += '/' + page_num; 14 | return $http.get(uri).success(callback); 15 | }, 16 | }; 17 | }); 18 | -------------------------------------------------------------------------------- /ui/static/partials/donate.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
    6 |
  • 找新窝旨在给北漂ers提供一种新的找房方式,豆瓣租房小组便是极好的数据来源了。
  • 7 |
  • 这种方式的成本比较低,找到的房东、合租者相对靠谱些,性价比很高。
  • 8 |
  • 我们喜欢豆瓣,喜欢小清新,拒绝广告,拒绝获取用户信息。
  • 9 |
  • 但也真是囊中羞涩,穷学生党。域名、服务器是一笔不小的开支。
  • 10 |
  • 如果找新窝帮到了您,希望您能够捐助我们,帮助找新窝走的更远!
  • 11 |
  • 我们会在官网(zhaoxinwo.com)列出所有的捐助者及资金流向,给大家提供更好的使用体验。
  • 12 |
  • 您可以点击以下按钮 或 扫描下方二维码 来捐助我们~请注明捐助找新窝,谢谢!
  • 13 |
14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 |
24 | 25 |
26 |
27 |
28 |
29 |
30 | -------------------------------------------------------------------------------- /ui/static/partials/empty.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 |

7 | 不要气馁,换个关键词再搜! 8 |

9 |
10 |
11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | -------------------------------------------------------------------------------- /ui/static/partials/error.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 |

7 | 这是一个未探索的地带... 8 |

9 |
10 |
11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | -------------------------------------------------------------------------------- /ui/static/partials/home.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 |

7 | 漂着的家儿,梦着的人儿~ 下载手机版 8 |

9 |
10 |
11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | -------------------------------------------------------------------------------- /ui/static/partials/search.html: -------------------------------------------------------------------------------- 1 |
2 | 疯狂加载中... 3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | {{($index+1)+(page_num-1)*5}}. {{house.title}} {{house.sim.length}}条相似内容 11 | {{house.pub_time}} 12 |
13 |
14 |
15 |
16 |
17 |
18 | [相似内容] {{sim.1}} 19 | {{sim.3}} 20 |
21 |
22 |
23 |
{{house.text}}
24 |
25 |
26 |

{{dizhi}}

27 |

{{ditie}}

28 |

{{house.jushi}}

29 |

{{house.shouji}}

30 |

{{house.zujin}}

31 |

{{link}}

32 |

33 |

{{house.confidence}}

34 |
35 |
36 |
37 |
38 |
39 | 上一页 40 |
41 |
42 | 下一页 43 |
44 |
45 |
46 | -------------------------------------------------------------------------------- /ui/static/partials/statistic.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 敬请期待... 6 |
7 |
8 |
9 |
10 | 15 | -------------------------------------------------------------------------------- /ui/templates/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 找新窝 6 | 7 | 8 | {% load staticfiles %} 9 | 10 | 11 | 12 | 13 | 22 | 23 | 24 |
25 |
26 |
27 |
28 | 29 |
30 | {% verbatim %} 31 |
32 |
33 | 34 | 35 | 36 | 37 |
38 |
39 | {% endverbatim %} 40 |
41 |
42 |
43 | 46 | 47 |
48 | 49 | 50 | 51 | 52 | 53 | 54 |
55 | 56 |
57 | {% load staticfiles %} 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /ui/templates/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 找新窝 6 | 7 | 8 | {% load staticfiles %} 9 | 10 | 11 | 12 | 13 | 22 | 23 | 24 |
25 |
26 |
27 |
28 | 29 |
30 | {% verbatim %} 31 |
32 |
33 | 34 | 35 | 36 | 37 |
38 |
39 | {% endverbatim %} 40 |
41 |
42 |
43 | 46 | 47 |
48 | 49 | 50 | 51 | 52 | 53 | 54 |
55 | 56 |
57 | {% load staticfiles %} 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /ui/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 找新窝 6 | 7 | 8 | 9 | 17 | {% load staticfiles %} 18 | 19 | 20 | 21 | 22 | 31 | 32 | 33 |
34 |
35 |
36 |
37 | 38 |
39 | {% verbatim %} 40 |
41 |
42 | 43 | 44 | 45 | 46 |
47 |
48 | {% endverbatim %} 49 |
50 |
51 |
52 | 55 | 56 |
57 | 58 | 59 | 60 | 61 | 62 | 63 |
64 | 65 |
66 | {% load staticfiles %} 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /ui/ui/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxiaoyang/zufang/49400b213cee2d328b9fe1363e0774655872cbeb/ui/ui/__init__.py -------------------------------------------------------------------------------- /ui/ui/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for ui project. 3 | 4 | For more information on this file, see 5 | https://docs.djangoproject.com/en/1.6/topics/settings/ 6 | 7 | For the full list of settings and their values, see 8 | https://docs.djangoproject.com/en/1.6/ref/settings/ 9 | """ 10 | 11 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 12 | import os 13 | BASE_DIR = os.path.dirname(os.path.dirname(__file__)) 14 | 15 | # Connect MongoDB 16 | from mongoengine import connect 17 | MONGO_DB_NAME = 'zufang' 18 | MONGO_CO_NAME = 'house' 19 | connect(MONGO_DB_NAME) 20 | 21 | # Quick-start development settings - unsuitable for production 22 | # See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/ 23 | 24 | # SECURITY WARNING: keep the secret key used in production secret! 25 | SECRET_KEY = '+)c*ihe7+mzmlt^qk-u4j2gode&t8j-$f)#sg30$s5&^a1u71i' 26 | 27 | # SECURITY WARNING: don't run with debug turned on in production! 28 | DEBUG = False 29 | 30 | TEMPLATE_DEBUG = DEBUG 31 | 32 | ALLOWED_HOSTS = ['182.92.159.73'] 33 | 34 | 35 | # Application definition 36 | 37 | INSTALLED_APPS = ( 38 | 'django.contrib.admin', 39 | 'django.contrib.auth', 40 | 'django.contrib.contenttypes', 41 | 'django.contrib.sessions', 42 | 'django.contrib.messages', 43 | 'django.contrib.staticfiles', 44 | 'app', 45 | ) 46 | 47 | MIDDLEWARE_CLASSES = ( 48 | 'django.contrib.sessions.middleware.SessionMiddleware', 49 | 'django.middleware.common.CommonMiddleware', 50 | 'django.middleware.csrf.CsrfViewMiddleware', 51 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 52 | 'django.contrib.messages.middleware.MessageMiddleware', 53 | #'django.middleware.clickjacking.XFrameOptionsMiddleware', # allow iframe 54 | ) 55 | 56 | ROOT_URLCONF = 'ui.urls' 57 | 58 | WSGI_APPLICATION = 'ui.wsgi.application' 59 | 60 | 61 | # Database 62 | # https://docs.djangoproject.com/en/1.6/ref/settings/#databases 63 | 64 | DATABASES = { 65 | 'default': { 66 | 'ENGINE': '', 67 | 'NAME': '', 68 | } 69 | } 70 | 71 | # Internationalization 72 | # https://docs.djangoproject.com/en/1.6/topics/i18n/ 73 | 74 | LANGUAGE_CODE = 'en-us' 75 | 76 | # Use system time 77 | TIME_ZONE = 'Asia/Shanghai' 78 | 79 | USE_I18N = True 80 | 81 | USE_L10N = True 82 | 83 | USE_TZ = False 84 | 85 | 86 | # Static files (CSS, JavaScript, Images) 87 | # https://docs.djangoproject.com/en/1.6/howto/static-files/ 88 | 89 | STATIC_URL = '/static/' 90 | 91 | STATICFILES_DIRS = ( 92 | BASE_DIR + '/static', 93 | ) 94 | 95 | if DEBUG == False: 96 | STATIC_ROOT = BASE_DIR + '/static' 97 | 98 | TEMPLATE_DIRS = ( 99 | os.path.join(BASE_DIR , 'templates').replace('\\','/'), 100 | ) 101 | 102 | -------------------------------------------------------------------------------- /ui/ui/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, include, url 2 | 3 | #from django.contrib import admin 4 | #admin.autodiscover() 5 | 6 | urlpatterns = patterns('', 7 | # Examples: 8 | # url(r'^$', 'ui.views.home', name='home'), 9 | # url(r'^blog/', include('blog.urls')), 10 | url(r'', include('app.urls')), 11 | #url(r'^admin/', include(admin.site.urls)), 12 | ) 13 | -------------------------------------------------------------------------------- /ui/ui/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for ui project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ui.settings") 12 | 13 | from django.core.wsgi import get_wsgi_application 14 | application = get_wsgi_application() 15 | -------------------------------------------------------------------------------- /uwsgi/dependencies: -------------------------------------------------------------------------------- 1 | sudo apt-get install uwsgi uwsgi-core uwsgi-plugin-python 2 | sudo apt-get install python-dev 3 | sudo apt-get install libpcre3 libpcre3-dev 4 | -------------------------------------------------------------------------------- /uwsgi/nginx.conf: -------------------------------------------------------------------------------- 1 | http { 2 | include /etc/nginx/mime.types; 3 | upstream django { 4 | server 127.0.0.1:8091; # for a web port socket (we'll use this first) 5 | } 6 | 7 | server { 8 | listen 80; 9 | server_name zhaoxinwo.com; 10 | server_name 182.92.159.73; 11 | charset utf-8; 12 | 13 | # max upload size 14 | #client_max_body_size 75M; # adjust to taste 15 | 16 | location /static/ { 17 | alias /home/zhy/zufang/ui/static/; # your Django project's static files - amend as required 18 | } 19 | 20 | location / { 21 | include /home/zhy/zufang/uwsgi/uwsgi_params; # the uwsgi_params file you installed 22 | uwsgi_pass django; 23 | } 24 | } 25 | } 26 | 27 | events { 28 | } 29 | -------------------------------------------------------------------------------- /uwsgi/run_server.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | uwsgi --ini uwsgi.ini 4 | -------------------------------------------------------------------------------- /uwsgi/uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | chdir = /home/zhy/zufang/ui 3 | module = ui.wsgi:app 4 | socket = :8091 5 | wsgi-file = /home/zhy/zufang/ui/ui/wsgi.py 6 | home = /home/zhy/zufang/env 7 | master = true 8 | vacuum = true 9 | -------------------------------------------------------------------------------- /uwsgi/uwsgi_params: -------------------------------------------------------------------------------- 1 | uwsgi_param QUERY_STRING $query_string; 2 | uwsgi_param REQUEST_METHOD $request_method; 3 | uwsgi_param CONTENT_TYPE $content_type; 4 | uwsgi_param CONTENT_LENGTH $content_length; 5 | 6 | uwsgi_param REQUEST_URI $request_uri; 7 | uwsgi_param PATH_INFO $document_uri; 8 | uwsgi_param DOCUMENT_ROOT $document_root; 9 | uwsgi_param SERVER_PROTOCOL $server_protocol; 10 | uwsgi_param HTTPS $https if_not_empty; 11 | 12 | uwsgi_param REMOTE_ADDR $remote_addr; 13 | uwsgi_param REMOTE_PORT $remote_port; 14 | uwsgi_param SERVER_PORT $server_port; 15 | uwsgi_param SERVER_NAME $server_name; 16 | -------------------------------------------------------------------------------- /zhaoxinwo-android.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxiaoyang/zufang/49400b213cee2d328b9fe1363e0774655872cbeb/zhaoxinwo-android.gif -------------------------------------------------------------------------------- /zhaoxinwo-web.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangxiaoyang/zufang/49400b213cee2d328b9fe1363e0774655872cbeb/zhaoxinwo-web.gif --------------------------------------------------------------------------------