From 1fb57e68778e252c47914b98ee4128a6fd980027 Mon Sep 17 00:00:00 2001 From: chen jinqian Date: Fri, 29 Mar 2024 10:08:42 +0800 Subject: [PATCH] first commit --- .idea/.gitignore | 3 + .idea/misc.xml | 8 + .idea/modules.xml | 8 + .idea/redis-manager-config.xml | 6 + .idea/vcs.xml | 6 + PyGuoyan.iml | 9 + SYgcg.py | 14 + __pycache__/crawler.cpython-310.pyc | Bin 0 -> 19733 bytes __pycache__/gymailer.cpython-310.pyc | Bin 0 -> 915 bytes __pycache__/properties.cpython-310.pyc | Bin 0 -> 1958 bytes cert.crt | 21 + config.ini | 5 + crawler.py | 714 ++++++++ dbsearch.py | 137 ++ gycrawler.py | 59 + gymailer.py | 44 + jdbc.properties | 46 + main.py | 75 + myrec.db | Bin 0 -> 12288 bytes properties.py | 72 + splash/SYgcg.py | 14 + splash/__init__.py | 0 splash/__pycache__/SYgcg.cpython-310.pyc | Bin 0 -> 677 bytes splash/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 132 bytes splash/__pycache__/gysplash.cpython-310.pyc | Bin 0 -> 3187 bytes splash/config/splash.cnf | 7 + splash/config/splash.json | 20 + splash/configscripts/main.lua | 1 + splash/gysplash.py | 122 ++ splash/scripts/main.lua | 75 + splash/scripts/modules/jquery-3.7.1.min.js | 2 + splash/scripts/modules/parser.lua | 28 + splash/scripts/modules/ygcg.js | 32 + splash/scripts/modules/zepto.js | 1650 +++++++++++++++++++ splash/scripts/modules/zepto.js.1 | 1650 +++++++++++++++++++ 35 files changed, 4828 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/redis-manager-config.xml create mode 100644 .idea/vcs.xml create mode 100644 PyGuoyan.iml create mode 100644 SYgcg.py create mode 100644 __pycache__/crawler.cpython-310.pyc create mode 100644 __pycache__/gymailer.cpython-310.pyc create mode 100644 __pycache__/properties.cpython-310.pyc create mode 100644 cert.crt create mode 100644 config.ini create mode 100644 crawler.py create mode 100644 dbsearch.py create mode 100644 gycrawler.py create mode 100644 gymailer.py create mode 100644 jdbc.properties create mode 100644 main.py create mode 100644 myrec.db create mode 100644 properties.py create mode 100644 splash/SYgcg.py create mode 100644 splash/__init__.py create mode 100644 splash/__pycache__/SYgcg.cpython-310.pyc create mode 100644 splash/__pycache__/__init__.cpython-310.pyc create mode 100644 splash/__pycache__/gysplash.cpython-310.pyc create mode 100644 splash/config/splash.cnf create mode 100644 splash/config/splash.json create mode 100644 splash/configscripts/main.lua create mode 100644 splash/gysplash.py create mode 100644 splash/scripts/main.lua create mode 100644 splash/scripts/modules/jquery-3.7.1.min.js create mode 100644 splash/scripts/modules/parser.lua create mode 100644 splash/scripts/modules/ygcg.js create mode 100644 splash/scripts/modules/zepto.js create mode 100644 splash/scripts/modules/zepto.js.1 diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..62b0f33 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..b5c8d00 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/redis-manager-config.xml b/.idea/redis-manager-config.xml new file mode 100644 index 0000000..78aa62b --- /dev/null +++ b/.idea/redis-manager-config.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/PyGuoyan.iml b/PyGuoyan.iml new file mode 100644 index 0000000..49554c9 --- /dev/null +++ b/PyGuoyan.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/SYgcg.py b/SYgcg.py new file mode 100644 index 0000000..9d1b054 --- /dev/null +++ b/SYgcg.py @@ -0,0 +1,14 @@ +#!/usr/bin/python3 +from splash.gysplash import SBase +import json + +class SYgcg(SBase): + def open(self): + return super().open('ygcg', pages=2, annoucement_type='政府采购') + +if __name__ == '__main__': + test = SYgcg() + r = test.open() + + results = json.loads(r.text) + print(results) \ No newline at end of file diff --git a/__pycache__/crawler.cpython-310.pyc b/__pycache__/crawler.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6d7618d63e1466cdd8d72c7fd37bc29ebcd3860e GIT binary patch literal 19733 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 JYN_tz{{`TlaaaHV literal 0 HcmV?d00001 diff --git a/__pycache__/gymailer.cpython-310.pyc b/__pycache__/gymailer.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8c80c31dd7d5bb772b40773fbcb4950994966396 GIT binary patch literal 915 zcmY*X&1(}u6rcT`d{m{@Vilx#ThIh8h=(EtZLQkW&;+e}S+<#Jx^X|!*^M?~1FbDy zM8unVO2CU3?MXyI{|1lF)z;dxH&4FVhEivFzkRy?yroJiW^NyHqj^)}xOA&DU8QR===v;m2xT>>>TqGuL`By@qBQ^_byXsF zwHPG|QHZ*!boE$Dpps2F(TO&RfJp3u{p&lO?q8GR%=t{^iz-^oXQ+$>zWe5FteefPVB5Z9WX;|3kA6)#`B%GDVb z`dqGt+^Dpc8nhPk6VnTe4`yyJ%-tzht2Y+!&zcI)EQ6cv5W+Z)!&Hg5;zxB8GZ}hh z3II36X`Z{paivr(+m*^3*SxUq1{_B;Aim>zJmW-m6f-xdb9J@l#wO;v*rbq|(HeCh zfo4R5S`42?kyEEUCsNxHWnw#%l4i(amODK6?o#6&Vq?Jnju-tPE|Q{4s8cMrZ??j= z6BO%hQ2=FyW*Z8GBTGQVO+_OBs;nw`<(MSCJZPgJ?5xO+Z5sju+wP1s++fvp0=u?C zgQ>w(JEsTMLTZhe8;fBVYC-E9gqPd#N*GM+zIeI6zOn!0{mz$-JLn?mD}! zYwL_E67hG~5)#Tgf6czaOW%2_kYMJVq%QQVo!y77FJDEfft*0a=(FkKdr*`bY^F_DEV&JEO*i@) zhxrwWWygFbDn92XQhdrQUa`c>7*aXevwp>nJta=WR8-;{_QTDoS9!Bw&gwZ--kdA> zSi%>`jg*gGXw@M8R8~?2*BEJ|7uw0iZl68b`kv)2$!t9SjY(+OMVA9Ug0JG=mpJqZBZB}%hWz{fqs@5Yh0t3 z^>vb`1MT7^Yl+dxoo_5;rIWoZS1vX-1#3nbTKlH#XVx{oeb&{b%?ecQ_6wuifs;n} zdq6RCey{c-`&q7$Z^1aO&lp@KP&f7lx!qHHnbPUrz46^)F;4TnR}gl~v5S%<%QKrK zD`;VEB54ZA0}*h+n>@nbRUY$gE}qN3TfXGcbMa5pn{2*H?(T($*Ro6*r%`8_pi)+k z*;9<=89zMZKH>LH>2z81fYJ$;Q&D=VHgYRHhdntuK$I zAY2>^F&$s=YY3nc_Zhs4LU<2J+p9sq`?z+iO83%X-zHDf{!srHllM^D4^hq3HH>kQ ze9~INgyR39@ln4H!Yy1>Vu50xSqcXhz2aMlN(rPm@OjGff|G|6@6PTmkZ5*<7%5(E z9dy}GyE-{f;<&DY*KXjy8F@LhpP&ar?qa_4I&KsmwmE!&vUW%%LB*ORE>4m`p@vw! ziEAdwlVRFlNMIXPfl>n$51_hP3Kj((D2qV3Xy7nZ0uhTuv>AI%zvdrx3CzVu_oJ}Z zvHA-amd!Xma%sh}HTJ#%~Mx(*PfBSozo-u1}*Xm_=2D+PAA{ z)|j(dOs&A&R&pAm)e2UGK)HvSa@Ith)j9g$?8$Z&nuE%N1L7;6@^K-n{8@`y0ZP_X zK-#!kM|6!PbU#`#yFxfQt8s>iGp=GhqfuMLmp*D=)K=_23rADf-LusgkCn5*`ti>w}$Byg)oxGErp@d0iD|1B6qL?{K& zMB)T!7j}z5N&11&DRdvfDv8%f?3v*M=Z_$>DAjqlP#QK!fIUY)b`o@|TmX7dJk`!G zAwyPqM$u$kS(uu<6p@(!k7R6 literal 0 HcmV?d00001 diff --git a/cert.crt b/cert.crt new file mode 100644 index 0000000..f4ce4ca --- /dev/null +++ b/cert.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw +MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B +AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz +yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE +38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP +AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad +DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME +HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- diff --git a/config.ini b/config.ini new file mode 100644 index 0000000..a4079c0 --- /dev/null +++ b/config.ini @@ -0,0 +1,5 @@ +[database] +host = localhost +database = guoyantest +user = root +password = Guoyan83086775 diff --git a/crawler.py b/crawler.py new file mode 100644 index 0000000..9a2fe76 --- /dev/null +++ b/crawler.py @@ -0,0 +1,714 @@ +#!/usr/bin/python3 +""" +=========================================================================================== +这是一个用于爬取采购信息的模块 +要处理采购公告信息。主要涉及sc_cggg, calalog, catalogdata, readlog四张表 +=========================================================================================== +class Crawler: + def __init__(self, connect): + def generate_id(self): + def write_log_information(self, data_id, catalog_name): + def CrawlPage_gzw_ningbo(self, page): # 宁波国资委市属国企招标投标信息 + def CrawlPage_zjcs_nbxzfw(self, type, page): # 宁波市中介超市 + def CrawlPage_ygcg_nbcqjy_org(self, page): # 宁波市阳光采购 + def CrawlPage_zfcg_czt_zj(self, page): # 浙江政府采购网 + def CrawlPage_cbbidding(self, page): # 宁波中基国际招标有限公司 + def CrawlPage_zmeetb(self, page): # 浙江国际招标有限公司 + def CrawlPage_nbbidding(self, page): # 宁波国际招标有限公司 +============================================================================================ +""" + +import datetime +import hashlib +import pymysql +import json +import random +from requests_html import HTMLSession +from requests_html import HTML, UserAgent +import gymailer +import time + +''' +============================================================ + 这个类用来封装splash服务 + 其中: + self.splash_ip 参数是splash服务的ip +============================================================ +''' + +class Splash: + def __init__(self): + self.splash_ip = '127.0.0.1' + + ''' + ============================================================ + wait_for参数用来制定需要等待的元素,只有该元素渲染完成,程序才能染回,否则将等待200秒。wait_for 参数采购选择器的方式,如 + 如制定元素id, 采用“#app"形式,如制定元素class, 采用 '.class-name'形式。 + ============================================================ + ''' + def post(self, url, wait_for, pages=1, page_element='', headers={'content-type':'application/json','Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8'}): + lua_scripts = """ +function wait_for_element(splash, css, maxwait) + -- Wait until a selector matches an element + -- in the page. Return an error if waited more + -- than maxwait seconds. + if maxwait == nil then + maxwait = 10 + end + return splash:wait_for_resume(string.format([[ + function main(splash) { + var selector = '%s'; + var maxwait = %s; + var end = Date.now() + maxwait*1000; + + function check() { + if(document.querySelector(selector)) { + splash.resume('Element found'); + } else if(Date.now() >= end) { + var err = 'Timeout waiting for element'; + splash.error(err + " " + selector); + } else { + setTimeout(check, 200); + } + } + check(); + } + ]], css, maxwait)) +end + +function main(splash, args) + pages = """ + str(pages) + """ + page_element = '""" + page_element + """' + wait_for = '""" + wait_for + """' + splash:go('""" + url + """') + wait_for_element(splash, wait_for) + wait_for_element(splash, page_element) + + -- 将第一页的结果加入返回结果集中 + results = {splash.html()} + + if pages == 1 then + return results + else + -- 执行翻页动作 + -- 先页面上的翻页元件(element),然后发送点击事件(click())翻页 + for i = 2, pages do + -- js 中是javascript脚本,用于获取翻页的元件,并发送click事件 + js = string.format("document.querySelector('%s').click();", page_element) + + -- 执行翻页脚本 + splash:runjs(js) + + -- 等待页面加载完成 + wait_for_element(splash, wait_for) + wait_for_element(splash, page_element) + + -- 这个地方看来必须加上延时,否则页面加载不完全,可能还没有完成页面更新 + assert(splash:wait(5)) + + -- 将页面加入返回结果集中 + table.insert(results, splash.html()) + end + return results + end +end + """ + + splash_url = 'http://' + self.splash_ip + ':8050/execute' + data = json.dumps({'lua_source':lua_scripts}) + r = HTMLSession().post(splash_url, headers=headers, data=data) + return r + + +class Crawler: + def __init__(self, connect): + self.connect = connect + + def generate_id(self): + # 用于生成一个32位的ID号 + current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + str(random.randint(0, 1000000)) + md5_hash = hashlib.md5() + md5_hash.update(current_time.encode('utf-8')) + return md5_hash.hexdigest() + + def write_log_information(self, data_id, catalog_name, log_type='采购公告'): + # 添加了一条信息,需要同步更新其他相关信息, 包含对话框信息和日志信息两项 + with self.connect.cursor() as cursor: + affected_row = cursor.execute("select id from catalog where name = '%s'" % (log_type)) + if affected_row == 0: + return False + + result = cursor.fetchall() + catalog_id = result[0][0] + catalogdata_id = self.generate_id() + readlog_id = self.generate_id() + + affected_row = cursor.execute("SELECT staffid FROM userinfo where username = 'root'") + if affected_row == 0: + return False + + result = cursor.fetchall() + staff_id = result[0][0] + add_date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + affected_row = cursor.execute( + 'insert into catalogdata (id, dataid, catalogid, creatorid, menderid, adddate, modifydate, datastatus) values (%s, %s, %s, %s, %s, %s, %s, %s)', + (catalogdata_id, data_id, catalog_id, staff_id, staff_id, add_date, add_date, 0)) + + cursor.execute( + 'insert into readlog (id, dataid, staffid, readnum, adddate, LastAccessDate, resid) values (%s, %s, %s, %s, %s, %s, %s)', + (readlog_id, data_id, staff_id, 1, datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), catalog_id)) + + return True + + + def write_information(self, title, url, region, publishTime, announcementType): + # 用于将一条信息写入数据库中 + with self.connect.cursor() as cursor: + cggg_id = self.generate_id() + + + try: + title = title.replace("'", "\\\'") + affected_rows = cursor.execute( + 'insert into sc_cggg (id, bt, lj, ssqy, fbsj, gglb) values (%s, %s, %s, %s, %s, %s)', + (cggg_id, title, url, region, publishTime, announcementType)) + except pymysql.err.IntegrityError: + print('信息重复') + self.connect.rollback() + return False + else: + if self.write_log_information(cggg_id, announcementType): + self.connect.commit() + else: + print('添加采购信息失败') + self.connect.rollback() + return False + + return True + + def write_information_cgyx(self, cgyx): + # 用于将一条信息写入数据库中 + + with self.connect.cursor() as cursor: + cgyx_id = self.generate_id() + cgyx['cgxmmc'] = cgyx['cgxmmc'].replace("'", "\\\'") + strSql = 'insert into sc_cgyx (id, cgxmmc, lj, cgxqqk, ysje, yjcgsj, ly) values (\''+cgyx_id+'\',\''+cgyx['cgxmmc']+'\',\''+cgyx['lj']+'\',\''+cgyx['cgxqqk']+'\',\''+cgyx['ysje']+'\',\''+cgyx['yjcgsj']+'\',\''+cgyx['ly']+'\')' + try: + affected_rows = cursor.execute(strSql) + except pymysql.err.IntegrityError: + print('信息重复') + #self.connect.rollback() + return False + else: + if self.write_log_information(cgyx_id, '采购意向'): + self.connect.commit() + else: + print('添加采购信息失败') + self.connect.rollback() + return False + + return True + + def Check(self): + with self.connect.cursor() as cursor: + affected_row = cursor.execute("select id as total from sc_cggg where date(fbsj) > (NOW() - INTERVAL 1 DAY);") + if affected_row == 0: + gymailer.SendMail('jinqian_chen@126.com', 'jinqian.chen@srit.com.cn', '爬虫警告信息', '采购信息提取不正常,请检查!') + return False + else: + return True + + + def Crawl(self): + # 这个方法是实际完成爬取工作的总入口。 + + # 爬取浙江政采网的信息 + print('开始获取浙江政采网的信息\n') + + # 定义要传递进去的关于公告信息类型的数据结构 + infoType = [ + {"announcementCode": "110-175885", "announcementType":"采购意向"}, + {"announcementCode": "110-978863", "announcementType":"采购公告"}, + {"announcementCode": "110-943756", "announcementType":"更正公告"}, + {"announcementCode": "110-420383", "announcementType":"非政府采购公告"}, + {"announcementCode": "110-900461", "announcementType":"结果公告"} + ] + for typeParam in infoType: + for page in range(1, 11): + try: + self.CrawlPage_zfcg_czt_zj(page, typeParam) + except Exception as e: + print('3--------------------------------', e) + + # 爬取宁波市阳光采购网的信息 + print('开始获取宁波市阳光采购网的信息\n') + infoType = [ + {"announcementCode": "21", "announcementType":"采购公告"}, + {"announcementCode": "23", "announcementType":"更正公告"}, + {"announcementCode": "22", "announcementType":"结果公告"} + ] + for typeParam in infoType: + try: + self.CrawlPage_ygcg_nbcqjy_org(2, typeParam) + except Exception as e: + print('4--------------------------------', e) + + # 爬取宁波市中介超市网的信息 + print('开始获取宁波市中介超市网的信息\n') + infoType = [ + {"announcementCode": '1', "announcementType":"项目需求公告"}, + {"announcementCode": '2', "announcementType":"结果公告"} + ] + + for typeParam in infoType: + for page in range(1, 6): + try: + self.CrawlPage_zjcs_nbxzfw(page, typeParam) + except Exception as e: + print('5------------------------------', e) + + # 爬取宁波市国资委市属企业采购信息 + print('开始获取宁波市国资委市属企业招投标网的信息\n') + for page in range(1, 5): + try: + self.CrawlPage_gzw_ningbo(page) + except Exception as e: + print('6------------------------------', e) + + # 爬取宁波中基国际招标网的信息 + print('开始获取宁波中基国际招标网的信息\n') + infoType = [ + {"announcementCode": "22", "announcementType":"采购公告"}, + {"announcementCode": "23", "announcementType":"结果公告"} + ] + + for typeParam in infoType: + for page in range(1, 6): + try: + self.CrawlPage_cbbidding(page, typeParam) + except Exception as e: + print('7--------------------------------', e) + + # 爬取浙江国际招标网的信息 + print('开始获取浙江国际招标网的信息\n') + infoType = [ + {"announcementCode": "Zbgg", "announcementType":"采购公告"}, + {"announcementCode": "Gzgg", "announcementType":"更正公告"}, + {"announcementCode": "jggg", "announcementType":"结果公告"} + ] + + for typeParam in infoType: + for page in range(1, 5): + try: + self.CrawlPage_zmeetb(page, typeParam) + except Exception as e: + print('8----------------------------', e) + + + # 爬取宁波市国际招标有限公司网站 + print('开始获取宁波国际招标网的信息\n') + + # 定义要传递进去的关于公告信息类型的数据结构 + infoType = [ + {"announcementCode": "1", "announcementType":"采购公告"}, + {"announcementCode": "1", "announcementType":"结果公告"}, + {"announcementCode": "2", "announcementType":"采购公告"}, + {"announcementCode": "2", "announcementType":"结果公告"} + ] + for typeParam in infoType: + for page in range(1, 5): + try: + self.CrawlPage_nbbidding(page, typeParam) + except Exception as e: + print('9--------------------------------', e) + + # 爬取宁波名诚招标代理有限公司网站 + print('开始获取宁波名城招标的信息\n') + + # 定义要传递进去的关于公告信息类型的数据结构 + infoType = [ + {"announcementCode": "99", "announcementType":"采购公告"}, + {"announcementCode": "88", "announcementType":"结果公告"} + ] + for typeParam in infoType: + for page in range(1, 2): + try: + self.CrawlPage_nbmcbidding(page, typeParam) + except Exception as e: + print('10--------------------------------', e) + + + # 宁波中基国际招标有限公司 https://www.cbbidding.com/ + def CrawlPage_cbbidding(self, page, typeParam): + # 这个方法是实际爬取指定页面的信息。 + session = HTMLSession() + session.DEFAULT_RETRIES = 5 + url = 'https://www.cbbidding.com/Index/cms.html?mid=' +typeParam['announcementCode'] + '&%2FIndex%2Fcms%2Fmid%2F' + typeParam['announcementCode'] + '_html=&page=' + str(page) + + headers = { + "Accept": "application/json, text/javascript, */*; q=0.01", + "Accept-Encoding": "gzip, deflate", + "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", + "Connection": "keep-alive", + "DNT": '1', + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36 HBPC/12.1.3.306" + } + + + # 这个网站返回的是一个网页,所以需要进行网页解析 + r = session.get(url = url, headers = headers) + + if r.status_code != 200: + if page == 1: + gymailer.SendMail('jinqian_chen@126.com', 'jinqian.chen@srit.com.cn', '爬虫警告信息:宁波中基国际招标网', r.text) + return False + + # 注意:xpath 函数返回的是list对象, 对象的元素是element + data = r.html.xpath('/html/body/div[3]/div[3]/div[2]/div[2]/div/ul/li') + for item in data: + title = item.xpath('//a')[0].text + url = 'https://www.cbbidding.com' + item.xpath('//a')[0].attrs.get('href') + region = '中基招标' + publishDate = item.xpath('//div')[0].text + + try: + publishDate = str(datetime.datetime.strptime(publishDate, '%Y-%m-%d')) + except Exception as e: + publishDate = publishDate.replace('.', '-') + publishDate = str(datetime.datetime.strptime(publishDate, '%Y-%m-%d')) + + print(url, title) + announcementType = typeParam['announcementType'] + #print(title, url, region, publishDate, announcementType) + self.write_information(title, url, region, publishDate, announcementType) + + + # 浙江国际招投标有限公司 https://www.zmeetb.com/ + def CrawlPage_zmeetb(self, page, typeParam): + # 这个方法是实际爬取指定页面的信息。 + session = HTMLSession() + url = 'https://www.zmeetb.com/' +typeParam['announcementCode'] + '/index/p/' + str(page) + '.html' + + headers = { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", + "Accept-Encoding": "gzip, deflate, br", + "Cache-Control": "max-age=0", + "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", + "Connection": "close", + "DNT": '1', + "Host": "www.zmeetb.com", + "sec-ch-ua": '" Not A;Brand";v="99", "Chromium";v="99"', + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": "Windows", + "Sec-Fetch-Dest": "document", + "Sec-Fetch-Mode": "navigate", + "Sec-Fetch-Site": "none", + "Sec-Fetch-User": "?1", + "Upgrade-Insecure-Requests": "1", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36 HBPC/12.1.3.306" + } + + # 这个网站返回的是一个网页,所以需要进行网页解析 + # 这个网站如果使用render()函数,会遇到ssl证书问题,需要进一步研究chromium浏览器的证书问题 + #r = session.get(url = url, headers = headers, verify='/opt/PyGuoyan/www.zmeetb.com') + r = session.get(url = url, headers = headers, verify=False) + + if r.status_code != 200: + if page == 1: + gymailer.SendMail('jinqian_chen@126.com', 'jinqian.chen@srit.com.cn', '爬虫警告信息:浙江国际招标网', r.text) + return False + + # 注意:xpath 函数返回的是list对象, 对象的元素是element + data = r.html.xpath('/html/body/div[1]/div[3]/div[2]/div/div/div[3]/div/ul/li/a') + for item in data: + title = item.xpath('//p')[0].text + url = item.attrs.get('href') + region = '浙江国际招标' + publishDate = item.xpath('//p')[1].text + announcementType = typeParam['announcementType'] + + self.write_information(title, url, region, publishDate, announcementType) + + + # 宁波市名诚招标有限有限公司 http://www.nbmcbidding.com/ + def CrawlPage_nbmcbidding(self, page, typeParam): + # 这个方法是实际爬取指定页面的信息。 + session = HTMLSession() + if typeParam['announcementType'] == '采购公告': + url = "http://www.nbmcbidding.com/news/99/"+str(page)+"/" + else: + url = "http://www.nbmcbidding.com/news/88/"+str(page)+"/" + + + data = {} + headers = { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", + "Host": "www.nbmcbidding.com", + 'Connection': 'keep-alive', + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36 HBPC/12.1.3.306" + } + + r = session.get(url = url, headers = headers, json = data) + + if r.status_code != 200: + if page == 1: + gymailer.SendMail('jinqian_chen@126.com', 'jinqian.chen@srit.com.cn', '爬虫警告信息:宁波名诚招标代理有限公司', r.text) + return False + + # 注意:xpath 函数返回的是list对象, 对象的元素是element + data = r.html.xpath('/html/body/div[1]/div/div[3]/div[2]/ul/li') + for item in data: + title = item.xpath('//a/div[2]')[0].text + url = item.xpath('//a')[0].attrs.get('href') + region = '宁波名诚招标' + publishDate = item.xpath('//a/div[4]')[0].text + announcementType = typeParam['announcementType'] + + self.write_information(title, url, region, publishDate, announcementType) + + + # 宁波市国际招标有限公司 http://www.nbbidding.com/ + def CrawlPage_nbbidding(self, page, typeParam): + # 这个方法是实际爬取指定页面的信息。 + session = HTMLSession() + if typeParam['announcementType'] == '采购公告': + url = "http://www.nbbidding.com/Home/Notice/news_list?page="+str(page)+"&is_Open=1&keyword" + + else: + url = "http://www.nbbidding.com/Home/Publicity/news_list?page="+str(page)+"&is_Open=1&keyword" + + + data = {} + headers = { + "Accept": "application/json, text/javascript, */*; q=0.01", + "Host": "www.nbbidding.com", + 'Connection': 'keep-alive', + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36 HBPC/12.1.3.306" + } + + r = session.get(url = url, headers = headers, json = data) + + if r.status_code != 200: + if page == 1: + gymailer.SendMail('jinqian_chen@126.com', 'jinqian.chen@srit.com.cn', '爬虫警告信息:宁波市国际招标网', r.text) + return False + + data = json.loads(r.text)['data'] + total = data['page']['count'] + data = data['list'] + + for item in data: + id = item['id'] + if typeParam['announcementType'] == '采购公告': + url = 'http://www.nbbidding.com/Home/Notice/news_detail?id=%s' % (id) + else: + url = 'http://www.nbbidding.com/Home/Publicity/news_detail?id=%s' % (id) + title = item['title'] + region = '宁波国际招标' + publishDate = item['addtime'] + announcementType = item['stage'] + self.write_information(title, url, region, publishDate, announcementType) + + print(publishDate, title, url) + + # 宁波市国资委属企业招标信息网 + def CrawlPage_gzw_ningbo(self, page): + # 这个方法是实际爬取指定页面的信息。 + session = HTMLSession() + url = 'http://gzw.ningbo.gov.cn/col/col1229663137/index.html?uid=6085425&pageNum=%s' % str(page) + + headers = { + "Accept": "application/json, text/javascript, */*; q=0.01", + "Accept-Encoding": "gzip, deflate", + "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", + "Connection": "keep-alive", + "DNT": '1', + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36 HBPC/12.1.3.306" + } + + # 这个网站返回的是一个网页,所以需要进行网页解析 + r = session.get(url = url, headers = headers) + r.html.render() + + if r.status_code != 200: + if page == 1: + gymailer.SendMail('jinqian_chen@126.com', 'jinqian.chen@srit.com.cn', '爬虫警告信息:宁波市国资委市属企业招标信息网', r.text) + return False + + # 注意:xpath 函数返回的是list对象, 对象的元素是element + data = r.html.xpath('/html/body/div[2]/div[3]/div/div/div[2]/div/div/div/ul/li') + for item in data: + title = item.xpath('//a')[0].text + url = item.xpath('//a')[0].attrs.get('href') + region = '宁波市属国企' + publishDate = item.xpath('//p')[0].text + announcementType = '采购公告' + self.write_information(title, url, region, publishDate, announcementType) + + + + # 宁波市中介超市网 + def CrawlPage_zjcs_nbxzfw(self, page, typeParam): + # 这个方法是实际爬取指定页面的信息。 + # type 用于判别采购信息的类型 + session = HTMLSession() + urllist = ['http://zjcs.nbxzfw.gov.cn/newsweb/api/News/GetList?ClassId=0901&Type='+typeParam['announcementCode']+'&pageIndex='+str(page)+'&pageSize=15','http://zjcs.nbxzfw.gov.cn/newsweb/api/News/GetList?ClassId=0902&Type='+typeParam['announcementCode']+'&pageIndex='+str(page)+'&pageSize=15'] + + headers = { + "Accept": "application/json, text/javascript, */*; q=0.01", + "Accept-Encoding": "gzip, deflate", + "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", + "Connection": "keep-alive", + "DNT": '1', + "Host": "ygcg.nbcqjy.org", + "Referer": "http://zjcs.nbxzfw.gov.cn/newsweb/page/news/infolist.html?Type="+str(type), + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36 HBPC/12.1.3.306" + } + + for url in urllist: + r = session.get(url = url, headers = headers) + + if r.status_code != 200: + if page == 1: + gymailer.SendMail('jinqian_chen@126.com', 'jinqian.chen@srit.com.cn', '爬虫警告信息:宁波中介超市网', r.text) + return False + + data = json.loads(r.text)['data'] + + total = data['total'] + data = data['rows'] + + for item in data: + articleId = item['AutoId'] + BulletinTypeId = item['BulletinTypeId'] + url = 'http://zjcs.nbxzfw.gov.cn/YWGG/Info?id=%s&Type=%s' % (articleId, BulletinTypeId) + title = item['BulletinTitle'] + region = '宁波中介超市' + publishDate = item['PublishDate'] + announcementType = typeParam['announcementType'] + self.write_information(title, url, region, publishDate, announcementType) + + #print(publishDate, url) + + + # 宁波阳光采购网 + def CrawlPage_ygcg_nbcqjy_org(self, pages, typeParam): + url = 'https://ygcg.nbcqjy.org/list?type=2&class=%E5%85%AC%E5%91%8A%E5%85%AC%E7%A4%BA¬iceType=' + typeParam['announcementCode'] + + wait_for = '.ant-pagination-item-ellipsis' + page_element = '.anticon-right' + try: + r = Splash().post(url, wait_for, pages=pages, page_element=page_element) + except Exception as e: + print(e) + + results = json.loads(r.text) + + # 这个方法是实际爬取指定页面的信息。 + if r.status_code != 200: + if page == 1: + gymailer.SendMail('jinqian_chen@126.com', 'jinqian.chen@srit.com.cn', '爬虫警告信息:宁波阳光采购网, 错误代码:'+str(r.status_code), r.text) + return False + + for i in range(1, pages + 1): + data = HTML(html=results[str(i)]).xpath('/html/body/div/div/div[2]/div[2]/div/div/div[2]/div[2]/div[5]/div[1]/div/ul/li') + if len(data) == 0: + print('数据为空') + gymailer.SendMail('jinqian_chen@126.com', 'jinqian.chen@srit.com.cn', '爬虫警告信息:宁波阳光采购网, keyerror', e) + return False + + for item in data: + url = 'http://ygcg.nbcqjy.org' + item.xpath('//a')[0].attrs.get('href') + title = item.xpath('//a/span[3]')[0].text + region = '宁波阳光采购' + publishDate = item.xpath('//div[2]')[0].text + announcementType = typeParam['announcementType'] + print(title) + self.write_information(title, url, region, publishDate, announcementType) + + + # 浙江政府采购网 + def CrawlPage_zfcg_czt_zj(self, page, typeParam): + # 这个方法是实际爬取指定页面的信息。 + session = HTMLSession() + url = 'https://zfcg.czt.zj.gov.cn/portal/category' + if typeParam['announcementCode'] == '110-420383': + data = { + "pageNo": page, + "pageSize": 15, + "categoryCode": typeParam['announcementCode'], + "districtCode": ["339900"], + "isProvince": True, + "includeGovDistrict": "1", + "_t": 1699104836000 + } + else: + data = { + "pageNo": page, + "pageSize": 15, + "categoryCode": typeParam['announcementCode'], + "isGov": True, + "excludeDistrictPrefix": "90", + "_t": 1699104836000 + } + + headers = { + "accept": "application/json, text/plain, */*", + "accept-language": "zh-CN,zh;q=0.9,en;q=0.8", + "content-type": "application/json;charset=UTF-8", + "sec-ch-ua": "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"99\"", + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": "\"Windows\"", + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "same-origin", + "x-requested-with": "XMLHttpRequest" + } + + try: + r = session.post(url = url, headers = headers, json = data) + except Exception as e: + print('10-------------------------', e) + + if r.status_code != 200: + if page == 1: + gymailer.SendMail('jinqian_chen@126.com', 'jinqian.chen@srit.com.cn', '爬虫警告信息:宁波政府采购网', r.text) + return False + + data = json.loads(r.text)['result']['data'] + total = data['total'] + data = data['data'] + + for item in data: + publishDate = datetime.datetime.fromtimestamp(item['publishDate']/1000) + pageUrl = 'https://zfcg.czt.zj.gov.cn/luban/detail?parentId=600007&articleId=' + item['articleId'] + '&utm=luban.luban-PC-37000.979-pc-websitegroup-zhejiang-secondPage-front.21.320086307d6811ee86314be74945ec2c' + detailUrl = 'https://zfcg.czt.zj.gov.cn/portal/detail?articleId=' + item['articleId'] + announcementType = typeParam['announcementType'] + if announcementType == '采购意向': + r = session.get(url = detailUrl, headers = headers) + + detailData = json.loads(r.text)['result']['data'] + if detailData == None: + break + + content = HTML(html=''+detailData['content']+'') + region = item['districtName'] + for detailItem in content.xpath('xml/div/div/div[1]/div/table/tbody/tr'): + title = detailItem.xpath('//td[2]')[0].text + cgxqqk = detailItem.xpath('//td[3]')[0].text + ysje = detailItem.xpath('//td[4]')[0].text + yjcgsj = detailItem.xpath('//td[5]')[0].text + ly = detailData["title"] + + self.write_information(title, pageUrl, region, publishDate, announcementType) + self.write_information_cgyx({'cgxmmc':title,'lj':pageUrl, 'cgxqqk':cgxqqk, 'ysje':ysje, 'yjcgsj':yjcgsj, 'ly':ly}) + else: + title = item['title'] + region = item['districtName'] + self.write_information(title, pageUrl, region, publishDate, announcementType) + + #print(publishDate, url) + + + return True diff --git a/dbsearch.py b/dbsearch.py new file mode 100644 index 0000000..8669831 --- /dev/null +++ b/dbsearch.py @@ -0,0 +1,137 @@ +#!/usr/bin/python3 + +import pymysql +from properties import Properties +import sys, getopt + +class DbSearch: + # 本类用于提供各类数据库信息搜索服务 + def __init__(self, connect): + self.connect = connect + + def GetTableList(self, database): + # 查询某个库的数据表的列表 + cursorTable = self.connect.cursor() + cursorTable.execute("SELECT table_name FROM INFORMATION_SCHEMA.TABLES where table_schema = '" + database + "'"); + + return cursorTable.fetchall() + + def GetColumnList(self, tableName): + # 查询某张表的数据字段列表 + cursorColumn = self.connect.cursor() + cursorColumn.execute("SELECT column_name,data_type FROM INFORMATION_SCHEMA.COLUMNS where table_schema='" + database + "' AND table_name='" + + tableName + "'"); + return cursorColumn.fetchall() + + def SearchTableByColumnName(self, columnName, database): + # 查询包含包含searchText的库表 + tableList = self.GetTableList(database) + findList = list() + for table in tableList: + columnList = self.GetColumnList(table[0]) + for column in columnList: + if column[0].find(columnName) != -1: + findList.append(table[0]) + + return findList + + def SearchTableByText(self, searchText, database): + # 查找包含searchText字符串的表,并显示相应的表记录 + tableList = self.GetTableList(database) + if len(tableList) == 0: + return False + + found = 0 + findList = list() + for table in tableList: + strSql = "SELECT '" + table[0] + "' as table_name, t.* " + strSql = strSql + " FROM " + database + "." + table[0] + " as t where " + "(" + + columnList = self.GetColumnList(table[0]) + i = 0 + + count = len(columnList) + + for column in columnList: + # 如果字段数据类型为非文本型,跳过 + if not column[1] in ('varchar', 'char', 'text'): + continue + i += 1 + + if i > 1: + strSql += " or " + strSql += column[0] + " like '%" + searchText + "%' " + + strSql += ")" + + cursorColumn = self.connect.cursor() + try: + cursorColumn.execute(strSql) + except Exception as e: + print('2----------------------------', database, strSql) + print("-----错误信息:-----\n", e) + return False + + result = cursorColumn.fetchall() + if len(result) > 0: + findList.append(table[0]) + print("==========================================================================") + print(table[0], result, strSql) + return findList + +if __name__ == '__main__': + print( +""" +============================================================ +|这是数据库全文检索工具,包含两个参数 | +============================================================ +""") + + # 设置运行环境。如果当前是测试环境,则将is_test设置为true + is_test = False + + if is_test: + file_path = "/opt/eresource_test/webapp/WEB-INF/classes/prod/jdbc.properties" + database = 'guoyantest' + else: + file_path = "/opt/eresource/webapp/WEB-INF/classes/prod/jdbc.properties" + database = 'guoyan' + + # 打开jdbc.properties文件,获取数据库的配置信息 + props = Properties(file_path) + host = 'localhost' + user = props.get('jdbc.username') + password = props.get('jdbc.password') + + # 打开数据连接 + db = pymysql.connect(host = host, user = user, password = password, database = database) + + # 获取命令行参数 + keyword = '' + searchType ='' + + keyword = '' + searchType = '' + try: + opts, args = getopt.getopt(sys.argv[1:],"hT:k:",["keyword=","searchType="]) + except getopt.GetoptError: + print(sys.argv[0] + ' -k -T ') + sys.exit(2) + + for opt, arg in opts: + if opt == '-h': + print('3--------------------', 'test.py -k -T ') + sys.exit() + elif opt in ("-k", "--keyword"): + keyword = arg + elif opt in ("-T", "--searchType"): + searchType = arg + dbSearch = DbSearch(db) + if searchType == '0': + print('正在根据您输入的关键词查找表.....................') + print('found tables: ', dbSearch.SearchTableByText(keyword, database)) + elif searchType == '1': + print('正在根据您输入的列名查找表.....................') + print('found tables: ', dbSearch.SearchTableByColumnName(keyword, database)) + + diff --git a/gycrawler.py b/gycrawler.py new file mode 100644 index 0000000..5cc93da --- /dev/null +++ b/gycrawler.py @@ -0,0 +1,59 @@ +#!/usr/bin/python3 +"""这是爬虫的主程序主程序 +作者:陈进钱 +日期:2023/11/03 +""" + +import pymysql +import datetime +import time +from apscheduler.schedulers.blocking import BlockingScheduler +from properties import Properties +from crawler import Crawler + +print( + """采购信息采集器 v1.0 +=================================================================================== + 这个程序用于获取各大招投标网站的采购信息 + version: 1.0 + 作者:陈进钱 + 日期:2023-11-04 +===================================================================================""") + +# 设置运行环境。如果当前是测试环境,则将is_test设置为true +is_test = False + +if is_test: + file_path = "/opt/eresource_test/webapp/WEB-INF/classes/prod/jdbc.properties" + database = 'guoyantest' +else: + file_path = "/opt/eresource/webapp/WEB-INF/classes/prod/jdbc.properties" + database = 'guoyan' + +# 打开jdbc.properties文件,获取数据库的配置信息 +props = Properties(file_path) +host = 'localhost' +user = props.get('jdbc.username') +password = props.get('jdbc.password') + +# 打开数据连接 +connect = pymysql.connect(host = host, user = user, password = password, database = database) + +# 获取采购信息,并填写到数据库中 +crawler = Crawler(connect) + +# 启动自动爬取任务 +def crawl_check_func(): + crawler.Check() + +# 启动自动爬取任务 +def crawl_job_func(): + crawler.Crawl() + +sched = BlockingScheduler() +sched.add_job(crawl_job_func, 'interval', hours=3, jitter=120, max_instances=4) +sched.add_job(crawl_check_func, 'interval', days=1, jitter=120, max_instances=4) +sched.start() + +# 关闭数据库连接 +connect.close() diff --git a/gymailer.py b/gymailer.py new file mode 100644 index 0000000..9011883 --- /dev/null +++ b/gymailer.py @@ -0,0 +1,44 @@ +import smtplib +from email.mime.text import MIMEText +from email.header import Header + +def SendMail(sender, receiver, subject, message): + # 发送邮件服务器 + smtp_server = 'smtp.126.com' + + # 发送邮件服务器端口 + smtp_port = 465 + + # 邮件对象 + msg = MIMEText(message, 'plain', 'utf-8') + msg['From'] = Header(sender, 'utf-8') + msg['To'] = Header(receiver, 'utf-8') + msg['Subject'] = Header(subject, 'utf-8') + + # SMTP对象 + smtpObj = smtplib.SMTP_SSL(smtp_server, smtp_port) + + # 登录SMTP服务器 + smtpObj.login(sender, 'ERXYFJRLKPTTDXWH') + + # 发送邮件 + smtpObj.sendmail(from_addr=sender,to_addrs=[receiver],msg=msg.as_string()) + + # 关闭SMTP连接 + smtpObj.quit() + +if __name__ == '__main__': + + # 发件人邮箱 + sender = 'jinqian_chen@126.com' + + # 收件人邮箱 + receiver = 'jinqian.chen@srit.com.cn' + + # 邮件主题 + subject = 'Python3发送邮件示例, new' + + # 邮件正文 + message = '这是一封Python3发送的邮件' + SendMail(sender, receiver, subject, message) + diff --git a/jdbc.properties b/jdbc.properties new file mode 100644 index 0000000..e6a415b --- /dev/null +++ b/jdbc.properties @@ -0,0 +1,46 @@ +#Db2 +#hibernate.dialect=org.hibernate.dialect.DB2Dialect +#jdbc.driverClassName=com.ibm.db2.jcc.DB2Driver +#jdbc.url=jdbc:db2://localhost:50000/eaching + +#Oracle +#hibernate.dialect=org.hibernate.dialect.Oracle10gDialect +#jdbc.driverClassName=oracle.jdbc.driver.OracleDriver +#jdbc.url=jdbc:oracle:thin:@47.99.208.214:1521:orcl +#jdbc.url=jdbc:oracle:thin:@118.190.161.36:1521:orcl + +#SqlServer +#hibernate.dialect=org.hibernate.dialect.SQLServerDialect +#jdbc.driverClassName=net.sourceforge.jtds.jdbc.Driver +#jdbc.url=jdbc:jtds:sqlserver://localhost:1433/guanwaimatou;SelectMethod=Cursor + + +#MySql +hibernate.dialect=org.hibernate.dialect.MySQLDialect +jdbc.driverClassName=com.mysql.jdbc.Driver +jdbc.url=jdbc:mysql://116.62.210.190:3306/guoyantest?autoReconnect=true&useUnicode=true&characterEncoding=UTF8&mysqlEncoding=utf8&zeroDateTimeBehavior=convertToNull + +jdbc.username=root +jdbc.password=Guoyan83086775 + +jdbc.maxConn=20 +jdbc.minConn=5 +jdbc.activeTime=900000 +jdbc.alias=eaching +jdbc.keepingSleepTime=30000 +jdbc.maxConnectionLifetime=60000 + +jdbc.multiSource=false + +hibernate.cache.use_second_level_cache=true +hibernate.show_sql=false +hibernate.generate_statistics=false +hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider +#hibernate.cache.provider_class=net.oschina.j2cache.hibernate3.J2CacheProvider +hibernate.cache.use_minimal_puts=true +hibernate.cache.use_structured_entries=true +hibernate.cache.use_query_cache=true +hibernate.use_sql_comments=trues +hibernate.order_updates=true +hibernate.format_sql=false +hbm2ddl.auto=create diff --git a/main.py b/main.py new file mode 100644 index 0000000..91fc80e --- /dev/null +++ b/main.py @@ -0,0 +1,75 @@ +#!/usr/bin/python3 +"""这是爬虫的主程序主程序 +作者:陈进钱 +日期:2023/11/03 +""" + +import pymysql +import datetime +import time +from apscheduler.schedulers.blocking import BlockingScheduler +from properties import Properties +from crawler import Crawler +import sys +import os + +print( + """采购信息采集器 v1.0 +=================================================================================== + 这个程序用于获取各大招投标网站的采购信息 + version: 1.0 + 作者:陈进钱 + 日期:2023-11-04 +===================================================================================""") + +# 设置运行环境。如果当前是测试环境,则将is_test设置为true +is_test = True +if is_test: + root = "/opt/eresource_test/webapp/WEB-INF/classes/prod/" +else: + root = "/opt/eresource/webapp/WEB-INF/classes/prod/" + +if os.path.exists(root): + file_path = root + "jdbc.properties" +else: + file_path = "jdbc.properties" + +if sys.platform == 'win32': + host = '116.62.210.190' + user = 'root' + password = 'Guoyan83086775' + if is_test: + database = 'guoyantest' + else: + database = 'guoyan' +else: + if is_test: + database = 'guoyantest' + else: + database = 'guoyan' + + # 打开jdbc.properties文件,获取数据库的配置信息 + props = Properties(file_path) + host = '116.62.210.190' + user = props.get('jdbc.username') + password = props.get('jdbc.password') + +# 打开数据连接 +connect = pymysql.connect(host = host, user = user, password = password, database = database) + +# 获取采购信息,并填写到数据库中 +crawler = Crawler(connect) +crawler.Crawl() +#crawler.CrawlPage_ygcg_nbcqjy_org(1, {"announcementCode": "21", "announcementType":"采购公告"}) +#print(crawler.Check()) + +# 启动自动爬取任务 +#def crawl_job_func(): +# crawler.Crawl() + +#sched = BlockingScheduler() +#sched.add_job(crawl_job_func, 'interval', hours=1, jitter=120) +#sched.start() + +# 关闭数据库连接 +connect.close() diff --git a/myrec.db b/myrec.db new file mode 100644 index 0000000000000000000000000000000000000000..aed9fcfc698bfde4dede49d033e687e3fe7698fd GIT binary patch literal 12288 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 0: + for param in params: + url = self.replace(url, param, params[param]) + + if wait_for == '': + wait_for = self.config['class'][self.class_name()]['wait_for'] + + if page_element =='': + page_element = self.config['class'][self.class_name()]['page_element'] + + if headers == '': + headers = self.config['class'][self.class_name()]['headers'] + scripts = self.script() + scripts = self.set_params_for_lua(scripts, { + 'pages':str(pages), + 'url':url, + 'wait_for':wait_for, + 'page_element':page_element, + # 这个解析器要从通过参数传递 + 'scripts_js': scripts_js, + 'announcement_type':annoucement_type + }) + + # print(scripts) + data = json.dumps({'lua_source':scripts}) + splash_url = 'http://' + self.config['server'] + ':' + self.config['port'] + '/execute' + r = HTMLSession().post(splash_url, headers=headers, data=data) + + return r diff --git a/splash/scripts/main.lua b/splash/scripts/main.lua new file mode 100644 index 0000000..fc52329 --- /dev/null +++ b/splash/scripts/main.lua @@ -0,0 +1,75 @@ +-- 本文件是页面抓取的主入口 +-- 这里必须采用加载模块的方法,否则好像不能动态加载js文件 +parser = require('parser') + +function main(splash, args) + pages = {{$pages}} + scripts_js = '{{$scripts_js}}' + page_element = '{{$page_element}}' + wait_for = '{{$wait_for}}' + announcement_type = '{{$announcement_type}}' + splash:go('{{$url}}') + wait_for_element(splash, wait_for) + wait_for_element(splash, page_element) + + -- 设置javascript脚本参数 + results = {} + params_js = {} + params_js['announcement_type'] = announcement_type + + -- 将第一页的结果加入返回结果集中 + result = parser.select(splash, scripts_js, params_js) + table.insert(results, result) + + if pages == 1 then + return results + else + -- 执行翻页动作 + -- 先页面上的翻页元件(element),然后发送点击事件(click())翻页 + for i = 2, pages do + -- 执行翻页脚本 + -- js 中是javascript脚本,用于获取翻页的元件,并发送click事件 + js = string.format("document.querySelector('%s').click();", page_element) + splash:runjs(js) + + -- 等待页面加载完成 + wait_for_element(splash, wait_for) + wait_for_element(splash, page_element) + + -- 这个地方看来必须加上延时,否则页面加载不完全,可能还没有完成页面更新 + assert(splash:wait(5)) + result = parser.select(splash, scripts_js, params_js) + table.insert(results, result) + end + return results + end +end + +function wait_for_element(splash, css, maxwait) + -- Wait until a selector matches an element + -- in the page. Return an error if waited more + -- than maxwait seconds. + if maxwait == nil then + maxwait = 10 + end + return splash:wait_for_resume(string.format([[ + function main(splash) { + var selector = '%s'; + var maxwait = %s; + var end = Date.now() + maxwait*1000; + + function check() { + if(document.querySelector(selector)) { + splash.resume('Element found'); + } else if(Date.now() >= end) { + var err = 'Timeout waiting for element'; + splash.error(err + " " + selector); + } else { + setTimeout(check, 200); + } + } + check(); + } + ]], css, maxwait)) +end + diff --git a/splash/scripts/modules/jquery-3.7.1.min.js b/splash/scripts/modules/jquery-3.7.1.min.js new file mode 100644 index 0000000..7f37b5d --- /dev/null +++ b/splash/scripts/modules/jquery-3.7.1.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0 div > div.z_list_vue > div.ant-spin-nested-loading > div > div > div.z_content > div.z_detail_content > div:nth-child(5) > div.ant-spin-nested-loading > div > ul'); + // 获取列表的第一个元素,获取成功的话,元素封装对象的length = 1 + li = ul.children('li').first() + item = {} + while (li.length == 1) + { + a = li.find('div.ant-list-item-meta > div > h4 > span > a'); + item.title = $(a.children()['2']).attr('title'); + item.url = a.attr('href'); + item.updateTime = $(li.children()[1]).text(); + item.region = '宁波阳光采购'; + item.announcementType = '{{$announcement_type}}' + + lists.push(item) + // 取下一个列表元素 + li = li.next() + } + + results.count = lists.length + results.lists = lists + return results +} diff --git a/splash/scripts/modules/zepto.js b/splash/scripts/modules/zepto.js new file mode 100644 index 0000000..18b3ada --- /dev/null +++ b/splash/scripts/modules/zepto.js @@ -0,0 +1,1650 @@ +/* Zepto v1.2.0 - zepto event ajax form ie - zeptojs.com/license */ +(function(global, factory) { + if (typeof define === 'function' && define.amd) + define(function() { return factory(global) }) + else + factory(global) +}(this, function(window) { + var Zepto = (function() { + var undefined, key, $, classList, emptyArray = [], concat = emptyArray.concat, filter = emptyArray.filter, slice = emptyArray.slice, + document = window.document, + elementDisplay = {}, classCache = {}, + cssNumber = { 'column-count': 1, 'columns': 1, 'font-weight': 1, 'line-height': 1,'opacity': 1, 'z-index': 1, 'zoom': 1 }, + fragmentRE = /^\s*<(\w+|!)[^>]*>/, + singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, + tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rootNodeRE = /^(?:body|html)$/i, + capitalRE = /([A-Z])/g, + + // special attributes that should be get/set via method calls + methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'], + + adjacencyOperators = [ 'after', 'prepend', 'before', 'append' ], + table = document.createElement('table'), + tableRow = document.createElement('tr'), + containers = { + 'tr': document.createElement('tbody'), + 'tbody': table, 'thead': table, 'tfoot': table, + 'td': tableRow, 'th': tableRow, + '*': document.createElement('div') + }, + readyRE = /complete|loaded|interactive/, + simpleSelectorRE = /^[\w-]*$/, + class2type = {}, + toString = class2type.toString, + zepto = {}, + camelize, uniq, + tempParent = document.createElement('div'), + propMap = { + 'tabindex': 'tabIndex', + 'readonly': 'readOnly', + 'for': 'htmlFor', + 'class': 'className', + 'maxlength': 'maxLength', + 'cellspacing': 'cellSpacing', + 'cellpadding': 'cellPadding', + 'rowspan': 'rowSpan', + 'colspan': 'colSpan', + 'usemap': 'useMap', + 'frameborder': 'frameBorder', + 'contenteditable': 'contentEditable' + }, + isArray = Array.isArray || + function(object){ return object instanceof Array } + + zepto.matches = function(element, selector) { + if (!selector || !element || element.nodeType !== 1) return false + var matchesSelector = element.matches || element.webkitMatchesSelector || + element.mozMatchesSelector || element.oMatchesSelector || + element.matchesSelector + if (matchesSelector) return matchesSelector.call(element, selector) + // fall back to performing a selector: + var match, parent = element.parentNode, temp = !parent + if (temp) (parent = tempParent).appendChild(element) + match = ~zepto.qsa(parent, selector).indexOf(element) + temp && tempParent.removeChild(element) + return match + } + + function type(obj) { + return obj == null ? String(obj) : + class2type[toString.call(obj)] || "object" + } + + function isFunction(value) { return type(value) == "function" } + function isWindow(obj) { return obj != null && obj == obj.window } + function isDocument(obj) { return obj != null && obj.nodeType == obj.DOCUMENT_NODE } + function isObject(obj) { return type(obj) == "object" } + function isPlainObject(obj) { + return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype + } + + function likeArray(obj) { + var length = !!obj && 'length' in obj && obj.length, + type = $.type(obj) + + return 'function' != type && !isWindow(obj) && ( + 'array' == type || length === 0 || + (typeof length == 'number' && length > 0 && (length - 1) in obj) + ) + } + + function compact(array) { return filter.call(array, function(item){ return item != null }) } + function flatten(array) { return array.length > 0 ? $.fn.concat.apply([], array) : array } + camelize = function(str){ return str.replace(/-+(.)?/g, function(match, chr){ return chr ? chr.toUpperCase() : '' }) } + function dasherize(str) { + return str.replace(/::/g, '/') + .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') + .replace(/([a-z\d])([A-Z])/g, '$1_$2') + .replace(/_/g, '-') + .toLowerCase() + } + uniq = function(array){ return filter.call(array, function(item, idx){ return array.indexOf(item) == idx }) } + + function classRE(name) { + return name in classCache ? + classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)')) + } + + function maybeAddPx(name, value) { + return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px" : value + } + + function defaultDisplay(nodeName) { + var element, display + if (!elementDisplay[nodeName]) { + element = document.createElement(nodeName) + document.body.appendChild(element) + display = getComputedStyle(element, '').getPropertyValue("display") + element.parentNode.removeChild(element) + display == "none" && (display = "block") + elementDisplay[nodeName] = display + } + return elementDisplay[nodeName] + } + + function children(element) { + return 'children' in element ? + slice.call(element.children) : + $.map(element.childNodes, function(node){ if (node.nodeType == 1) return node }) + } + + function Z(dom, selector) { + var i, len = dom ? dom.length : 0 + for (i = 0; i < len; i++) this[i] = dom[i] + this.length = len + this.selector = selector || '' + } + + // `$.zepto.fragment` takes a html string and an optional tag name + // to generate DOM nodes from the given html string. + // The generated DOM nodes are returned as an array. + // This function can be overridden in plugins for example to make + // it compatible with browsers that don't support the DOM fully. + zepto.fragment = function(html, name, properties) { + var dom, nodes, container + + // A special case optimization for a single tag + if (singleTagRE.test(html)) dom = $(document.createElement(RegExp.$1)) + + if (!dom) { + if (html.replace) html = html.replace(tagExpanderRE, "<$1>") + if (name === undefined) name = fragmentRE.test(html) && RegExp.$1 + if (!(name in containers)) name = '*' + + container = containers[name] + container.innerHTML = '' + html + dom = $.each(slice.call(container.childNodes), function(){ + container.removeChild(this) + }) + } + + if (isPlainObject(properties)) { + nodes = $(dom) + $.each(properties, function(key, value) { + if (methodAttributes.indexOf(key) > -1) nodes[key](value) + else nodes.attr(key, value) + }) + } + + return dom + } + + // `$.zepto.Z` swaps out the prototype of the given `dom` array + // of nodes with `$.fn` and thus supplying all the Zepto functions + // to the array. This method can be overridden in plugins. + zepto.Z = function(dom, selector) { + return new Z(dom, selector) + } + + // `$.zepto.isZ` should return `true` if the given object is a Zepto + // collection. This method can be overridden in plugins. + zepto.isZ = function(object) { + return object instanceof zepto.Z + } + + // `$.zepto.init` is Zepto's counterpart to jQuery's `$.fn.init` and + // takes a CSS selector and an optional context (and handles various + // special cases). + // This method can be overridden in plugins. + zepto.init = function(selector, context) { + var dom + // If nothing given, return an empty Zepto collection + if (!selector) return zepto.Z() + // Optimize for string selectors + else if (typeof selector == 'string') { + selector = selector.trim() + // If it's a html fragment, create nodes from it + // Note: In both Chrome 21 and Firefox 15, DOM error 12 + // is thrown if the fragment doesn't begin with < + if (selector[0] == '<' && fragmentRE.test(selector)) + dom = zepto.fragment(selector, RegExp.$1, context), selector = null + // If there's a context, create a collection on that context first, and select + // nodes from there + else if (context !== undefined) return $(context).find(selector) + // If it's a CSS selector, use it to select nodes. + else dom = zepto.qsa(document, selector) + } + // If a function is given, call it when the DOM is ready + else if (isFunction(selector)) return $(document).ready(selector) + // If a Zepto collection is given, just return it + else if (zepto.isZ(selector)) return selector + else { + // normalize array if an array of nodes is given + if (isArray(selector)) dom = compact(selector) + // Wrap DOM nodes. + else if (isObject(selector)) + dom = [selector], selector = null + // If it's a html fragment, create nodes from it + else if (fragmentRE.test(selector)) + dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null + // If there's a context, create a collection on that context first, and select + // nodes from there + else if (context !== undefined) return $(context).find(selector) + // And last but no least, if it's a CSS selector, use it to select nodes. + else dom = zepto.qsa(document, selector) + } + // create a new Zepto collection from the nodes found + return zepto.Z(dom, selector) + } + + // `$` will be the base `Zepto` object. When calling this + // function just call `$.zepto.init, which makes the implementation + // details of selecting nodes and creating Zepto collections + // patchable in plugins. + $ = function(selector, context){ + return zepto.init(selector, context) + } + + function extend(target, source, deep) { + for (key in source) + if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { + if (isPlainObject(source[key]) && !isPlainObject(target[key])) + target[key] = {} + if (isArray(source[key]) && !isArray(target[key])) + target[key] = [] + extend(target[key], source[key], deep) + } + else if (source[key] !== undefined) target[key] = source[key] + } + + // Copy all but undefined properties from one or more + // objects to the `target` object. + $.extend = function(target){ + var deep, args = slice.call(arguments, 1) + if (typeof target == 'boolean') { + deep = target + target = args.shift() + } + args.forEach(function(arg){ extend(target, arg, deep) }) + return target + } + + // `$.zepto.qsa` is Zepto's CSS selector implementation which + // uses `document.querySelectorAll` and optimizes for some special cases, like `#id`. + // This method can be overridden in plugins. + zepto.qsa = function(element, selector){ + var found, + maybeID = selector[0] == '#', + maybeClass = !maybeID && selector[0] == '.', + nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, // Ensure that a 1 char tag name still gets checked + isSimple = simpleSelectorRE.test(nameOnly) + return (element.getElementById && isSimple && maybeID) ? // Safari DocumentFragment doesn't have getElementById + ( (found = element.getElementById(nameOnly)) ? [found] : [] ) : + (element.nodeType !== 1 && element.nodeType !== 9 && element.nodeType !== 11) ? [] : + slice.call( + isSimple && !maybeID && element.getElementsByClassName ? // DocumentFragment doesn't have getElementsByClassName/TagName + maybeClass ? element.getElementsByClassName(nameOnly) : // If it's simple, it could be a class + element.getElementsByTagName(selector) : // Or a tag + element.querySelectorAll(selector) // Or it's not simple, and we need to query all + ) + } + + function filtered(nodes, selector) { + return selector == null ? $(nodes) : $(nodes).filter(selector) + } + + $.contains = document.documentElement.contains ? + function(parent, node) { + return parent !== node && parent.contains(node) + } : + function(parent, node) { + while (node && (node = node.parentNode)) + if (node === parent) return true + return false + } + + function funcArg(context, arg, idx, payload) { + return isFunction(arg) ? arg.call(context, idx, payload) : arg + } + + function setAttribute(node, name, value) { + value == null ? node.removeAttribute(name) : node.setAttribute(name, value) + } + + // access className property while respecting SVGAnimatedString + function className(node, value){ + var klass = node.className || '', + svg = klass && klass.baseVal !== undefined + + if (value === undefined) return svg ? klass.baseVal : klass + svg ? (klass.baseVal = value) : (node.className = value) + } + + // "true" => true + // "false" => false + // "null" => null + // "42" => 42 + // "42.5" => 42.5 + // "08" => "08" + // JSON => parse if valid + // String => self + function deserializeValue(value) { + try { + return value ? + value == "true" || + ( value == "false" ? false : + value == "null" ? null : + +value + "" == value ? +value : + /^[\[\{]/.test(value) ? $.parseJSON(value) : + value ) + : value + } catch(e) { + return value + } + } + + $.type = type + $.isFunction = isFunction + $.isWindow = isWindow + $.isArray = isArray + $.isPlainObject = isPlainObject + + $.isEmptyObject = function(obj) { + var name + for (name in obj) return false + return true + } + + $.isNumeric = function(val) { + var num = Number(val), type = typeof val + return val != null && type != 'boolean' && + (type != 'string' || val.length) && + !isNaN(num) && isFinite(num) || false + } + + $.inArray = function(elem, array, i){ + return emptyArray.indexOf.call(array, elem, i) + } + + $.camelCase = camelize + $.trim = function(str) { + return str == null ? "" : String.prototype.trim.call(str) + } + + // plugin compatibility + $.uuid = 0 + $.support = { } + $.expr = { } + $.noop = function() {} + + $.map = function(elements, callback){ + var value, values = [], i, key + if (likeArray(elements)) + for (i = 0; i < elements.length; i++) { + value = callback(elements[i], i) + if (value != null) values.push(value) + } + else + for (key in elements) { + value = callback(elements[key], key) + if (value != null) values.push(value) + } + return flatten(values) + } + + $.each = function(elements, callback){ + var i, key + if (likeArray(elements)) { + for (i = 0; i < elements.length; i++) + if (callback.call(elements[i], i, elements[i]) === false) return elements + } else { + for (key in elements) + if (callback.call(elements[key], key, elements[key]) === false) return elements + } + + return elements + } + + $.grep = function(elements, callback){ + return filter.call(elements, callback) + } + + if (window.JSON) $.parseJSON = JSON.parse + + // Populate the class2type map + $.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase() + }) + + // Define methods that will be available on all + // Zepto collections + $.fn = { + constructor: zepto.Z, + length: 0, + + // Because a collection acts like an array + // copy over these useful array functions. + forEach: emptyArray.forEach, + reduce: emptyArray.reduce, + push: emptyArray.push, + sort: emptyArray.sort, + splice: emptyArray.splice, + indexOf: emptyArray.indexOf, + concat: function(){ + var i, value, args = [] + for (i = 0; i < arguments.length; i++) { + value = arguments[i] + args[i] = zepto.isZ(value) ? value.toArray() : value + } + return concat.apply(zepto.isZ(this) ? this.toArray() : this, args) + }, + + // `map` and `slice` in the jQuery API work differently + // from their array counterparts + map: function(fn){ + return $($.map(this, function(el, i){ return fn.call(el, i, el) })) + }, + slice: function(){ + return $(slice.apply(this, arguments)) + }, + + ready: function(callback){ + // need to check if document.body exists for IE as that browser reports + // document ready when it hasn't yet created the body element + if (readyRE.test(document.readyState) && document.body) callback($) + else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false) + return this + }, + get: function(idx){ + return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length] + }, + toArray: function(){ return this.get() }, + size: function(){ + return this.length + }, + remove: function(){ + return this.each(function(){ + if (this.parentNode != null) + this.parentNode.removeChild(this) + }) + }, + each: function(callback){ + emptyArray.every.call(this, function(el, idx){ + return callback.call(el, idx, el) !== false + }) + return this + }, + filter: function(selector){ + if (isFunction(selector)) return this.not(this.not(selector)) + return $(filter.call(this, function(element){ + return zepto.matches(element, selector) + })) + }, + add: function(selector,context){ + return $(uniq(this.concat($(selector,context)))) + }, + is: function(selector){ + return this.length > 0 && zepto.matches(this[0], selector) + }, + not: function(selector){ + var nodes=[] + if (isFunction(selector) && selector.call !== undefined) + this.each(function(idx){ + if (!selector.call(this,idx)) nodes.push(this) + }) + else { + var excludes = typeof selector == 'string' ? this.filter(selector) : + (likeArray(selector) && isFunction(selector.item)) ? slice.call(selector) : $(selector) + this.forEach(function(el){ + if (excludes.indexOf(el) < 0) nodes.push(el) + }) + } + return $(nodes) + }, + has: function(selector){ + return this.filter(function(){ + return isObject(selector) ? + $.contains(this, selector) : + $(this).find(selector).size() + }) + }, + eq: function(idx){ + return idx === -1 ? this.slice(idx) : this.slice(idx, + idx + 1) + }, + first: function(){ + var el = this[0] + return el && !isObject(el) ? el : $(el) + }, + last: function(){ + var el = this[this.length - 1] + return el && !isObject(el) ? el : $(el) + }, + find: function(selector){ + var result, $this = this + if (!selector) result = $() + else if (typeof selector == 'object') + result = $(selector).filter(function(){ + var node = this + return emptyArray.some.call($this, function(parent){ + return $.contains(parent, node) + }) + }) + else if (this.length == 1) result = $(zepto.qsa(this[0], selector)) + else result = this.map(function(){ return zepto.qsa(this, selector) }) + return result + }, + closest: function(selector, context){ + var nodes = [], collection = typeof selector == 'object' && $(selector) + this.each(function(_, node){ + while (node && !(collection ? collection.indexOf(node) >= 0 : zepto.matches(node, selector))) + node = node !== context && !isDocument(node) && node.parentNode + if (node && nodes.indexOf(node) < 0) nodes.push(node) + }) + return $(nodes) + }, + parents: function(selector){ + var ancestors = [], nodes = this + while (nodes.length > 0) + nodes = $.map(nodes, function(node){ + if ((node = node.parentNode) && !isDocument(node) && ancestors.indexOf(node) < 0) { + ancestors.push(node) + return node + } + }) + return filtered(ancestors, selector) + }, + parent: function(selector){ + return filtered(uniq(this.pluck('parentNode')), selector) + }, + children: function(selector){ + return filtered(this.map(function(){ return children(this) }), selector) + }, + contents: function() { + return this.map(function() { return this.contentDocument || slice.call(this.childNodes) }) + }, + siblings: function(selector){ + return filtered(this.map(function(i, el){ + return filter.call(children(el.parentNode), function(child){ return child!==el }) + }), selector) + }, + empty: function(){ + return this.each(function(){ this.innerHTML = '' }) + }, + // `pluck` is borrowed from Prototype.js + pluck: function(property){ + return $.map(this, function(el){ return el[property] }) + }, + show: function(){ + return this.each(function(){ + this.style.display == "none" && (this.style.display = '') + if (getComputedStyle(this, '').getPropertyValue("display") == "none") + this.style.display = defaultDisplay(this.nodeName) + }) + }, + replaceWith: function(newContent){ + return this.before(newContent).remove() + }, + wrap: function(structure){ + var func = isFunction(structure) + if (this[0] && !func) + var dom = $(structure).get(0), + clone = dom.parentNode || this.length > 1 + + return this.each(function(index){ + $(this).wrapAll( + func ? structure.call(this, index) : + clone ? dom.cloneNode(true) : dom + ) + }) + }, + wrapAll: function(structure){ + if (this[0]) { + $(this[0]).before(structure = $(structure)) + var children + // drill down to the inmost element + while ((children = structure.children()).length) structure = children.first() + $(structure).append(this) + } + return this + }, + wrapInner: function(structure){ + var func = isFunction(structure) + return this.each(function(index){ + var self = $(this), contents = self.contents(), + dom = func ? structure.call(this, index) : structure + contents.length ? contents.wrapAll(dom) : self.append(dom) + }) + }, + unwrap: function(){ + this.parent().each(function(){ + $(this).replaceWith($(this).children()) + }) + return this + }, + clone: function(){ + return this.map(function(){ return this.cloneNode(true) }) + }, + hide: function(){ + return this.css("display", "none") + }, + toggle: function(setting){ + return this.each(function(){ + var el = $(this) + ;(setting === undefined ? el.css("display") == "none" : setting) ? el.show() : el.hide() + }) + }, + prev: function(selector){ return $(this.pluck('previousElementSibling')).filter(selector || '*') }, + next: function(selector){ return $(this.pluck('nextElementSibling')).filter(selector || '*') }, + html: function(html){ + return 0 in arguments ? + this.each(function(idx){ + var originHtml = this.innerHTML + $(this).empty().append( funcArg(this, html, idx, originHtml) ) + }) : + (0 in this ? this[0].innerHTML : null) + }, + text: function(text){ + return 0 in arguments ? + this.each(function(idx){ + var newText = funcArg(this, text, idx, this.textContent) + this.textContent = newText == null ? '' : ''+newText + }) : + (0 in this ? this.pluck('textContent').join("") : null) + }, + attr: function(name, value){ + var result + return (typeof name == 'string' && !(1 in arguments)) ? + (0 in this && this[0].nodeType == 1 && (result = this[0].getAttribute(name)) != null ? result : undefined) : + this.each(function(idx){ + if (this.nodeType !== 1) return + if (isObject(name)) for (key in name) setAttribute(this, key, name[key]) + else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name))) + }) + }, + removeAttr: function(name){ + return this.each(function(){ this.nodeType === 1 && name.split(' ').forEach(function(attribute){ + setAttribute(this, attribute) + }, this)}) + }, + prop: function(name, value){ + name = propMap[name] || name + return (1 in arguments) ? + this.each(function(idx){ + this[name] = funcArg(this, value, idx, this[name]) + }) : + (this[0] && this[0][name]) + }, + removeProp: function(name){ + name = propMap[name] || name + return this.each(function(){ delete this[name] }) + }, + data: function(name, value){ + var attrName = 'data-' + name.replace(capitalRE, '-$1').toLowerCase() + + var data = (1 in arguments) ? + this.attr(attrName, value) : + this.attr(attrName) + + return data !== null ? deserializeValue(data) : undefined + }, + val: function(value){ + if (0 in arguments) { + if (value == null) value = "" + return this.each(function(idx){ + this.value = funcArg(this, value, idx, this.value) + }) + } else { + return this[0] && (this[0].multiple ? + $(this[0]).find('option').filter(function(){ return this.selected }).pluck('value') : + this[0].value) + } + }, + offset: function(coordinates){ + if (coordinates) return this.each(function(index){ + var $this = $(this), + coords = funcArg(this, coordinates, index, $this.offset()), + parentOffset = $this.offsetParent().offset(), + props = { + top: coords.top - parentOffset.top, + left: coords.left - parentOffset.left + } + + if ($this.css('position') == 'static') props['position'] = 'relative' + $this.css(props) + }) + if (!this.length) return null + if (document.documentElement !== this[0] && !$.contains(document.documentElement, this[0])) + return {top: 0, left: 0} + var obj = this[0].getBoundingClientRect() + return { + left: obj.left + window.pageXOffset, + top: obj.top + window.pageYOffset, + width: Math.round(obj.width), + height: Math.round(obj.height) + } + }, + css: function(property, value){ + if (arguments.length < 2) { + var element = this[0] + if (typeof property == 'string') { + if (!element) return + return element.style[camelize(property)] || getComputedStyle(element, '').getPropertyValue(property) + } else if (isArray(property)) { + if (!element) return + var props = {} + var computedStyle = getComputedStyle(element, '') + $.each(property, function(_, prop){ + props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop)) + }) + return props + } + } + + var css = '' + if (type(property) == 'string') { + if (!value && value !== 0) + this.each(function(){ this.style.removeProperty(dasherize(property)) }) + else + css = dasherize(property) + ":" + maybeAddPx(property, value) + } else { + for (key in property) + if (!property[key] && property[key] !== 0) + this.each(function(){ this.style.removeProperty(dasherize(key)) }) + else + css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';' + } + + return this.each(function(){ this.style.cssText += ';' + css }) + }, + index: function(element){ + return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0]) + }, + hasClass: function(name){ + if (!name) return false + return emptyArray.some.call(this, function(el){ + return this.test(className(el)) + }, classRE(name)) + }, + addClass: function(name){ + if (!name) return this + return this.each(function(idx){ + if (!('className' in this)) return + classList = [] + var cls = className(this), newName = funcArg(this, name, idx, cls) + newName.split(/\s+/g).forEach(function(klass){ + if (!$(this).hasClass(klass)) classList.push(klass) + }, this) + classList.length && className(this, cls + (cls ? " " : "") + classList.join(" ")) + }) + }, + removeClass: function(name){ + return this.each(function(idx){ + if (!('className' in this)) return + if (name === undefined) return className(this, '') + classList = className(this) + funcArg(this, name, idx, classList).split(/\s+/g).forEach(function(klass){ + classList = classList.replace(classRE(klass), " ") + }) + className(this, classList.trim()) + }) + }, + toggleClass: function(name, when){ + if (!name) return this + return this.each(function(idx){ + var $this = $(this), names = funcArg(this, name, idx, className(this)) + names.split(/\s+/g).forEach(function(klass){ + (when === undefined ? !$this.hasClass(klass) : when) ? + $this.addClass(klass) : $this.removeClass(klass) + }) + }) + }, + scrollTop: function(value){ + if (!this.length) return + var hasScrollTop = 'scrollTop' in this[0] + if (value === undefined) return hasScrollTop ? this[0].scrollTop : this[0].pageYOffset + return this.each(hasScrollTop ? + function(){ this.scrollTop = value } : + function(){ this.scrollTo(this.scrollX, value) }) + }, + scrollLeft: function(value){ + if (!this.length) return + var hasScrollLeft = 'scrollLeft' in this[0] + if (value === undefined) return hasScrollLeft ? this[0].scrollLeft : this[0].pageXOffset + return this.each(hasScrollLeft ? + function(){ this.scrollLeft = value } : + function(){ this.scrollTo(value, this.scrollY) }) + }, + position: function() { + if (!this.length) return + + var elem = this[0], + // Get *real* offsetParent + offsetParent = this.offsetParent(), + // Get correct offsets + offset = this.offset(), + parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset() + + // Subtract element margins + // note: when an element has margin: auto the offsetLeft and marginLeft + // are the same in Safari causing offset.left to incorrectly be 0 + offset.top -= parseFloat( $(elem).css('margin-top') ) || 0 + offset.left -= parseFloat( $(elem).css('margin-left') ) || 0 + + // Add offsetParent borders + parentOffset.top += parseFloat( $(offsetParent[0]).css('border-top-width') ) || 0 + parentOffset.left += parseFloat( $(offsetParent[0]).css('border-left-width') ) || 0 + + // Subtract the two offsets + return { + top: offset.top - parentOffset.top, + left: offset.left - parentOffset.left + } + }, + offsetParent: function() { + return this.map(function(){ + var parent = this.offsetParent || document.body + while (parent && !rootNodeRE.test(parent.nodeName) && $(parent).css("position") == "static") + parent = parent.offsetParent + return parent + }) + } + } + + // for now + $.fn.detach = $.fn.remove + + // Generate the `width` and `height` functions + ;['width', 'height'].forEach(function(dimension){ + var dimensionProperty = + dimension.replace(/./, function(m){ return m[0].toUpperCase() }) + + $.fn[dimension] = function(value){ + var offset, el = this[0] + if (value === undefined) return isWindow(el) ? el['inner' + dimensionProperty] : + isDocument(el) ? el.documentElement['scroll' + dimensionProperty] : + (offset = this.offset()) && offset[dimension] + else return this.each(function(idx){ + el = $(this) + el.css(dimension, funcArg(this, value, idx, el[dimension]())) + }) + } + }) + + function traverseNode(node, fun) { + fun(node) + for (var i = 0, len = node.childNodes.length; i < len; i++) + traverseNode(node.childNodes[i], fun) + } + + // Generate the `after`, `prepend`, `before`, `append`, + // `insertAfter`, `insertBefore`, `appendTo`, and `prependTo` methods. + adjacencyOperators.forEach(function(operator, operatorIndex) { + var inside = operatorIndex % 2 //=> prepend, append + + $.fn[operator] = function(){ + // arguments can be nodes, arrays of nodes, Zepto objects and HTML strings + var argType, nodes = $.map(arguments, function(arg) { + var arr = [] + argType = type(arg) + if (argType == "array") { + arg.forEach(function(el) { + if (el.nodeType !== undefined) return arr.push(el) + else if ($.zepto.isZ(el)) return arr = arr.concat(el.get()) + arr = arr.concat(zepto.fragment(el)) + }) + return arr + } + return argType == "object" || arg == null ? + arg : zepto.fragment(arg) + }), + parent, copyByClone = this.length > 1 + if (nodes.length < 1) return this + + return this.each(function(_, target){ + parent = inside ? target : target.parentNode + + // convert all methods to a "before" operation + target = operatorIndex == 0 ? target.nextSibling : + operatorIndex == 1 ? target.firstChild : + operatorIndex == 2 ? target : + null + + var parentInDocument = $.contains(document.documentElement, parent) + + nodes.forEach(function(node){ + if (copyByClone) node = node.cloneNode(true) + else if (!parent) return $(node).remove() + + parent.insertBefore(node, target) + if (parentInDocument) traverseNode(node, function(el){ + if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' && + (!el.type || el.type === 'text/javascript') && !el.src){ + var target = el.ownerDocument ? el.ownerDocument.defaultView : window + target['eval'].call(target, el.innerHTML) + } + }) + }) + }) + } + + // after => insertAfter + // prepend => prependTo + // before => insertBefore + // append => appendTo + $.fn[inside ? operator+'To' : 'insert'+(operatorIndex ? 'Before' : 'After')] = function(html){ + $(html)[operator](this) + return this + } + }) + + zepto.Z.prototype = Z.prototype = $.fn + + // Export internal API functions in the `$.zepto` namespace + zepto.uniq = uniq + zepto.deserializeValue = deserializeValue + $.zepto = zepto + + return $ +})() + +window.Zepto = Zepto +window.$ === undefined && (window.$ = Zepto) + +;(function($){ + var _zid = 1, undefined, + slice = Array.prototype.slice, + isFunction = $.isFunction, + isString = function(obj){ return typeof obj == 'string' }, + handlers = {}, + specialEvents={}, + focusinSupported = 'onfocusin' in window, + focus = { focus: 'focusin', blur: 'focusout' }, + hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' } + + specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents' + + function zid(element) { + return element._zid || (element._zid = _zid++) + } + function findHandlers(element, event, fn, selector) { + event = parse(event) + if (event.ns) var matcher = matcherFor(event.ns) + return (handlers[zid(element)] || []).filter(function(handler) { + return handler + && (!event.e || handler.e == event.e) + && (!event.ns || matcher.test(handler.ns)) + && (!fn || zid(handler.fn) === zid(fn)) + && (!selector || handler.sel == selector) + }) + } + function parse(event) { + var parts = ('' + event).split('.') + return {e: parts[0], ns: parts.slice(1).sort().join(' ')} + } + function matcherFor(ns) { + return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)') + } + + function eventCapture(handler, captureSetting) { + return handler.del && + (!focusinSupported && (handler.e in focus)) || + !!captureSetting + } + + function realEvent(type) { + return hover[type] || (focusinSupported && focus[type]) || type + } + + function add(element, events, fn, data, selector, delegator, capture){ + var id = zid(element), set = (handlers[id] || (handlers[id] = [])) + events.split(/\s/).forEach(function(event){ + if (event == 'ready') return $(document).ready(fn) + var handler = parse(event) + handler.fn = fn + handler.sel = selector + // emulate mouseenter, mouseleave + if (handler.e in hover) fn = function(e){ + var related = e.relatedTarget + if (!related || (related !== this && !$.contains(this, related))) + return handler.fn.apply(this, arguments) + } + handler.del = delegator + var callback = delegator || fn + handler.proxy = function(e){ + e = compatible(e) + if (e.isImmediatePropagationStopped()) return + e.data = data + var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args)) + if (result === false) e.preventDefault(), e.stopPropagation() + return result + } + handler.i = set.length + set.push(handler) + if ('addEventListener' in element) + element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + } + function remove(element, events, fn, selector, capture){ + var id = zid(element) + ;(events || '').split(/\s/).forEach(function(event){ + findHandlers(element, event, fn, selector).forEach(function(handler){ + delete handlers[id][handler.i] + if ('removeEventListener' in element) + element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + }) + } + + $.event = { add: add, remove: remove } + + $.proxy = function(fn, context) { + var args = (2 in arguments) && slice.call(arguments, 2) + if (isFunction(fn)) { + var proxyFn = function(){ return fn.apply(context, args ? args.concat(slice.call(arguments)) : arguments) } + proxyFn._zid = zid(fn) + return proxyFn + } else if (isString(context)) { + if (args) { + args.unshift(fn[context], fn) + return $.proxy.apply(null, args) + } else { + return $.proxy(fn[context], fn) + } + } else { + throw new TypeError("expected function") + } + } + + $.fn.bind = function(event, data, callback){ + return this.on(event, data, callback) + } + $.fn.unbind = function(event, callback){ + return this.off(event, callback) + } + $.fn.one = function(event, selector, data, callback){ + return this.on(event, selector, data, callback, 1) + } + + var returnTrue = function(){return true}, + returnFalse = function(){return false}, + ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$|webkitMovement[XY]$)/, + eventMethods = { + preventDefault: 'isDefaultPrevented', + stopImmediatePropagation: 'isImmediatePropagationStopped', + stopPropagation: 'isPropagationStopped' + } + + function compatible(event, source) { + if (source || !event.isDefaultPrevented) { + source || (source = event) + + $.each(eventMethods, function(name, predicate) { + var sourceMethod = source[name] + event[name] = function(){ + this[predicate] = returnTrue + return sourceMethod && sourceMethod.apply(source, arguments) + } + event[predicate] = returnFalse + }) + + event.timeStamp || (event.timeStamp = Date.now()) + + if (source.defaultPrevented !== undefined ? source.defaultPrevented : + 'returnValue' in source ? source.returnValue === false : + source.getPreventDefault && source.getPreventDefault()) + event.isDefaultPrevented = returnTrue + } + return event + } + + function createProxy(event) { + var key, proxy = { originalEvent: event } + for (key in event) + if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key] + + return compatible(proxy, event) + } + + $.fn.delegate = function(selector, event, callback){ + return this.on(event, selector, callback) + } + $.fn.undelegate = function(selector, event, callback){ + return this.off(event, selector, callback) + } + + $.fn.live = function(event, callback){ + $(document.body).delegate(this.selector, event, callback) + return this + } + $.fn.die = function(event, callback){ + $(document.body).undelegate(this.selector, event, callback) + return this + } + + $.fn.on = function(event, selector, data, callback, one){ + var autoRemove, delegator, $this = this + if (event && !isString(event)) { + $.each(event, function(type, fn){ + $this.on(type, selector, data, fn, one) + }) + return $this + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = data, data = selector, selector = undefined + if (callback === undefined || data === false) + callback = data, data = undefined + + if (callback === false) callback = returnFalse + + return $this.each(function(_, element){ + if (one) autoRemove = function(e){ + remove(element, e.type, callback) + return callback.apply(this, arguments) + } + + if (selector) delegator = function(e){ + var evt, match = $(e.target).closest(selector, element).get(0) + if (match && match !== element) { + evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element}) + return (autoRemove || callback).apply(match, [evt].concat(slice.call(arguments, 1))) + } + } + + add(element, event, callback, data, selector, delegator || autoRemove) + }) + } + $.fn.off = function(event, selector, callback){ + var $this = this + if (event && !isString(event)) { + $.each(event, function(type, fn){ + $this.off(type, selector, fn) + }) + return $this + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = selector, selector = undefined + + if (callback === false) callback = returnFalse + + return $this.each(function(){ + remove(this, event, callback, selector) + }) + } + + $.fn.trigger = function(event, args){ + event = (isString(event) || $.isPlainObject(event)) ? $.Event(event) : compatible(event) + event._args = args + return this.each(function(){ + // handle focus(), blur() by calling them directly + if (event.type in focus && typeof this[event.type] == "function") this[event.type]() + // items in the collection might not be DOM elements + else if ('dispatchEvent' in this) this.dispatchEvent(event) + else $(this).triggerHandler(event, args) + }) + } + + // triggers event handlers on current element just as if an event occurred, + // doesn't trigger an actual event, doesn't bubble + $.fn.triggerHandler = function(event, args){ + var e, result + this.each(function(i, element){ + e = createProxy(isString(event) ? $.Event(event) : event) + e._args = args + e.target = element + $.each(findHandlers(element, event.type || event), function(i, handler){ + result = handler.proxy(e) + if (e.isImmediatePropagationStopped()) return false + }) + }) + return result + } + + // shortcut methods for `.bind(event, fn)` for each event type + ;('focusin focusout focus blur load resize scroll unload click dblclick '+ + 'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave '+ + 'change select keydown keypress keyup error').split(' ').forEach(function(event) { + $.fn[event] = function(callback) { + return (0 in arguments) ? + this.bind(event, callback) : + this.trigger(event) + } + }) + + $.Event = function(type, props) { + if (!isString(type)) props = type, type = props.type + var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true + if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name]) + event.initEvent(type, bubbles, true) + return compatible(event) + } + +})(Zepto) + +;(function($){ + var jsonpID = +new Date(), + document = window.document, + key, + name, + rscript = /)<[^<]*)*<\/script>/gi, + scriptTypeRE = /^(?:text|application)\/javascript/i, + xmlTypeRE = /^(?:text|application)\/xml/i, + jsonType = 'application/json', + htmlType = 'text/html', + blankRE = /^\s*$/, + originAnchor = document.createElement('a') + + originAnchor.href = window.location.href + + // trigger a custom event and return false if it was cancelled + function triggerAndReturn(context, eventName, data) { + var event = $.Event(eventName) + $(context).trigger(event, data) + return !event.isDefaultPrevented() + } + + // trigger an Ajax "global" event + function triggerGlobal(settings, context, eventName, data) { + if (settings.global) return triggerAndReturn(context || document, eventName, data) + } + + // Number of active Ajax requests + $.active = 0 + + function ajaxStart(settings) { + if (settings.global && $.active++ === 0) triggerGlobal(settings, null, 'ajaxStart') + } + function ajaxStop(settings) { + if (settings.global && !(--$.active)) triggerGlobal(settings, null, 'ajaxStop') + } + + // triggers an extra global event "ajaxBeforeSend" that's like "ajaxSend" but cancelable + function ajaxBeforeSend(xhr, settings) { + var context = settings.context + if (settings.beforeSend.call(context, xhr, settings) === false || + triggerGlobal(settings, context, 'ajaxBeforeSend', [xhr, settings]) === false) + return false + + triggerGlobal(settings, context, 'ajaxSend', [xhr, settings]) + } + function ajaxSuccess(data, xhr, settings, deferred) { + var context = settings.context, status = 'success' + settings.success.call(context, data, status, xhr) + if (deferred) deferred.resolveWith(context, [data, status, xhr]) + triggerGlobal(settings, context, 'ajaxSuccess', [xhr, settings, data]) + ajaxComplete(status, xhr, settings) + } + // type: "timeout", "error", "abort", "parsererror" + function ajaxError(error, type, xhr, settings, deferred) { + var context = settings.context + settings.error.call(context, xhr, type, error) + if (deferred) deferred.rejectWith(context, [xhr, type, error]) + triggerGlobal(settings, context, 'ajaxError', [xhr, settings, error || type]) + ajaxComplete(type, xhr, settings) + } + // status: "success", "notmodified", "error", "timeout", "abort", "parsererror" + function ajaxComplete(status, xhr, settings) { + var context = settings.context + settings.complete.call(context, xhr, status) + triggerGlobal(settings, context, 'ajaxComplete', [xhr, settings]) + ajaxStop(settings) + } + + function ajaxDataFilter(data, type, settings) { + if (settings.dataFilter == empty) return data + var context = settings.context + return settings.dataFilter.call(context, data, type) + } + + // Empty function, used as default callback + function empty() {} + + $.ajaxJSONP = function(options, deferred){ + if (!('type' in options)) return $.ajax(options) + + var _callbackName = options.jsonpCallback, + callbackName = ($.isFunction(_callbackName) ? + _callbackName() : _callbackName) || ('Zepto' + (jsonpID++)), + script = document.createElement('script'), + originalCallback = window[callbackName], + responseData, + abort = function(errorType) { + $(script).triggerHandler('error', errorType || 'abort') + }, + xhr = { abort: abort }, abortTimeout + + if (deferred) deferred.promise(xhr) + + $(script).on('load error', function(e, errorType){ + clearTimeout(abortTimeout) + $(script).off().remove() + + if (e.type == 'error' || !responseData) { + ajaxError(null, errorType || 'error', xhr, options, deferred) + } else { + ajaxSuccess(responseData[0], xhr, options, deferred) + } + + window[callbackName] = originalCallback + if (responseData && $.isFunction(originalCallback)) + originalCallback(responseData[0]) + + originalCallback = responseData = undefined + }) + + if (ajaxBeforeSend(xhr, options) === false) { + abort('abort') + return xhr + } + + window[callbackName] = function(){ + responseData = arguments + } + + script.src = options.url.replace(/\?(.+)=\?/, '?$1=' + callbackName) + document.head.appendChild(script) + + if (options.timeout > 0) abortTimeout = setTimeout(function(){ + abort('timeout') + }, options.timeout) + + return xhr + } + + $.ajaxSettings = { + // Default type of request + type: 'GET', + // Callback that is executed before request + beforeSend: empty, + // Callback that is executed if the request succeeds + success: empty, + // Callback that is executed the the server drops error + error: empty, + // Callback that is executed on request complete (both: error and success) + complete: empty, + // The context for the callbacks + context: null, + // Whether to trigger "global" Ajax events + global: true, + // Transport + xhr: function () { + return new window.XMLHttpRequest() + }, + // MIME types mapping + // IIS returns Javascript as "application/x-javascript" + accepts: { + script: 'text/javascript, application/javascript, application/x-javascript', + json: jsonType, + xml: 'application/xml, text/xml', + html: htmlType, + text: 'text/plain' + }, + // Whether the request is to another domain + crossDomain: false, + // Default timeout + timeout: 0, + // Whether data should be serialized to string + processData: true, + // Whether the browser should be allowed to cache GET responses + cache: true, + //Used to handle the raw response data of XMLHttpRequest. + //This is a pre-filtering function to sanitize the response. + //The sanitized response should be returned + dataFilter: empty + } + + function mimeToDataType(mime) { + if (mime) mime = mime.split(';', 2)[0] + return mime && ( mime == htmlType ? 'html' : + mime == jsonType ? 'json' : + scriptTypeRE.test(mime) ? 'script' : + xmlTypeRE.test(mime) && 'xml' ) || 'text' + } + + function appendQuery(url, query) { + if (query == '') return url + return (url + '&' + query).replace(/[&?]{1,2}/, '?') + } + + // serialize payload and append it to the URL for GET requests + function serializeData(options) { + if (options.processData && options.data && $.type(options.data) != "string") + options.data = $.param(options.data, options.traditional) + if (options.data && (!options.type || options.type.toUpperCase() == 'GET' || 'jsonp' == options.dataType)) + options.url = appendQuery(options.url, options.data), options.data = undefined + } + + $.ajax = function(options){ + var settings = $.extend({}, options || {}), + deferred = $.Deferred && $.Deferred(), + urlAnchor, hashIndex + for (key in $.ajaxSettings) if (settings[key] === undefined) settings[key] = $.ajaxSettings[key] + + ajaxStart(settings) + + if (!settings.crossDomain) { + urlAnchor = document.createElement('a') + urlAnchor.href = settings.url + // cleans up URL for .href (IE only), see https://github.com/madrobby/zepto/pull/1049 + urlAnchor.href = urlAnchor.href + settings.crossDomain = (originAnchor.protocol + '//' + originAnchor.host) !== (urlAnchor.protocol + '//' + urlAnchor.host) + } + + if (!settings.url) settings.url = window.location.toString() + if ((hashIndex = settings.url.indexOf('#')) > -1) settings.url = settings.url.slice(0, hashIndex) + serializeData(settings) + + var dataType = settings.dataType, hasPlaceholder = /\?.+=\?/.test(settings.url) + if (hasPlaceholder) dataType = 'jsonp' + + if (settings.cache === false || ( + (!options || options.cache !== true) && + ('script' == dataType || 'jsonp' == dataType) + )) + settings.url = appendQuery(settings.url, '_=' + Date.now()) + + if ('jsonp' == dataType) { + if (!hasPlaceholder) + settings.url = appendQuery(settings.url, + settings.jsonp ? (settings.jsonp + '=?') : settings.jsonp === false ? '' : 'callback=?') + return $.ajaxJSONP(settings, deferred) + } + + var mime = settings.accepts[dataType], + headers = { }, + setHeader = function(name, value) { headers[name.toLowerCase()] = [name, value] }, + protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol, + xhr = settings.xhr(), + nativeSetHeader = xhr.setRequestHeader, + abortTimeout + + if (deferred) deferred.promise(xhr) + + if (!settings.crossDomain) setHeader('X-Requested-With', 'XMLHttpRequest') + setHeader('Accept', mime || '*/*') + if (mime = settings.mimeType || mime) { + if (mime.indexOf(',') > -1) mime = mime.split(',', 2)[0] + xhr.overrideMimeType && xhr.overrideMimeType(mime) + } + if (settings.contentType || (settings.contentType !== false && settings.data && settings.type.toUpperCase() != 'GET')) + setHeader('Content-Type', settings.contentType || 'application/x-www-form-urlencoded') + + if (settings.headers) for (name in settings.headers) setHeader(name, settings.headers[name]) + xhr.setRequestHeader = setHeader + + xhr.onreadystatechange = function(){ + if (xhr.readyState == 4) { + xhr.onreadystatechange = empty + clearTimeout(abortTimeout) + var result, error = false + if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 || (xhr.status == 0 && protocol == 'file:')) { + dataType = dataType || mimeToDataType(settings.mimeType || xhr.getResponseHeader('content-type')) + + if (xhr.responseType == 'arraybuffer' || xhr.responseType == 'blob') + result = xhr.response + else { + result = xhr.responseText + + try { + // http://perfectionkills.com/global-eval-what-are-the-options/ + // sanitize response accordingly if data filter callback provided + result = ajaxDataFilter(result, dataType, settings) + if (dataType == 'script') (1,eval)(result) + else if (dataType == 'xml') result = xhr.responseXML + else if (dataType == 'json') result = blankRE.test(result) ? null : $.parseJSON(result) + } catch (e) { error = e } + + if (error) return ajaxError(error, 'parsererror', xhr, settings, deferred) + } + + ajaxSuccess(result, xhr, settings, deferred) + } else { + ajaxError(xhr.statusText || null, xhr.status ? 'error' : 'abort', xhr, settings, deferred) + } + } + } + + if (ajaxBeforeSend(xhr, settings) === false) { + xhr.abort() + ajaxError(null, 'abort', xhr, settings, deferred) + return xhr + } + + var async = 'async' in settings ? settings.async : true + xhr.open(settings.type, settings.url, async, settings.username, settings.password) + + if (settings.xhrFields) for (name in settings.xhrFields) xhr[name] = settings.xhrFields[name] + + for (name in headers) nativeSetHeader.apply(xhr, headers[name]) + + if (settings.timeout > 0) abortTimeout = setTimeout(function(){ + xhr.onreadystatechange = empty + xhr.abort() + ajaxError(null, 'timeout', xhr, settings, deferred) + }, settings.timeout) + + // avoid sending empty string (#319) + xhr.send(settings.data ? settings.data : null) + return xhr + } + + // handle optional data/success arguments + function parseArguments(url, data, success, dataType) { + if ($.isFunction(data)) dataType = success, success = data, data = undefined + if (!$.isFunction(success)) dataType = success, success = undefined + return { + url: url + , data: data + , success: success + , dataType: dataType + } + } + + $.get = function(/* url, data, success, dataType */){ + return $.ajax(parseArguments.apply(null, arguments)) + } + + $.post = function(/* url, data, success, dataType */){ + var options = parseArguments.apply(null, arguments) + options.type = 'POST' + return $.ajax(options) + } + + $.getJSON = function(/* url, data, success */){ + var options = parseArguments.apply(null, arguments) + options.dataType = 'json' + return $.ajax(options) + } + + $.fn.load = function(url, data, success){ + if (!this.length) return this + var self = this, parts = url.split(/\s/), selector, + options = parseArguments(url, data, success), + callback = options.success + if (parts.length > 1) options.url = parts[0], selector = parts[1] + options.success = function(response){ + self.html(selector ? + $('
').html(response.replace(rscript, "")).find(selector) + : response) + callback && callback.apply(self, arguments) + } + $.ajax(options) + return this + } + + var escape = encodeURIComponent + + function serialize(params, obj, traditional, scope){ + var type, array = $.isArray(obj), hash = $.isPlainObject(obj) + $.each(obj, function(key, value) { + type = $.type(value) + if (scope) key = traditional ? scope : + scope + '[' + (hash || type == 'object' || type == 'array' ? key : '') + ']' + // handle data in serializeArray() format + if (!scope && array) params.add(value.name, value.value) + // recurse into nested objects + else if (type == "array" || (!traditional && type == "object")) + serialize(params, value, traditional, key) + else params.add(key, value) + }) + } + + $.param = function(obj, traditional){ + var params = [] + params.add = function(key, value) { + if ($.isFunction(value)) value = value() + if (value == null) value = "" + this.push(escape(key) + '=' + escape(value)) + } + serialize(params, obj, traditional) + return params.join('&').replace(/%20/g, '+') + } +})(Zepto) + +;(function($){ + $.fn.serializeArray = function() { + var name, type, result = [], + add = function(value) { + if (value.forEach) return value.forEach(add) + result.push({ name: name, value: value }) + } + if (this[0]) $.each(this[0].elements, function(_, field){ + type = field.type, name = field.name + if (name && field.nodeName.toLowerCase() != 'fieldset' && + !field.disabled && type != 'submit' && type != 'reset' && type != 'button' && type != 'file' && + ((type != 'radio' && type != 'checkbox') || field.checked)) + add($(field).val()) + }) + return result + } + + $.fn.serialize = function(){ + var result = [] + this.serializeArray().forEach(function(elm){ + result.push(encodeURIComponent(elm.name) + '=' + encodeURIComponent(elm.value)) + }) + return result.join('&') + } + + $.fn.submit = function(callback) { + if (0 in arguments) this.bind('submit', callback) + else if (this.length) { + var event = $.Event('submit') + this.eq(0).trigger(event) + if (!event.isDefaultPrevented()) this.get(0).submit() + } + return this + } + +})(Zepto) + +;(function(){ + // getComputedStyle shouldn't freak out when called + // without a valid element as argument + try { + getComputedStyle(undefined) + } catch(e) { + var nativeGetComputedStyle = getComputedStyle + window.getComputedStyle = function(element, pseudoElement){ + try { + return nativeGetComputedStyle(element, pseudoElement) + } catch(e) { + return null + } + } + } +})() + return Zepto +})) diff --git a/splash/scripts/modules/zepto.js.1 b/splash/scripts/modules/zepto.js.1 new file mode 100644 index 0000000..18b3ada --- /dev/null +++ b/splash/scripts/modules/zepto.js.1 @@ -0,0 +1,1650 @@ +/* Zepto v1.2.0 - zepto event ajax form ie - zeptojs.com/license */ +(function(global, factory) { + if (typeof define === 'function' && define.amd) + define(function() { return factory(global) }) + else + factory(global) +}(this, function(window) { + var Zepto = (function() { + var undefined, key, $, classList, emptyArray = [], concat = emptyArray.concat, filter = emptyArray.filter, slice = emptyArray.slice, + document = window.document, + elementDisplay = {}, classCache = {}, + cssNumber = { 'column-count': 1, 'columns': 1, 'font-weight': 1, 'line-height': 1,'opacity': 1, 'z-index': 1, 'zoom': 1 }, + fragmentRE = /^\s*<(\w+|!)[^>]*>/, + singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, + tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rootNodeRE = /^(?:body|html)$/i, + capitalRE = /([A-Z])/g, + + // special attributes that should be get/set via method calls + methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'], + + adjacencyOperators = [ 'after', 'prepend', 'before', 'append' ], + table = document.createElement('table'), + tableRow = document.createElement('tr'), + containers = { + 'tr': document.createElement('tbody'), + 'tbody': table, 'thead': table, 'tfoot': table, + 'td': tableRow, 'th': tableRow, + '*': document.createElement('div') + }, + readyRE = /complete|loaded|interactive/, + simpleSelectorRE = /^[\w-]*$/, + class2type = {}, + toString = class2type.toString, + zepto = {}, + camelize, uniq, + tempParent = document.createElement('div'), + propMap = { + 'tabindex': 'tabIndex', + 'readonly': 'readOnly', + 'for': 'htmlFor', + 'class': 'className', + 'maxlength': 'maxLength', + 'cellspacing': 'cellSpacing', + 'cellpadding': 'cellPadding', + 'rowspan': 'rowSpan', + 'colspan': 'colSpan', + 'usemap': 'useMap', + 'frameborder': 'frameBorder', + 'contenteditable': 'contentEditable' + }, + isArray = Array.isArray || + function(object){ return object instanceof Array } + + zepto.matches = function(element, selector) { + if (!selector || !element || element.nodeType !== 1) return false + var matchesSelector = element.matches || element.webkitMatchesSelector || + element.mozMatchesSelector || element.oMatchesSelector || + element.matchesSelector + if (matchesSelector) return matchesSelector.call(element, selector) + // fall back to performing a selector: + var match, parent = element.parentNode, temp = !parent + if (temp) (parent = tempParent).appendChild(element) + match = ~zepto.qsa(parent, selector).indexOf(element) + temp && tempParent.removeChild(element) + return match + } + + function type(obj) { + return obj == null ? String(obj) : + class2type[toString.call(obj)] || "object" + } + + function isFunction(value) { return type(value) == "function" } + function isWindow(obj) { return obj != null && obj == obj.window } + function isDocument(obj) { return obj != null && obj.nodeType == obj.DOCUMENT_NODE } + function isObject(obj) { return type(obj) == "object" } + function isPlainObject(obj) { + return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype + } + + function likeArray(obj) { + var length = !!obj && 'length' in obj && obj.length, + type = $.type(obj) + + return 'function' != type && !isWindow(obj) && ( + 'array' == type || length === 0 || + (typeof length == 'number' && length > 0 && (length - 1) in obj) + ) + } + + function compact(array) { return filter.call(array, function(item){ return item != null }) } + function flatten(array) { return array.length > 0 ? $.fn.concat.apply([], array) : array } + camelize = function(str){ return str.replace(/-+(.)?/g, function(match, chr){ return chr ? chr.toUpperCase() : '' }) } + function dasherize(str) { + return str.replace(/::/g, '/') + .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') + .replace(/([a-z\d])([A-Z])/g, '$1_$2') + .replace(/_/g, '-') + .toLowerCase() + } + uniq = function(array){ return filter.call(array, function(item, idx){ return array.indexOf(item) == idx }) } + + function classRE(name) { + return name in classCache ? + classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)')) + } + + function maybeAddPx(name, value) { + return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px" : value + } + + function defaultDisplay(nodeName) { + var element, display + if (!elementDisplay[nodeName]) { + element = document.createElement(nodeName) + document.body.appendChild(element) + display = getComputedStyle(element, '').getPropertyValue("display") + element.parentNode.removeChild(element) + display == "none" && (display = "block") + elementDisplay[nodeName] = display + } + return elementDisplay[nodeName] + } + + function children(element) { + return 'children' in element ? + slice.call(element.children) : + $.map(element.childNodes, function(node){ if (node.nodeType == 1) return node }) + } + + function Z(dom, selector) { + var i, len = dom ? dom.length : 0 + for (i = 0; i < len; i++) this[i] = dom[i] + this.length = len + this.selector = selector || '' + } + + // `$.zepto.fragment` takes a html string and an optional tag name + // to generate DOM nodes from the given html string. + // The generated DOM nodes are returned as an array. + // This function can be overridden in plugins for example to make + // it compatible with browsers that don't support the DOM fully. + zepto.fragment = function(html, name, properties) { + var dom, nodes, container + + // A special case optimization for a single tag + if (singleTagRE.test(html)) dom = $(document.createElement(RegExp.$1)) + + if (!dom) { + if (html.replace) html = html.replace(tagExpanderRE, "<$1>") + if (name === undefined) name = fragmentRE.test(html) && RegExp.$1 + if (!(name in containers)) name = '*' + + container = containers[name] + container.innerHTML = '' + html + dom = $.each(slice.call(container.childNodes), function(){ + container.removeChild(this) + }) + } + + if (isPlainObject(properties)) { + nodes = $(dom) + $.each(properties, function(key, value) { + if (methodAttributes.indexOf(key) > -1) nodes[key](value) + else nodes.attr(key, value) + }) + } + + return dom + } + + // `$.zepto.Z` swaps out the prototype of the given `dom` array + // of nodes with `$.fn` and thus supplying all the Zepto functions + // to the array. This method can be overridden in plugins. + zepto.Z = function(dom, selector) { + return new Z(dom, selector) + } + + // `$.zepto.isZ` should return `true` if the given object is a Zepto + // collection. This method can be overridden in plugins. + zepto.isZ = function(object) { + return object instanceof zepto.Z + } + + // `$.zepto.init` is Zepto's counterpart to jQuery's `$.fn.init` and + // takes a CSS selector and an optional context (and handles various + // special cases). + // This method can be overridden in plugins. + zepto.init = function(selector, context) { + var dom + // If nothing given, return an empty Zepto collection + if (!selector) return zepto.Z() + // Optimize for string selectors + else if (typeof selector == 'string') { + selector = selector.trim() + // If it's a html fragment, create nodes from it + // Note: In both Chrome 21 and Firefox 15, DOM error 12 + // is thrown if the fragment doesn't begin with < + if (selector[0] == '<' && fragmentRE.test(selector)) + dom = zepto.fragment(selector, RegExp.$1, context), selector = null + // If there's a context, create a collection on that context first, and select + // nodes from there + else if (context !== undefined) return $(context).find(selector) + // If it's a CSS selector, use it to select nodes. + else dom = zepto.qsa(document, selector) + } + // If a function is given, call it when the DOM is ready + else if (isFunction(selector)) return $(document).ready(selector) + // If a Zepto collection is given, just return it + else if (zepto.isZ(selector)) return selector + else { + // normalize array if an array of nodes is given + if (isArray(selector)) dom = compact(selector) + // Wrap DOM nodes. + else if (isObject(selector)) + dom = [selector], selector = null + // If it's a html fragment, create nodes from it + else if (fragmentRE.test(selector)) + dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null + // If there's a context, create a collection on that context first, and select + // nodes from there + else if (context !== undefined) return $(context).find(selector) + // And last but no least, if it's a CSS selector, use it to select nodes. + else dom = zepto.qsa(document, selector) + } + // create a new Zepto collection from the nodes found + return zepto.Z(dom, selector) + } + + // `$` will be the base `Zepto` object. When calling this + // function just call `$.zepto.init, which makes the implementation + // details of selecting nodes and creating Zepto collections + // patchable in plugins. + $ = function(selector, context){ + return zepto.init(selector, context) + } + + function extend(target, source, deep) { + for (key in source) + if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { + if (isPlainObject(source[key]) && !isPlainObject(target[key])) + target[key] = {} + if (isArray(source[key]) && !isArray(target[key])) + target[key] = [] + extend(target[key], source[key], deep) + } + else if (source[key] !== undefined) target[key] = source[key] + } + + // Copy all but undefined properties from one or more + // objects to the `target` object. + $.extend = function(target){ + var deep, args = slice.call(arguments, 1) + if (typeof target == 'boolean') { + deep = target + target = args.shift() + } + args.forEach(function(arg){ extend(target, arg, deep) }) + return target + } + + // `$.zepto.qsa` is Zepto's CSS selector implementation which + // uses `document.querySelectorAll` and optimizes for some special cases, like `#id`. + // This method can be overridden in plugins. + zepto.qsa = function(element, selector){ + var found, + maybeID = selector[0] == '#', + maybeClass = !maybeID && selector[0] == '.', + nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, // Ensure that a 1 char tag name still gets checked + isSimple = simpleSelectorRE.test(nameOnly) + return (element.getElementById && isSimple && maybeID) ? // Safari DocumentFragment doesn't have getElementById + ( (found = element.getElementById(nameOnly)) ? [found] : [] ) : + (element.nodeType !== 1 && element.nodeType !== 9 && element.nodeType !== 11) ? [] : + slice.call( + isSimple && !maybeID && element.getElementsByClassName ? // DocumentFragment doesn't have getElementsByClassName/TagName + maybeClass ? element.getElementsByClassName(nameOnly) : // If it's simple, it could be a class + element.getElementsByTagName(selector) : // Or a tag + element.querySelectorAll(selector) // Or it's not simple, and we need to query all + ) + } + + function filtered(nodes, selector) { + return selector == null ? $(nodes) : $(nodes).filter(selector) + } + + $.contains = document.documentElement.contains ? + function(parent, node) { + return parent !== node && parent.contains(node) + } : + function(parent, node) { + while (node && (node = node.parentNode)) + if (node === parent) return true + return false + } + + function funcArg(context, arg, idx, payload) { + return isFunction(arg) ? arg.call(context, idx, payload) : arg + } + + function setAttribute(node, name, value) { + value == null ? node.removeAttribute(name) : node.setAttribute(name, value) + } + + // access className property while respecting SVGAnimatedString + function className(node, value){ + var klass = node.className || '', + svg = klass && klass.baseVal !== undefined + + if (value === undefined) return svg ? klass.baseVal : klass + svg ? (klass.baseVal = value) : (node.className = value) + } + + // "true" => true + // "false" => false + // "null" => null + // "42" => 42 + // "42.5" => 42.5 + // "08" => "08" + // JSON => parse if valid + // String => self + function deserializeValue(value) { + try { + return value ? + value == "true" || + ( value == "false" ? false : + value == "null" ? null : + +value + "" == value ? +value : + /^[\[\{]/.test(value) ? $.parseJSON(value) : + value ) + : value + } catch(e) { + return value + } + } + + $.type = type + $.isFunction = isFunction + $.isWindow = isWindow + $.isArray = isArray + $.isPlainObject = isPlainObject + + $.isEmptyObject = function(obj) { + var name + for (name in obj) return false + return true + } + + $.isNumeric = function(val) { + var num = Number(val), type = typeof val + return val != null && type != 'boolean' && + (type != 'string' || val.length) && + !isNaN(num) && isFinite(num) || false + } + + $.inArray = function(elem, array, i){ + return emptyArray.indexOf.call(array, elem, i) + } + + $.camelCase = camelize + $.trim = function(str) { + return str == null ? "" : String.prototype.trim.call(str) + } + + // plugin compatibility + $.uuid = 0 + $.support = { } + $.expr = { } + $.noop = function() {} + + $.map = function(elements, callback){ + var value, values = [], i, key + if (likeArray(elements)) + for (i = 0; i < elements.length; i++) { + value = callback(elements[i], i) + if (value != null) values.push(value) + } + else + for (key in elements) { + value = callback(elements[key], key) + if (value != null) values.push(value) + } + return flatten(values) + } + + $.each = function(elements, callback){ + var i, key + if (likeArray(elements)) { + for (i = 0; i < elements.length; i++) + if (callback.call(elements[i], i, elements[i]) === false) return elements + } else { + for (key in elements) + if (callback.call(elements[key], key, elements[key]) === false) return elements + } + + return elements + } + + $.grep = function(elements, callback){ + return filter.call(elements, callback) + } + + if (window.JSON) $.parseJSON = JSON.parse + + // Populate the class2type map + $.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase() + }) + + // Define methods that will be available on all + // Zepto collections + $.fn = { + constructor: zepto.Z, + length: 0, + + // Because a collection acts like an array + // copy over these useful array functions. + forEach: emptyArray.forEach, + reduce: emptyArray.reduce, + push: emptyArray.push, + sort: emptyArray.sort, + splice: emptyArray.splice, + indexOf: emptyArray.indexOf, + concat: function(){ + var i, value, args = [] + for (i = 0; i < arguments.length; i++) { + value = arguments[i] + args[i] = zepto.isZ(value) ? value.toArray() : value + } + return concat.apply(zepto.isZ(this) ? this.toArray() : this, args) + }, + + // `map` and `slice` in the jQuery API work differently + // from their array counterparts + map: function(fn){ + return $($.map(this, function(el, i){ return fn.call(el, i, el) })) + }, + slice: function(){ + return $(slice.apply(this, arguments)) + }, + + ready: function(callback){ + // need to check if document.body exists for IE as that browser reports + // document ready when it hasn't yet created the body element + if (readyRE.test(document.readyState) && document.body) callback($) + else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false) + return this + }, + get: function(idx){ + return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length] + }, + toArray: function(){ return this.get() }, + size: function(){ + return this.length + }, + remove: function(){ + return this.each(function(){ + if (this.parentNode != null) + this.parentNode.removeChild(this) + }) + }, + each: function(callback){ + emptyArray.every.call(this, function(el, idx){ + return callback.call(el, idx, el) !== false + }) + return this + }, + filter: function(selector){ + if (isFunction(selector)) return this.not(this.not(selector)) + return $(filter.call(this, function(element){ + return zepto.matches(element, selector) + })) + }, + add: function(selector,context){ + return $(uniq(this.concat($(selector,context)))) + }, + is: function(selector){ + return this.length > 0 && zepto.matches(this[0], selector) + }, + not: function(selector){ + var nodes=[] + if (isFunction(selector) && selector.call !== undefined) + this.each(function(idx){ + if (!selector.call(this,idx)) nodes.push(this) + }) + else { + var excludes = typeof selector == 'string' ? this.filter(selector) : + (likeArray(selector) && isFunction(selector.item)) ? slice.call(selector) : $(selector) + this.forEach(function(el){ + if (excludes.indexOf(el) < 0) nodes.push(el) + }) + } + return $(nodes) + }, + has: function(selector){ + return this.filter(function(){ + return isObject(selector) ? + $.contains(this, selector) : + $(this).find(selector).size() + }) + }, + eq: function(idx){ + return idx === -1 ? this.slice(idx) : this.slice(idx, + idx + 1) + }, + first: function(){ + var el = this[0] + return el && !isObject(el) ? el : $(el) + }, + last: function(){ + var el = this[this.length - 1] + return el && !isObject(el) ? el : $(el) + }, + find: function(selector){ + var result, $this = this + if (!selector) result = $() + else if (typeof selector == 'object') + result = $(selector).filter(function(){ + var node = this + return emptyArray.some.call($this, function(parent){ + return $.contains(parent, node) + }) + }) + else if (this.length == 1) result = $(zepto.qsa(this[0], selector)) + else result = this.map(function(){ return zepto.qsa(this, selector) }) + return result + }, + closest: function(selector, context){ + var nodes = [], collection = typeof selector == 'object' && $(selector) + this.each(function(_, node){ + while (node && !(collection ? collection.indexOf(node) >= 0 : zepto.matches(node, selector))) + node = node !== context && !isDocument(node) && node.parentNode + if (node && nodes.indexOf(node) < 0) nodes.push(node) + }) + return $(nodes) + }, + parents: function(selector){ + var ancestors = [], nodes = this + while (nodes.length > 0) + nodes = $.map(nodes, function(node){ + if ((node = node.parentNode) && !isDocument(node) && ancestors.indexOf(node) < 0) { + ancestors.push(node) + return node + } + }) + return filtered(ancestors, selector) + }, + parent: function(selector){ + return filtered(uniq(this.pluck('parentNode')), selector) + }, + children: function(selector){ + return filtered(this.map(function(){ return children(this) }), selector) + }, + contents: function() { + return this.map(function() { return this.contentDocument || slice.call(this.childNodes) }) + }, + siblings: function(selector){ + return filtered(this.map(function(i, el){ + return filter.call(children(el.parentNode), function(child){ return child!==el }) + }), selector) + }, + empty: function(){ + return this.each(function(){ this.innerHTML = '' }) + }, + // `pluck` is borrowed from Prototype.js + pluck: function(property){ + return $.map(this, function(el){ return el[property] }) + }, + show: function(){ + return this.each(function(){ + this.style.display == "none" && (this.style.display = '') + if (getComputedStyle(this, '').getPropertyValue("display") == "none") + this.style.display = defaultDisplay(this.nodeName) + }) + }, + replaceWith: function(newContent){ + return this.before(newContent).remove() + }, + wrap: function(structure){ + var func = isFunction(structure) + if (this[0] && !func) + var dom = $(structure).get(0), + clone = dom.parentNode || this.length > 1 + + return this.each(function(index){ + $(this).wrapAll( + func ? structure.call(this, index) : + clone ? dom.cloneNode(true) : dom + ) + }) + }, + wrapAll: function(structure){ + if (this[0]) { + $(this[0]).before(structure = $(structure)) + var children + // drill down to the inmost element + while ((children = structure.children()).length) structure = children.first() + $(structure).append(this) + } + return this + }, + wrapInner: function(structure){ + var func = isFunction(structure) + return this.each(function(index){ + var self = $(this), contents = self.contents(), + dom = func ? structure.call(this, index) : structure + contents.length ? contents.wrapAll(dom) : self.append(dom) + }) + }, + unwrap: function(){ + this.parent().each(function(){ + $(this).replaceWith($(this).children()) + }) + return this + }, + clone: function(){ + return this.map(function(){ return this.cloneNode(true) }) + }, + hide: function(){ + return this.css("display", "none") + }, + toggle: function(setting){ + return this.each(function(){ + var el = $(this) + ;(setting === undefined ? el.css("display") == "none" : setting) ? el.show() : el.hide() + }) + }, + prev: function(selector){ return $(this.pluck('previousElementSibling')).filter(selector || '*') }, + next: function(selector){ return $(this.pluck('nextElementSibling')).filter(selector || '*') }, + html: function(html){ + return 0 in arguments ? + this.each(function(idx){ + var originHtml = this.innerHTML + $(this).empty().append( funcArg(this, html, idx, originHtml) ) + }) : + (0 in this ? this[0].innerHTML : null) + }, + text: function(text){ + return 0 in arguments ? + this.each(function(idx){ + var newText = funcArg(this, text, idx, this.textContent) + this.textContent = newText == null ? '' : ''+newText + }) : + (0 in this ? this.pluck('textContent').join("") : null) + }, + attr: function(name, value){ + var result + return (typeof name == 'string' && !(1 in arguments)) ? + (0 in this && this[0].nodeType == 1 && (result = this[0].getAttribute(name)) != null ? result : undefined) : + this.each(function(idx){ + if (this.nodeType !== 1) return + if (isObject(name)) for (key in name) setAttribute(this, key, name[key]) + else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name))) + }) + }, + removeAttr: function(name){ + return this.each(function(){ this.nodeType === 1 && name.split(' ').forEach(function(attribute){ + setAttribute(this, attribute) + }, this)}) + }, + prop: function(name, value){ + name = propMap[name] || name + return (1 in arguments) ? + this.each(function(idx){ + this[name] = funcArg(this, value, idx, this[name]) + }) : + (this[0] && this[0][name]) + }, + removeProp: function(name){ + name = propMap[name] || name + return this.each(function(){ delete this[name] }) + }, + data: function(name, value){ + var attrName = 'data-' + name.replace(capitalRE, '-$1').toLowerCase() + + var data = (1 in arguments) ? + this.attr(attrName, value) : + this.attr(attrName) + + return data !== null ? deserializeValue(data) : undefined + }, + val: function(value){ + if (0 in arguments) { + if (value == null) value = "" + return this.each(function(idx){ + this.value = funcArg(this, value, idx, this.value) + }) + } else { + return this[0] && (this[0].multiple ? + $(this[0]).find('option').filter(function(){ return this.selected }).pluck('value') : + this[0].value) + } + }, + offset: function(coordinates){ + if (coordinates) return this.each(function(index){ + var $this = $(this), + coords = funcArg(this, coordinates, index, $this.offset()), + parentOffset = $this.offsetParent().offset(), + props = { + top: coords.top - parentOffset.top, + left: coords.left - parentOffset.left + } + + if ($this.css('position') == 'static') props['position'] = 'relative' + $this.css(props) + }) + if (!this.length) return null + if (document.documentElement !== this[0] && !$.contains(document.documentElement, this[0])) + return {top: 0, left: 0} + var obj = this[0].getBoundingClientRect() + return { + left: obj.left + window.pageXOffset, + top: obj.top + window.pageYOffset, + width: Math.round(obj.width), + height: Math.round(obj.height) + } + }, + css: function(property, value){ + if (arguments.length < 2) { + var element = this[0] + if (typeof property == 'string') { + if (!element) return + return element.style[camelize(property)] || getComputedStyle(element, '').getPropertyValue(property) + } else if (isArray(property)) { + if (!element) return + var props = {} + var computedStyle = getComputedStyle(element, '') + $.each(property, function(_, prop){ + props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop)) + }) + return props + } + } + + var css = '' + if (type(property) == 'string') { + if (!value && value !== 0) + this.each(function(){ this.style.removeProperty(dasherize(property)) }) + else + css = dasherize(property) + ":" + maybeAddPx(property, value) + } else { + for (key in property) + if (!property[key] && property[key] !== 0) + this.each(function(){ this.style.removeProperty(dasherize(key)) }) + else + css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';' + } + + return this.each(function(){ this.style.cssText += ';' + css }) + }, + index: function(element){ + return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0]) + }, + hasClass: function(name){ + if (!name) return false + return emptyArray.some.call(this, function(el){ + return this.test(className(el)) + }, classRE(name)) + }, + addClass: function(name){ + if (!name) return this + return this.each(function(idx){ + if (!('className' in this)) return + classList = [] + var cls = className(this), newName = funcArg(this, name, idx, cls) + newName.split(/\s+/g).forEach(function(klass){ + if (!$(this).hasClass(klass)) classList.push(klass) + }, this) + classList.length && className(this, cls + (cls ? " " : "") + classList.join(" ")) + }) + }, + removeClass: function(name){ + return this.each(function(idx){ + if (!('className' in this)) return + if (name === undefined) return className(this, '') + classList = className(this) + funcArg(this, name, idx, classList).split(/\s+/g).forEach(function(klass){ + classList = classList.replace(classRE(klass), " ") + }) + className(this, classList.trim()) + }) + }, + toggleClass: function(name, when){ + if (!name) return this + return this.each(function(idx){ + var $this = $(this), names = funcArg(this, name, idx, className(this)) + names.split(/\s+/g).forEach(function(klass){ + (when === undefined ? !$this.hasClass(klass) : when) ? + $this.addClass(klass) : $this.removeClass(klass) + }) + }) + }, + scrollTop: function(value){ + if (!this.length) return + var hasScrollTop = 'scrollTop' in this[0] + if (value === undefined) return hasScrollTop ? this[0].scrollTop : this[0].pageYOffset + return this.each(hasScrollTop ? + function(){ this.scrollTop = value } : + function(){ this.scrollTo(this.scrollX, value) }) + }, + scrollLeft: function(value){ + if (!this.length) return + var hasScrollLeft = 'scrollLeft' in this[0] + if (value === undefined) return hasScrollLeft ? this[0].scrollLeft : this[0].pageXOffset + return this.each(hasScrollLeft ? + function(){ this.scrollLeft = value } : + function(){ this.scrollTo(value, this.scrollY) }) + }, + position: function() { + if (!this.length) return + + var elem = this[0], + // Get *real* offsetParent + offsetParent = this.offsetParent(), + // Get correct offsets + offset = this.offset(), + parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset() + + // Subtract element margins + // note: when an element has margin: auto the offsetLeft and marginLeft + // are the same in Safari causing offset.left to incorrectly be 0 + offset.top -= parseFloat( $(elem).css('margin-top') ) || 0 + offset.left -= parseFloat( $(elem).css('margin-left') ) || 0 + + // Add offsetParent borders + parentOffset.top += parseFloat( $(offsetParent[0]).css('border-top-width') ) || 0 + parentOffset.left += parseFloat( $(offsetParent[0]).css('border-left-width') ) || 0 + + // Subtract the two offsets + return { + top: offset.top - parentOffset.top, + left: offset.left - parentOffset.left + } + }, + offsetParent: function() { + return this.map(function(){ + var parent = this.offsetParent || document.body + while (parent && !rootNodeRE.test(parent.nodeName) && $(parent).css("position") == "static") + parent = parent.offsetParent + return parent + }) + } + } + + // for now + $.fn.detach = $.fn.remove + + // Generate the `width` and `height` functions + ;['width', 'height'].forEach(function(dimension){ + var dimensionProperty = + dimension.replace(/./, function(m){ return m[0].toUpperCase() }) + + $.fn[dimension] = function(value){ + var offset, el = this[0] + if (value === undefined) return isWindow(el) ? el['inner' + dimensionProperty] : + isDocument(el) ? el.documentElement['scroll' + dimensionProperty] : + (offset = this.offset()) && offset[dimension] + else return this.each(function(idx){ + el = $(this) + el.css(dimension, funcArg(this, value, idx, el[dimension]())) + }) + } + }) + + function traverseNode(node, fun) { + fun(node) + for (var i = 0, len = node.childNodes.length; i < len; i++) + traverseNode(node.childNodes[i], fun) + } + + // Generate the `after`, `prepend`, `before`, `append`, + // `insertAfter`, `insertBefore`, `appendTo`, and `prependTo` methods. + adjacencyOperators.forEach(function(operator, operatorIndex) { + var inside = operatorIndex % 2 //=> prepend, append + + $.fn[operator] = function(){ + // arguments can be nodes, arrays of nodes, Zepto objects and HTML strings + var argType, nodes = $.map(arguments, function(arg) { + var arr = [] + argType = type(arg) + if (argType == "array") { + arg.forEach(function(el) { + if (el.nodeType !== undefined) return arr.push(el) + else if ($.zepto.isZ(el)) return arr = arr.concat(el.get()) + arr = arr.concat(zepto.fragment(el)) + }) + return arr + } + return argType == "object" || arg == null ? + arg : zepto.fragment(arg) + }), + parent, copyByClone = this.length > 1 + if (nodes.length < 1) return this + + return this.each(function(_, target){ + parent = inside ? target : target.parentNode + + // convert all methods to a "before" operation + target = operatorIndex == 0 ? target.nextSibling : + operatorIndex == 1 ? target.firstChild : + operatorIndex == 2 ? target : + null + + var parentInDocument = $.contains(document.documentElement, parent) + + nodes.forEach(function(node){ + if (copyByClone) node = node.cloneNode(true) + else if (!parent) return $(node).remove() + + parent.insertBefore(node, target) + if (parentInDocument) traverseNode(node, function(el){ + if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' && + (!el.type || el.type === 'text/javascript') && !el.src){ + var target = el.ownerDocument ? el.ownerDocument.defaultView : window + target['eval'].call(target, el.innerHTML) + } + }) + }) + }) + } + + // after => insertAfter + // prepend => prependTo + // before => insertBefore + // append => appendTo + $.fn[inside ? operator+'To' : 'insert'+(operatorIndex ? 'Before' : 'After')] = function(html){ + $(html)[operator](this) + return this + } + }) + + zepto.Z.prototype = Z.prototype = $.fn + + // Export internal API functions in the `$.zepto` namespace + zepto.uniq = uniq + zepto.deserializeValue = deserializeValue + $.zepto = zepto + + return $ +})() + +window.Zepto = Zepto +window.$ === undefined && (window.$ = Zepto) + +;(function($){ + var _zid = 1, undefined, + slice = Array.prototype.slice, + isFunction = $.isFunction, + isString = function(obj){ return typeof obj == 'string' }, + handlers = {}, + specialEvents={}, + focusinSupported = 'onfocusin' in window, + focus = { focus: 'focusin', blur: 'focusout' }, + hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' } + + specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents' + + function zid(element) { + return element._zid || (element._zid = _zid++) + } + function findHandlers(element, event, fn, selector) { + event = parse(event) + if (event.ns) var matcher = matcherFor(event.ns) + return (handlers[zid(element)] || []).filter(function(handler) { + return handler + && (!event.e || handler.e == event.e) + && (!event.ns || matcher.test(handler.ns)) + && (!fn || zid(handler.fn) === zid(fn)) + && (!selector || handler.sel == selector) + }) + } + function parse(event) { + var parts = ('' + event).split('.') + return {e: parts[0], ns: parts.slice(1).sort().join(' ')} + } + function matcherFor(ns) { + return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)') + } + + function eventCapture(handler, captureSetting) { + return handler.del && + (!focusinSupported && (handler.e in focus)) || + !!captureSetting + } + + function realEvent(type) { + return hover[type] || (focusinSupported && focus[type]) || type + } + + function add(element, events, fn, data, selector, delegator, capture){ + var id = zid(element), set = (handlers[id] || (handlers[id] = [])) + events.split(/\s/).forEach(function(event){ + if (event == 'ready') return $(document).ready(fn) + var handler = parse(event) + handler.fn = fn + handler.sel = selector + // emulate mouseenter, mouseleave + if (handler.e in hover) fn = function(e){ + var related = e.relatedTarget + if (!related || (related !== this && !$.contains(this, related))) + return handler.fn.apply(this, arguments) + } + handler.del = delegator + var callback = delegator || fn + handler.proxy = function(e){ + e = compatible(e) + if (e.isImmediatePropagationStopped()) return + e.data = data + var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args)) + if (result === false) e.preventDefault(), e.stopPropagation() + return result + } + handler.i = set.length + set.push(handler) + if ('addEventListener' in element) + element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + } + function remove(element, events, fn, selector, capture){ + var id = zid(element) + ;(events || '').split(/\s/).forEach(function(event){ + findHandlers(element, event, fn, selector).forEach(function(handler){ + delete handlers[id][handler.i] + if ('removeEventListener' in element) + element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + }) + } + + $.event = { add: add, remove: remove } + + $.proxy = function(fn, context) { + var args = (2 in arguments) && slice.call(arguments, 2) + if (isFunction(fn)) { + var proxyFn = function(){ return fn.apply(context, args ? args.concat(slice.call(arguments)) : arguments) } + proxyFn._zid = zid(fn) + return proxyFn + } else if (isString(context)) { + if (args) { + args.unshift(fn[context], fn) + return $.proxy.apply(null, args) + } else { + return $.proxy(fn[context], fn) + } + } else { + throw new TypeError("expected function") + } + } + + $.fn.bind = function(event, data, callback){ + return this.on(event, data, callback) + } + $.fn.unbind = function(event, callback){ + return this.off(event, callback) + } + $.fn.one = function(event, selector, data, callback){ + return this.on(event, selector, data, callback, 1) + } + + var returnTrue = function(){return true}, + returnFalse = function(){return false}, + ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$|webkitMovement[XY]$)/, + eventMethods = { + preventDefault: 'isDefaultPrevented', + stopImmediatePropagation: 'isImmediatePropagationStopped', + stopPropagation: 'isPropagationStopped' + } + + function compatible(event, source) { + if (source || !event.isDefaultPrevented) { + source || (source = event) + + $.each(eventMethods, function(name, predicate) { + var sourceMethod = source[name] + event[name] = function(){ + this[predicate] = returnTrue + return sourceMethod && sourceMethod.apply(source, arguments) + } + event[predicate] = returnFalse + }) + + event.timeStamp || (event.timeStamp = Date.now()) + + if (source.defaultPrevented !== undefined ? source.defaultPrevented : + 'returnValue' in source ? source.returnValue === false : + source.getPreventDefault && source.getPreventDefault()) + event.isDefaultPrevented = returnTrue + } + return event + } + + function createProxy(event) { + var key, proxy = { originalEvent: event } + for (key in event) + if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key] + + return compatible(proxy, event) + } + + $.fn.delegate = function(selector, event, callback){ + return this.on(event, selector, callback) + } + $.fn.undelegate = function(selector, event, callback){ + return this.off(event, selector, callback) + } + + $.fn.live = function(event, callback){ + $(document.body).delegate(this.selector, event, callback) + return this + } + $.fn.die = function(event, callback){ + $(document.body).undelegate(this.selector, event, callback) + return this + } + + $.fn.on = function(event, selector, data, callback, one){ + var autoRemove, delegator, $this = this + if (event && !isString(event)) { + $.each(event, function(type, fn){ + $this.on(type, selector, data, fn, one) + }) + return $this + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = data, data = selector, selector = undefined + if (callback === undefined || data === false) + callback = data, data = undefined + + if (callback === false) callback = returnFalse + + return $this.each(function(_, element){ + if (one) autoRemove = function(e){ + remove(element, e.type, callback) + return callback.apply(this, arguments) + } + + if (selector) delegator = function(e){ + var evt, match = $(e.target).closest(selector, element).get(0) + if (match && match !== element) { + evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element}) + return (autoRemove || callback).apply(match, [evt].concat(slice.call(arguments, 1))) + } + } + + add(element, event, callback, data, selector, delegator || autoRemove) + }) + } + $.fn.off = function(event, selector, callback){ + var $this = this + if (event && !isString(event)) { + $.each(event, function(type, fn){ + $this.off(type, selector, fn) + }) + return $this + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = selector, selector = undefined + + if (callback === false) callback = returnFalse + + return $this.each(function(){ + remove(this, event, callback, selector) + }) + } + + $.fn.trigger = function(event, args){ + event = (isString(event) || $.isPlainObject(event)) ? $.Event(event) : compatible(event) + event._args = args + return this.each(function(){ + // handle focus(), blur() by calling them directly + if (event.type in focus && typeof this[event.type] == "function") this[event.type]() + // items in the collection might not be DOM elements + else if ('dispatchEvent' in this) this.dispatchEvent(event) + else $(this).triggerHandler(event, args) + }) + } + + // triggers event handlers on current element just as if an event occurred, + // doesn't trigger an actual event, doesn't bubble + $.fn.triggerHandler = function(event, args){ + var e, result + this.each(function(i, element){ + e = createProxy(isString(event) ? $.Event(event) : event) + e._args = args + e.target = element + $.each(findHandlers(element, event.type || event), function(i, handler){ + result = handler.proxy(e) + if (e.isImmediatePropagationStopped()) return false + }) + }) + return result + } + + // shortcut methods for `.bind(event, fn)` for each event type + ;('focusin focusout focus blur load resize scroll unload click dblclick '+ + 'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave '+ + 'change select keydown keypress keyup error').split(' ').forEach(function(event) { + $.fn[event] = function(callback) { + return (0 in arguments) ? + this.bind(event, callback) : + this.trigger(event) + } + }) + + $.Event = function(type, props) { + if (!isString(type)) props = type, type = props.type + var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true + if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name]) + event.initEvent(type, bubbles, true) + return compatible(event) + } + +})(Zepto) + +;(function($){ + var jsonpID = +new Date(), + document = window.document, + key, + name, + rscript = /)<[^<]*)*<\/script>/gi, + scriptTypeRE = /^(?:text|application)\/javascript/i, + xmlTypeRE = /^(?:text|application)\/xml/i, + jsonType = 'application/json', + htmlType = 'text/html', + blankRE = /^\s*$/, + originAnchor = document.createElement('a') + + originAnchor.href = window.location.href + + // trigger a custom event and return false if it was cancelled + function triggerAndReturn(context, eventName, data) { + var event = $.Event(eventName) + $(context).trigger(event, data) + return !event.isDefaultPrevented() + } + + // trigger an Ajax "global" event + function triggerGlobal(settings, context, eventName, data) { + if (settings.global) return triggerAndReturn(context || document, eventName, data) + } + + // Number of active Ajax requests + $.active = 0 + + function ajaxStart(settings) { + if (settings.global && $.active++ === 0) triggerGlobal(settings, null, 'ajaxStart') + } + function ajaxStop(settings) { + if (settings.global && !(--$.active)) triggerGlobal(settings, null, 'ajaxStop') + } + + // triggers an extra global event "ajaxBeforeSend" that's like "ajaxSend" but cancelable + function ajaxBeforeSend(xhr, settings) { + var context = settings.context + if (settings.beforeSend.call(context, xhr, settings) === false || + triggerGlobal(settings, context, 'ajaxBeforeSend', [xhr, settings]) === false) + return false + + triggerGlobal(settings, context, 'ajaxSend', [xhr, settings]) + } + function ajaxSuccess(data, xhr, settings, deferred) { + var context = settings.context, status = 'success' + settings.success.call(context, data, status, xhr) + if (deferred) deferred.resolveWith(context, [data, status, xhr]) + triggerGlobal(settings, context, 'ajaxSuccess', [xhr, settings, data]) + ajaxComplete(status, xhr, settings) + } + // type: "timeout", "error", "abort", "parsererror" + function ajaxError(error, type, xhr, settings, deferred) { + var context = settings.context + settings.error.call(context, xhr, type, error) + if (deferred) deferred.rejectWith(context, [xhr, type, error]) + triggerGlobal(settings, context, 'ajaxError', [xhr, settings, error || type]) + ajaxComplete(type, xhr, settings) + } + // status: "success", "notmodified", "error", "timeout", "abort", "parsererror" + function ajaxComplete(status, xhr, settings) { + var context = settings.context + settings.complete.call(context, xhr, status) + triggerGlobal(settings, context, 'ajaxComplete', [xhr, settings]) + ajaxStop(settings) + } + + function ajaxDataFilter(data, type, settings) { + if (settings.dataFilter == empty) return data + var context = settings.context + return settings.dataFilter.call(context, data, type) + } + + // Empty function, used as default callback + function empty() {} + + $.ajaxJSONP = function(options, deferred){ + if (!('type' in options)) return $.ajax(options) + + var _callbackName = options.jsonpCallback, + callbackName = ($.isFunction(_callbackName) ? + _callbackName() : _callbackName) || ('Zepto' + (jsonpID++)), + script = document.createElement('script'), + originalCallback = window[callbackName], + responseData, + abort = function(errorType) { + $(script).triggerHandler('error', errorType || 'abort') + }, + xhr = { abort: abort }, abortTimeout + + if (deferred) deferred.promise(xhr) + + $(script).on('load error', function(e, errorType){ + clearTimeout(abortTimeout) + $(script).off().remove() + + if (e.type == 'error' || !responseData) { + ajaxError(null, errorType || 'error', xhr, options, deferred) + } else { + ajaxSuccess(responseData[0], xhr, options, deferred) + } + + window[callbackName] = originalCallback + if (responseData && $.isFunction(originalCallback)) + originalCallback(responseData[0]) + + originalCallback = responseData = undefined + }) + + if (ajaxBeforeSend(xhr, options) === false) { + abort('abort') + return xhr + } + + window[callbackName] = function(){ + responseData = arguments + } + + script.src = options.url.replace(/\?(.+)=\?/, '?$1=' + callbackName) + document.head.appendChild(script) + + if (options.timeout > 0) abortTimeout = setTimeout(function(){ + abort('timeout') + }, options.timeout) + + return xhr + } + + $.ajaxSettings = { + // Default type of request + type: 'GET', + // Callback that is executed before request + beforeSend: empty, + // Callback that is executed if the request succeeds + success: empty, + // Callback that is executed the the server drops error + error: empty, + // Callback that is executed on request complete (both: error and success) + complete: empty, + // The context for the callbacks + context: null, + // Whether to trigger "global" Ajax events + global: true, + // Transport + xhr: function () { + return new window.XMLHttpRequest() + }, + // MIME types mapping + // IIS returns Javascript as "application/x-javascript" + accepts: { + script: 'text/javascript, application/javascript, application/x-javascript', + json: jsonType, + xml: 'application/xml, text/xml', + html: htmlType, + text: 'text/plain' + }, + // Whether the request is to another domain + crossDomain: false, + // Default timeout + timeout: 0, + // Whether data should be serialized to string + processData: true, + // Whether the browser should be allowed to cache GET responses + cache: true, + //Used to handle the raw response data of XMLHttpRequest. + //This is a pre-filtering function to sanitize the response. + //The sanitized response should be returned + dataFilter: empty + } + + function mimeToDataType(mime) { + if (mime) mime = mime.split(';', 2)[0] + return mime && ( mime == htmlType ? 'html' : + mime == jsonType ? 'json' : + scriptTypeRE.test(mime) ? 'script' : + xmlTypeRE.test(mime) && 'xml' ) || 'text' + } + + function appendQuery(url, query) { + if (query == '') return url + return (url + '&' + query).replace(/[&?]{1,2}/, '?') + } + + // serialize payload and append it to the URL for GET requests + function serializeData(options) { + if (options.processData && options.data && $.type(options.data) != "string") + options.data = $.param(options.data, options.traditional) + if (options.data && (!options.type || options.type.toUpperCase() == 'GET' || 'jsonp' == options.dataType)) + options.url = appendQuery(options.url, options.data), options.data = undefined + } + + $.ajax = function(options){ + var settings = $.extend({}, options || {}), + deferred = $.Deferred && $.Deferred(), + urlAnchor, hashIndex + for (key in $.ajaxSettings) if (settings[key] === undefined) settings[key] = $.ajaxSettings[key] + + ajaxStart(settings) + + if (!settings.crossDomain) { + urlAnchor = document.createElement('a') + urlAnchor.href = settings.url + // cleans up URL for .href (IE only), see https://github.com/madrobby/zepto/pull/1049 + urlAnchor.href = urlAnchor.href + settings.crossDomain = (originAnchor.protocol + '//' + originAnchor.host) !== (urlAnchor.protocol + '//' + urlAnchor.host) + } + + if (!settings.url) settings.url = window.location.toString() + if ((hashIndex = settings.url.indexOf('#')) > -1) settings.url = settings.url.slice(0, hashIndex) + serializeData(settings) + + var dataType = settings.dataType, hasPlaceholder = /\?.+=\?/.test(settings.url) + if (hasPlaceholder) dataType = 'jsonp' + + if (settings.cache === false || ( + (!options || options.cache !== true) && + ('script' == dataType || 'jsonp' == dataType) + )) + settings.url = appendQuery(settings.url, '_=' + Date.now()) + + if ('jsonp' == dataType) { + if (!hasPlaceholder) + settings.url = appendQuery(settings.url, + settings.jsonp ? (settings.jsonp + '=?') : settings.jsonp === false ? '' : 'callback=?') + return $.ajaxJSONP(settings, deferred) + } + + var mime = settings.accepts[dataType], + headers = { }, + setHeader = function(name, value) { headers[name.toLowerCase()] = [name, value] }, + protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol, + xhr = settings.xhr(), + nativeSetHeader = xhr.setRequestHeader, + abortTimeout + + if (deferred) deferred.promise(xhr) + + if (!settings.crossDomain) setHeader('X-Requested-With', 'XMLHttpRequest') + setHeader('Accept', mime || '*/*') + if (mime = settings.mimeType || mime) { + if (mime.indexOf(',') > -1) mime = mime.split(',', 2)[0] + xhr.overrideMimeType && xhr.overrideMimeType(mime) + } + if (settings.contentType || (settings.contentType !== false && settings.data && settings.type.toUpperCase() != 'GET')) + setHeader('Content-Type', settings.contentType || 'application/x-www-form-urlencoded') + + if (settings.headers) for (name in settings.headers) setHeader(name, settings.headers[name]) + xhr.setRequestHeader = setHeader + + xhr.onreadystatechange = function(){ + if (xhr.readyState == 4) { + xhr.onreadystatechange = empty + clearTimeout(abortTimeout) + var result, error = false + if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 || (xhr.status == 0 && protocol == 'file:')) { + dataType = dataType || mimeToDataType(settings.mimeType || xhr.getResponseHeader('content-type')) + + if (xhr.responseType == 'arraybuffer' || xhr.responseType == 'blob') + result = xhr.response + else { + result = xhr.responseText + + try { + // http://perfectionkills.com/global-eval-what-are-the-options/ + // sanitize response accordingly if data filter callback provided + result = ajaxDataFilter(result, dataType, settings) + if (dataType == 'script') (1,eval)(result) + else if (dataType == 'xml') result = xhr.responseXML + else if (dataType == 'json') result = blankRE.test(result) ? null : $.parseJSON(result) + } catch (e) { error = e } + + if (error) return ajaxError(error, 'parsererror', xhr, settings, deferred) + } + + ajaxSuccess(result, xhr, settings, deferred) + } else { + ajaxError(xhr.statusText || null, xhr.status ? 'error' : 'abort', xhr, settings, deferred) + } + } + } + + if (ajaxBeforeSend(xhr, settings) === false) { + xhr.abort() + ajaxError(null, 'abort', xhr, settings, deferred) + return xhr + } + + var async = 'async' in settings ? settings.async : true + xhr.open(settings.type, settings.url, async, settings.username, settings.password) + + if (settings.xhrFields) for (name in settings.xhrFields) xhr[name] = settings.xhrFields[name] + + for (name in headers) nativeSetHeader.apply(xhr, headers[name]) + + if (settings.timeout > 0) abortTimeout = setTimeout(function(){ + xhr.onreadystatechange = empty + xhr.abort() + ajaxError(null, 'timeout', xhr, settings, deferred) + }, settings.timeout) + + // avoid sending empty string (#319) + xhr.send(settings.data ? settings.data : null) + return xhr + } + + // handle optional data/success arguments + function parseArguments(url, data, success, dataType) { + if ($.isFunction(data)) dataType = success, success = data, data = undefined + if (!$.isFunction(success)) dataType = success, success = undefined + return { + url: url + , data: data + , success: success + , dataType: dataType + } + } + + $.get = function(/* url, data, success, dataType */){ + return $.ajax(parseArguments.apply(null, arguments)) + } + + $.post = function(/* url, data, success, dataType */){ + var options = parseArguments.apply(null, arguments) + options.type = 'POST' + return $.ajax(options) + } + + $.getJSON = function(/* url, data, success */){ + var options = parseArguments.apply(null, arguments) + options.dataType = 'json' + return $.ajax(options) + } + + $.fn.load = function(url, data, success){ + if (!this.length) return this + var self = this, parts = url.split(/\s/), selector, + options = parseArguments(url, data, success), + callback = options.success + if (parts.length > 1) options.url = parts[0], selector = parts[1] + options.success = function(response){ + self.html(selector ? + $('
').html(response.replace(rscript, "")).find(selector) + : response) + callback && callback.apply(self, arguments) + } + $.ajax(options) + return this + } + + var escape = encodeURIComponent + + function serialize(params, obj, traditional, scope){ + var type, array = $.isArray(obj), hash = $.isPlainObject(obj) + $.each(obj, function(key, value) { + type = $.type(value) + if (scope) key = traditional ? scope : + scope + '[' + (hash || type == 'object' || type == 'array' ? key : '') + ']' + // handle data in serializeArray() format + if (!scope && array) params.add(value.name, value.value) + // recurse into nested objects + else if (type == "array" || (!traditional && type == "object")) + serialize(params, value, traditional, key) + else params.add(key, value) + }) + } + + $.param = function(obj, traditional){ + var params = [] + params.add = function(key, value) { + if ($.isFunction(value)) value = value() + if (value == null) value = "" + this.push(escape(key) + '=' + escape(value)) + } + serialize(params, obj, traditional) + return params.join('&').replace(/%20/g, '+') + } +})(Zepto) + +;(function($){ + $.fn.serializeArray = function() { + var name, type, result = [], + add = function(value) { + if (value.forEach) return value.forEach(add) + result.push({ name: name, value: value }) + } + if (this[0]) $.each(this[0].elements, function(_, field){ + type = field.type, name = field.name + if (name && field.nodeName.toLowerCase() != 'fieldset' && + !field.disabled && type != 'submit' && type != 'reset' && type != 'button' && type != 'file' && + ((type != 'radio' && type != 'checkbox') || field.checked)) + add($(field).val()) + }) + return result + } + + $.fn.serialize = function(){ + var result = [] + this.serializeArray().forEach(function(elm){ + result.push(encodeURIComponent(elm.name) + '=' + encodeURIComponent(elm.value)) + }) + return result.join('&') + } + + $.fn.submit = function(callback) { + if (0 in arguments) this.bind('submit', callback) + else if (this.length) { + var event = $.Event('submit') + this.eq(0).trigger(event) + if (!event.isDefaultPrevented()) this.get(0).submit() + } + return this + } + +})(Zepto) + +;(function(){ + // getComputedStyle shouldn't freak out when called + // without a valid element as argument + try { + getComputedStyle(undefined) + } catch(e) { + var nativeGetComputedStyle = getComputedStyle + window.getComputedStyle = function(element, pseudoElement){ + try { + return nativeGetComputedStyle(element, pseudoElement) + } catch(e) { + return null + } + } + } +})() + return Zepto +}))