├── configs
├── api_cfg.js
├── build
│ ├── webpack.development.js
│ ├── webpack.production.js
│ └── webpack.base.js
└── site_cfg.js
├── models
└── .gitkeep
├── controllers
└── index.js
├── middlewares
└── .gitkeep
├── public
└── src
│ ├── styles
│ ├── main.scss
│ └── icon.scss
│ ├── scripts
│ └── common
│ │ └── index.js
│ ├── fonts
│ ├── iconfont.eot
│ ├── iconfont.ttf
│ ├── iconfont.woff
│ └── iconfont.svg
│ └── js
│ ├── core.js.map
│ ├── core.js
│ ├── common.js.map
│ └── common.js
├── views
└── dev
│ ├── home
│ └── index.html
│ └── layouts
│ └── main.html
├── routers
├── index.js
└── home.js
├── test
└── test.js
├── kits
├── cache_kit.js
├── logger_kit.js
└── api_kit.js
├── .eslintrc.js
├── .jsbeautifyrc
├── README.md
├── .gitignore
├── app.js
├── package.json
└── gulpfile.js
/configs/api_cfg.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/models/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/controllers/index.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/middlewares/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/src/styles/main.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/src/scripts/common/index.js:
--------------------------------------------------------------------------------
1 | const $ = require('zepto');
2 |
--------------------------------------------------------------------------------
/views/dev/home/index.html:
--------------------------------------------------------------------------------
1 | {% extends 'layouts/main.html' %}
2 |
3 | {% block body %}
4 | 测试
5 | {% endblock %}
--------------------------------------------------------------------------------
/public/src/fonts/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaylinwang/koa-skeleton/HEAD/public/src/fonts/iconfont.eot
--------------------------------------------------------------------------------
/public/src/fonts/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaylinwang/koa-skeleton/HEAD/public/src/fonts/iconfont.ttf
--------------------------------------------------------------------------------
/public/src/fonts/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jaylinwang/koa-skeleton/HEAD/public/src/fonts/iconfont.woff
--------------------------------------------------------------------------------
/configs/build/webpack.development.js:
--------------------------------------------------------------------------------
1 | const merge = require('webpack-merge');
2 | const webpackBaseCfg = require('./webpack.base');
3 |
4 | module.exports = merge(webpackBaseCfg, {
5 | cache: true,
6 | devtool: '#source-map',
7 | });
8 |
--------------------------------------------------------------------------------
/routers/index.js:
--------------------------------------------------------------------------------
1 | const Router = require('koa-router');
2 | const homeRouter = require('./home');
3 |
4 | const router = new Router();
5 |
6 | router.use('/', homeRouter.routes(), homeRouter.allowedMethods());
7 |
8 | module.exports = router;
9 |
--------------------------------------------------------------------------------
/routers/home.js:
--------------------------------------------------------------------------------
1 | const Router = require('koa-router');
2 |
3 | const router = new Router();
4 |
5 | router.get('/', (ctx, next) => {
6 | return next().then(() => {
7 | // ctx.body = 'home';
8 | return ctx.render('home/index');
9 | });
10 | });
11 |
12 | module.exports = router;
13 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava';
2 |
3 | const apiKit = require('../kits/api_kit');
4 |
5 | test('api_request', t => {
6 | const promise = apiKit.post('http://ht.p.jx-cloud.cc:3032/api/pub/live/getLatestCourses');
7 | return promise.then(body => {
8 | t.deepEqual({
9 | ret: -212,
10 | message: 'invalid client_id',
11 | }, body);
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/configs/build/webpack.production.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const merge = require('webpack-merge');
3 | const webpackBaseCfg = require('./webpack.base');
4 |
5 | module.exports = merge(webpackBaseCfg, {
6 | cache: true,
7 | devtool: '#source-map',
8 | plugins: [
9 | new webpack.optimize.UglifyJsPlugin({
10 | compress: {
11 | warnings: false,
12 | },
13 | }),
14 | ],
15 | });
16 |
--------------------------------------------------------------------------------
/views/dev/layouts/main.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{brandName}}
7 |
8 | {% block style %}
9 |
10 | {% endblock %}
11 |
12 |
13 |
14 | {% block body %}
15 |
16 | {% endblock %}
17 |
18 | {% block script %}
19 |
20 | {% endblock %}
21 |
22 |
23 |
--------------------------------------------------------------------------------
/kits/cache_kit.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const bunyan = require('bunyan');
4 | const Redis = require('ioredis');
5 |
6 | const logger = bunyan.createLogger({
7 | name: 'api request',
8 | });
9 |
10 | module.exports = (opts) => {
11 | const redis = new Redis(opts);
12 | redis.on('error', (err) => {
13 | if (err) {
14 | logger.error('connect to redis error, check your redis config', err);
15 | process.exit(1);
16 | }
17 | });
18 | return redis;
19 | };
20 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "extends": "airbnb",
3 | "rules": {
4 | strict: "off",
5 | "indent": [
6 | "error",
7 | 4, {
8 | "SwitchCase": 1
9 | }
10 | ],
11 | "max-len": ["error", 120, 4],
12 | "func-names": ["error", "never"],
13 | "import/no-extraneous-dependencies": ["error", {
14 | "devDependencies": true,
15 | "optionalDependencies": false,
16 | "peerDependencies": false
17 | }]
18 | }
19 | };
20 |
--------------------------------------------------------------------------------
/kits/logger_kit.js:
--------------------------------------------------------------------------------
1 | const bunyan = require('bunyan');
2 |
3 | function reqSerializer(req) {
4 | return {
5 | method: req.method,
6 | url: req.uri.href,
7 | headers: req.headers,
8 | body: req.body,
9 | };
10 | }
11 |
12 | const logger = bunyan.createLogger({
13 | name: 'hiteacher',
14 | streams: [{
15 | level: 'info',
16 | stream: process.stdout,
17 | }, {
18 | level: 'error',
19 | stream: process.stdout,
20 | }],
21 | serializers: {
22 | req: reqSerializer,
23 | },
24 | });
25 |
26 | module.exports = logger;
27 |
--------------------------------------------------------------------------------
/.jsbeautifyrc:
--------------------------------------------------------------------------------
1 | {
2 | "indent_size": 4,
3 | "indent_char": " ",
4 | "eol": "\n",
5 | "indent_level": 0,
6 | "indent_with_tabs": false,
7 | "preserve_newlines": true,
8 | "max_preserve_newlines": 10,
9 | "jslint_happy": true,
10 | "space_after_anon_function": false,
11 | "brace_style": "collapse",
12 | "keep_array_indentation": false,
13 | "keep_function_indentation": false,
14 | "space_before_conditional": true,
15 | "break_chained_methods": false,
16 | "eval_code": false,
17 | "unescape_strings": false,
18 | "wrap_line_length": 0,
19 | "wrap_attributes": "auto",
20 | "wrap_attributes_indent_size": 4,
21 | "end_with_newline": true
22 | }
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # koa-skeleton
2 |
3 | ## 项目描述
4 |
5 | 基于koa2的web项目架子,自娱自乐,仅供参考,欢迎指正 :)
6 |
7 | ## 目录结构
8 |
9 | `+`表示一级目录,`++`表示二级目录,`+++`表示三级级目录,
10 |
11 | ```
12 | + configs(项目配置文件目录)
13 | ++ build(项目编译相关配置) *
14 |
15 | + controllers(项目业务控制代码目录)
16 |
17 | + kits(常用工具包)
18 |
19 | + middlewares(项目中间件)
20 |
21 | + models(业务数据对象,可以是操作数据库,可以是来源于调用api)
22 |
23 | + public(静态资源目录)
24 | ++ src(项目静态资源源文件)
25 | +++ fonts(字体文件)
26 | +++ iamges(图片)
27 | +++ styles(未编译样式脚本,本项目使用sass)
28 | +++ scripts(未编译js脚本,本项目部分使用es6)
29 | ++ publish(项目静态资源发布文件,发布自动生成)
30 |
31 | + routers(路由配置文件目录)
32 |
33 | + test(项目相关测试文件)
34 |
35 | + views(项目视图目录)
36 | ++ dev(开发视图文件)
37 | ++ pro(发布视图文件,发布自动生成)
38 |
39 | + app.js(项目入口)
40 |
41 | ```
42 |
43 | ## License
44 |
45 | MIT - [@jaylinwang](https://github.com/jaylinwang)
46 |
47 |
--------------------------------------------------------------------------------
/public/src/styles/icon.scss:
--------------------------------------------------------------------------------
1 | @font-face {font-family: "iconfont";
2 | src: url('../fonts/iconfont.eot?t=1472017686'); /* IE9*/
3 | src: url('../fonts/iconfont.eot?t=1472017686#iefix') format('embedded-opentype'), /* IE6-IE8 */
4 | url('../fonts/iconfont.woff?t=1472017686') format('woff'), /* chrome, firefox */
5 | url('../fonts/iconfont.ttf?t=1472017686') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
6 | url('../fonts/iconfont.svg?t=1472017686#iconfont') format('svg'); /* iOS 4.1- */
7 | }
8 |
9 | .iconfont {
10 | font-family:"iconfont" !important;
11 | font-size:16px;
12 | font-style:normal;
13 | -webkit-font-smoothing: antialiased;
14 | -webkit-text-stroke-width: 0.2px;
15 | -moz-osx-font-smoothing: grayscale;
16 | }
17 | .icon-scan:before { content: "\e601"; }
18 | .icon-jiudianxinxi:before { content: "\e602"; }
19 | .icon-jingdian2:before { content: "\e600"; }
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Node template
3 | # Logs
4 | logs
5 | *.log
6 | npm-debug.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 |
13 | # Directory for instrumented libs generated by jscoverage/JSCover
14 | lib-cov
15 |
16 | # Coverage directory used by tools like istanbul
17 | coverage
18 |
19 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
20 | .grunt
21 |
22 | # node-waf configuration
23 | .lock-wscript
24 |
25 | # Compiled binary addons (http://nodejs.org/api/addons.html)
26 | public/build
27 | public/publish
28 | public/temp/upload_*
29 | public/temp/avatar_*
30 |
31 | # Dependency directory
32 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
33 | node_modules
34 | ### Example user template template
35 | ### Example user template
36 |
37 | # IntelliJ project files
38 | .idea
39 | *.iml
40 | out
41 | gen
42 |
43 | .DS_Store
44 | typings
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | const Koa = require('koa');
2 | const views = require('koa-views');
3 | const nunjucks = require('nunjucks');
4 | const session = require('koa-generic-session');
5 | const redisStore = require('koa-redis');
6 | const convert = require('koa-convert');
7 | const csrf = require('koa-csrf');
8 |
9 | const logger = require('./kits/logger_kit');
10 | const routers = require('./routers');
11 | const siteCfg = require('./configs/site_cfg');
12 |
13 | const app = new Koa();
14 |
15 | app.use(convert(session({
16 | store: redisStore(siteCfg.redis),
17 | })));
18 |
19 | app.use(convert(csrf()));
20 |
21 | app.use(views(siteCfg.view_path, {
22 | map: {
23 | html: 'nunjucks',
24 | },
25 | }));
26 |
27 | // nunjucks配置
28 | nunjucks.configure(siteCfg.view_path);
29 |
30 | app.use(routers.routes());
31 |
32 | app.listen(siteCfg.port, () => {
33 | logger.info({
34 | port: siteCfg.port,
35 | env: app.env,
36 | }, '服务器启动信息');
37 | });
38 |
--------------------------------------------------------------------------------
/configs/build/webpack.base.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const webpack = require('webpack');
3 | const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
4 | // const npmRoot = path.resolve(process.cwd(), 'node_modules');
5 |
6 | module.exports = {
7 | context: path.resolve(process.cwd(), 'public/src'),
8 | entry: {
9 | common: ['./scripts/common/index'],
10 | },
11 | output: {
12 | path: path.join(process.cwd(), 'public/src/js/'),
13 | publicPath: 'src/js/',
14 | filename: '[name].js',
15 | },
16 | resolve: {
17 | alias: {},
18 | },
19 | module: {
20 | loaders: [{
21 | test: /\.css$/,
22 | loaders: ['style', 'css'],
23 | }, {
24 | test: /\.(woff2?|svg)$/,
25 | loader: 'url?limit=10000',
26 | }, {
27 | test: /\.(ttf|eot)$/,
28 | loader: 'file',
29 | }, {
30 | test: /\.js$/,
31 | exclude: /node_modules/,
32 | loader: 'babel',
33 | query: {
34 | presets: ['es2015'],
35 | },
36 | }],
37 | },
38 | plugins: [
39 | new CommonsChunkPlugin({
40 | name: 'core',
41 | filename: 'core.js',
42 | }),
43 | new webpack.ProvidePlugin({}),
44 | ],
45 | };
46 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "koa-skeleton",
3 | "version": "0.1.0",
4 | "description": "koa-skeleton",
5 | "main": "app.js",
6 | "scripts": {
7 | "test": "ava",
8 | "wechat-dev": "gulp dev:wechat --use-strict"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/jaylinwang/koa-skeleton.git"
13 | },
14 | "keywords": [
15 | "koa-skeleton"
16 | ],
17 | "author": "JaylinWang",
18 | "license": "MIT",
19 | "dependencies": {
20 | "ava": "^0.16.0",
21 | "bluebird": "^3.4.1",
22 | "bunyan": "^1.8.1",
23 | "ioredis": "^2.3.0",
24 | "koa": "^2.0.0-alpha.5",
25 | "koa-convert": "^1.2.0",
26 | "koa-csrf": "^2.5.0",
27 | "koa-generic-session": "^1.11.3",
28 | "koa-redis": "^2.1.2",
29 | "koa-router": "^7.0.1",
30 | "koa-views": "^5.0.2",
31 | "lodash": "^4.15.0",
32 | "nunjucks": "^2.4.2",
33 | "request": "^2.74.0",
34 | "requestretry": "^1.10.0",
35 | "zepto": "^1.2.0"
36 | },
37 | "devDependencies": {
38 | "ava": "^0.16.0",
39 | "babel-core": "^6.13.2",
40 | "babel-loader": "^6.2.5",
41 | "babel-preset-es2015": "^6.13.2",
42 | "css-loader": "^0.24.0",
43 | "del": "^2.2.2",
44 | "eslint": "^3.3.1",
45 | "eslint-config-airbnb": "^10.0.1",
46 | "eslint-plugin-import": "^1.14.0",
47 | "eslint-plugin-jsx-a11y": "^2.1.0",
48 | "eslint-plugin-react": "^6.1.2",
49 | "file-loader": "^0.9.0",
50 | "gulp": "^3.9.1",
51 | "gulp-base64": "^0.1.3",
52 | "gulp-nodemon": "^2.1.0",
53 | "gulp-plumber": "^1.1.0",
54 | "gulp-rev": "^7.1.2",
55 | "gulp-rev-replace": "^0.4.3",
56 | "gulp-sass": "^2.3.2",
57 | "gulp-sequence": "^0.4.5",
58 | "gulp-util": "^3.0.7",
59 | "style-loader": "^0.13.1",
60 | "webpack": "^1.13.2",
61 | "webpack-merge": "^0.14.1"
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/kits/api_kit.js:
--------------------------------------------------------------------------------
1 | const bunyan = require('bunyan');
2 | const Promise = require('bluebird');
3 |
4 | const logger = bunyan.createLogger({
5 | name: 'api request',
6 | });
7 |
8 | const baseRequest = require('requestretry').defaults({
9 | gzip: true,
10 | encoding: 'utf8',
11 | headers: {
12 | 'User-Agent': 'request from node',
13 | },
14 | maxAttempts: 3, // 最大尝试次数
15 | retryDelay: 3000, // 每次重试间隔时间
16 | fullResponse: true,
17 | promiseFactory: (resolver) => new Promise(resolver),
18 | });
19 |
20 | /**
21 | * api请求
22 | * @param {string} url
23 | * @param {Object} data
24 | * @param {Object} options
25 | */
26 | const request = function (url, data, options) {
27 | const mData = Object.assign({}, data || {});
28 | const mOptions = Object.assign({
29 | url,
30 | form: mData,
31 | }, options || {});
32 | const beginDate = new Date();
33 | return baseRequest(mOptions).then((response) => {
34 | const time = new Date() - beginDate;
35 | logger.info(`request <${url}> cost ${time}`);
36 | try {
37 | const body = JSON.parse(response.body);
38 | if (body.ret !== -500 && body.ret !== -404) {
39 | return body;
40 | }
41 | logger.error({
42 | error: body,
43 | }, 'API请求错误');
44 | throw new Error('API请求错误');
45 | } catch (error) {
46 | throw new Error('API返回一个非json数据');
47 | }
48 | }).catch((error) => {
49 | logger.error({
50 | error,
51 | });
52 | });
53 | };
54 |
55 | /**
56 | * api post请求
57 | * @param {string} url
58 | * @param {Object} data
59 | * @param {Object} options
60 | */
61 | const post = function (url, data, options) {
62 | Object.assign({
63 | method: 'POST',
64 | }, options || {});
65 |
66 | return request(url, data, options);
67 | };
68 |
69 | /**
70 | * api get请求
71 | * @param {string} url
72 | * @param {Object} data
73 | * @param {Object} options
74 | */
75 | const get = function (url, data, options) {
76 | Object.assign({
77 | method: 'GET',
78 | }, options || {});
79 | return request(url, data, options);
80 | };
81 |
82 | exports.get = get;
83 | exports.post = post;
84 |
--------------------------------------------------------------------------------
/configs/site_cfg.js:
--------------------------------------------------------------------------------
1 | const config = {
2 | /**
3 | * 程序运行端口
4 | */
5 | port: 3000,
6 |
7 | /**
8 | * 静态资源路径
9 | */
10 | resource_url: '/build',
11 |
12 | /**
13 | * 视图路径
14 | */
15 | view_path: `${process.cwd()}/views/dev`,
16 |
17 | /**
18 | * redis
19 | */
20 | redis: {
21 | host: '',
22 | port: 6379,
23 | prefix: 'jaylinwang_session_',
24 | pass: '',
25 | db: 7,
26 | ttl: 60 * 60 * 2,
27 | },
28 |
29 | /**
30 | * session secret setting
31 | */
32 | session_secret: 'jaylinwang_secret',
33 |
34 | /**
35 | * auth_cookie_name setting
36 | */
37 | auth_cookie_name: 'sunny',
38 |
39 | /**
40 | * 执行上下文
41 | */
42 | scope: 'wechat',
43 |
44 | /**
45 | * 站点地址
46 | */
47 | site_url: 'http://172.16.1.224:4000',
48 | };
49 |
50 | //= ================================================
51 | // # 微信环境配置
52 | //= ================================================
53 |
54 | // 微信上下文
55 | //
56 | if (process.env.NODE_ENV === 'wechat-dev' ||
57 | process.env.NODE_ENV === 'wechat-preprod' ||
58 | process.env.NODE_ENV === 'wechat-prod') {
59 | config.scope = 'wechat';
60 | config.port = 4000;
61 | config.session_secret = 'jaylinwang_wechat_secret';
62 | config.auth_cookie_name = 'jaylinwang_wechat';
63 | config.site_url = 'http://172.16.1.224:4000';
64 | }
65 |
66 | // 预生产环境
67 | //
68 | if (process.env.NODE_ENV === 'wechat-preprod') {
69 | config.resource_url = '';
70 | config.site_url = 'http://w.jx-cloud.cc';
71 | config.view_path = `${process.cwd()}/views/pro`;
72 | }
73 |
74 | // 生产环境
75 | if (process.env.NODE_ENV === 'wechat-prod') {
76 | config.resource_url = '';
77 | config.site_url = 'http://jaylinwang_wechat.com.cn';
78 | config.view_path = `${process.cwd()}/views/pro`;
79 | config.redis = {
80 | // # 内网
81 | host: '',
82 | // # 外网
83 | // host: '120.24.44.32',
84 | port: 6379,
85 | pass: '',
86 | db: 7,
87 | prefix: 'jaylinwang_wechat_session_',
88 | ttl: 60 * 60 * 2,
89 | };
90 | }
91 |
92 | //= ================================================
93 | // # 手机网站环境配置
94 | //= ================================================
95 |
96 | // wap上下文
97 | if (process.env.NODE_ENV === 'wap-dev' ||
98 | process.env.NODE_ENV === 'wap-preprod' ||
99 | process.env.NODE_ENV === 'wap-prod') {
100 | config.scope = 'wap';
101 | config.port = 5000;
102 | config.session_secret = 'jaylinwang_wap_secret';
103 | config.auth_cookie_name = 'jaylinwang_wap';
104 | config.site_url = 'http://192.168.100.201:5000';
105 | }
106 |
107 | // 预生产环境
108 | if (process.env.NODE_ENV === 'wap-preprod') {
109 | config.resource_url = 'http://s.jxcstatic.com/wapstatics';
110 | config.site_url = 'http://w.jx-cloud.cc';
111 | config.view_path = `${process.cwd()}/views/pro`;
112 | }
113 |
114 | // 生产环境
115 | if (process.env.NODE_ENV === 'wap-prod') {
116 | config.resource_url = '';
117 | config.site_url = '';
118 | config.view_path = `${process.cwd()}/views/pro`;
119 | config.redis = {
120 | // # 内网
121 | host: '',
122 | // # 外网
123 | // host: '120.24.44.32',
124 | port: 6379,
125 | pass: '',
126 | db: 7,
127 | prefix: 'jaylinwang_wap_session_',
128 | ttl: 60 * 60 * 2,
129 | };
130 | }
131 |
132 | module.exports = config;
133 |
--------------------------------------------------------------------------------
/public/src/js/core.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["webpack:///webpack/bootstrap bffe3e89f13bb53bed3a"],"names":[],"mappings":";AAAA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAQ,oBAAoB;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,uBAAe;AACf;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,YAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,wEAAgE,aAAa;AAC7E;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA","file":"core.js","sourcesContent":[" \t// install a JSONP callback for chunk loading\n \tvar parentJsonpFunction = window[\"webpackJsonp\"];\n \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules) {\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, callbacks = [];\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(installedChunks[chunkId])\n \t\t\t\tcallbacks.push.apply(callbacks, installedChunks[chunkId]);\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tmodules[moduleId] = moreModules[moduleId];\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules);\n \t\twhile(callbacks.length)\n \t\t\tcallbacks.shift().call(null, __webpack_require__);\n \t\tif(moreModules[0]) {\n \t\t\tinstalledModules[0] = 0;\n \t\t\treturn __webpack_require__(0);\n \t\t}\n \t};\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// object to store loaded and loading chunks\n \t// \"0\" means \"already loaded\"\n \t// Array means \"loading\", array contains callbacks\n \tvar installedChunks = {\n \t\t1:0\n \t};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n \t// This file contains only the entry chunk.\n \t// The chunk loading function for additional chunks\n \t__webpack_require__.e = function requireEnsure(chunkId, callback) {\n \t\t// \"0\" is the signal for \"already loaded\"\n \t\tif(installedChunks[chunkId] === 0)\n \t\t\treturn callback.call(null, __webpack_require__);\n\n \t\t// an array means \"currently loading\".\n \t\tif(installedChunks[chunkId] !== undefined) {\n \t\t\tinstalledChunks[chunkId].push(callback);\n \t\t} else {\n \t\t\t// start chunk loading\n \t\t\tinstalledChunks[chunkId] = [callback];\n \t\t\tvar head = document.getElementsByTagName('head')[0];\n \t\t\tvar script = document.createElement('script');\n \t\t\tscript.type = 'text/javascript';\n \t\t\tscript.charset = 'utf-8';\n \t\t\tscript.async = true;\n\n \t\t\tscript.src = __webpack_require__.p + \"\" + chunkId + \".\" + ({\"0\":\"common\"}[chunkId]||chunkId) + \".js\";\n \t\t\thead.appendChild(script);\n \t\t}\n \t};\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"src/js/\";\n\n\n\n/** WEBPACK FOOTER **\n ** webpack/bootstrap bffe3e89f13bb53bed3a\n **/"],"sourceRoot":""}
--------------------------------------------------------------------------------
/public/src/js/core.js:
--------------------------------------------------------------------------------
1 | /******/ (function(modules) { // webpackBootstrap
2 | /******/ // install a JSONP callback for chunk loading
3 | /******/ var parentJsonpFunction = window["webpackJsonp"];
4 | /******/ window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules) {
5 | /******/ // add "moreModules" to the modules object,
6 | /******/ // then flag all "chunkIds" as loaded and fire callback
7 | /******/ var moduleId, chunkId, i = 0, callbacks = [];
8 | /******/ for(;i < chunkIds.length; i++) {
9 | /******/ chunkId = chunkIds[i];
10 | /******/ if(installedChunks[chunkId])
11 | /******/ callbacks.push.apply(callbacks, installedChunks[chunkId]);
12 | /******/ installedChunks[chunkId] = 0;
13 | /******/ }
14 | /******/ for(moduleId in moreModules) {
15 | /******/ modules[moduleId] = moreModules[moduleId];
16 | /******/ }
17 | /******/ if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules);
18 | /******/ while(callbacks.length)
19 | /******/ callbacks.shift().call(null, __webpack_require__);
20 | /******/ if(moreModules[0]) {
21 | /******/ installedModules[0] = 0;
22 | /******/ return __webpack_require__(0);
23 | /******/ }
24 | /******/ };
25 | /******/
26 | /******/ // The module cache
27 | /******/ var installedModules = {};
28 | /******/
29 | /******/ // object to store loaded and loading chunks
30 | /******/ // "0" means "already loaded"
31 | /******/ // Array means "loading", array contains callbacks
32 | /******/ var installedChunks = {
33 | /******/ 1:0
34 | /******/ };
35 | /******/
36 | /******/ // The require function
37 | /******/ function __webpack_require__(moduleId) {
38 | /******/
39 | /******/ // Check if module is in cache
40 | /******/ if(installedModules[moduleId])
41 | /******/ return installedModules[moduleId].exports;
42 | /******/
43 | /******/ // Create a new module (and put it into the cache)
44 | /******/ var module = installedModules[moduleId] = {
45 | /******/ exports: {},
46 | /******/ id: moduleId,
47 | /******/ loaded: false
48 | /******/ };
49 | /******/
50 | /******/ // Execute the module function
51 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
52 | /******/
53 | /******/ // Flag the module as loaded
54 | /******/ module.loaded = true;
55 | /******/
56 | /******/ // Return the exports of the module
57 | /******/ return module.exports;
58 | /******/ }
59 | /******/
60 | /******/ // This file contains only the entry chunk.
61 | /******/ // The chunk loading function for additional chunks
62 | /******/ __webpack_require__.e = function requireEnsure(chunkId, callback) {
63 | /******/ // "0" is the signal for "already loaded"
64 | /******/ if(installedChunks[chunkId] === 0)
65 | /******/ return callback.call(null, __webpack_require__);
66 | /******/
67 | /******/ // an array means "currently loading".
68 | /******/ if(installedChunks[chunkId] !== undefined) {
69 | /******/ installedChunks[chunkId].push(callback);
70 | /******/ } else {
71 | /******/ // start chunk loading
72 | /******/ installedChunks[chunkId] = [callback];
73 | /******/ var head = document.getElementsByTagName('head')[0];
74 | /******/ var script = document.createElement('script');
75 | /******/ script.type = 'text/javascript';
76 | /******/ script.charset = 'utf-8';
77 | /******/ script.async = true;
78 | /******/
79 | /******/ script.src = __webpack_require__.p + "" + chunkId + "." + ({"0":"common"}[chunkId]||chunkId) + ".js";
80 | /******/ head.appendChild(script);
81 | /******/ }
82 | /******/ };
83 | /******/
84 | /******/ // expose the modules object (__webpack_modules__)
85 | /******/ __webpack_require__.m = modules;
86 | /******/
87 | /******/ // expose the module cache
88 | /******/ __webpack_require__.c = installedModules;
89 | /******/
90 | /******/ // __webpack_public_path__
91 | /******/ __webpack_require__.p = "src/js/";
92 | /******/ })
93 | /************************************************************************/
94 | /******/ ([]);
95 | //# sourceMappingURL=core.js.map
--------------------------------------------------------------------------------
/public/src/fonts/iconfont.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
51 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const gulp = require('gulp');
4 | const gutil = require('gulp-util');
5 | const nodemon = require('gulp-nodemon');
6 | const webpack = require('webpack');
7 | const sass = require('gulp-sass');
8 | const base64 = require('gulp-base64');
9 | const rev = require('gulp-rev');
10 | const revReplace = require('gulp-rev-replace');
11 | const gulpSequence = require('gulp-sequence');
12 | const plumber = require('gulp-plumber');
13 | const del = require('del');
14 |
15 | const webpackDevCfg = require('./configs/build/webpack.development');
16 | const webpackProdCfg = require('./configs/build/webpack.production');
17 |
18 | //= =====================================================
19 | // # 公共操作
20 | // ## sass编译
21 | // ## 删除不想干文件
22 | //= ======================================================
23 |
24 | // 压缩合并css, css中既有自己写的.scss, 也有引入第三方库的.css
25 | gulp.task('build:sass', () => {
26 | gulp.src(['public/src/styles/*.scss'])
27 | .pipe(plumber())
28 | .pipe(sass({
29 | outputStyle: 'compressed',
30 | }))
31 | .pipe(base64())
32 | .pipe(gulp.dest('./public/src/css'));
33 | });
34 |
35 | // 删除目录
36 | gulp.task('clean', () => {
37 | del(['public/publish/**/*']).then(paths => {
38 | gutil.log('Deleted files and folders:\n', paths.join('\n'));
39 | });
40 | });
41 |
42 | //= ===========================================
43 | // # 开发相关操作
44 | // ## 编译js
45 | // ## 监听文件变化
46 | // ## nodemon模式启动
47 | //= ===========================================
48 |
49 | // 开发环境中编译js
50 | gulp.task('build:js-dev', () => {
51 | webpack(webpackDevCfg, (err, stats) => {
52 | if (err) {
53 | throw new gutil.PluginError('webpack', err);
54 | }
55 | gutil.log('[webpack]', stats.toString({
56 | colors: true,
57 | }));
58 | });
59 | });
60 |
61 | // 监听src下文件变化
62 | gulp.task('watch', () => {
63 | gulp.watch(['public/src/styles/**/*.scss'], ['build:sass']);
64 | gulp.watch('public/src/styles/**/*.js', ['build:js-dev']);
65 | });
66 |
67 | // nodemon setting
68 | gulp.task('nodemon:wap-dev', () => {
69 | nodemon({
70 | script: 'app.js',
71 | ext: 'js html',
72 | // ignore: ['public/**/*'],
73 | env: {
74 | NODE_ENV: 'wap-dev',
75 | },
76 | });
77 | });
78 | gulp.task('nodemon:wechat-dev', () => {
79 | nodemon({
80 | script: 'app.js',
81 | ext: 'js html',
82 | env: {
83 | NODE_ENV: 'wechat-dev',
84 | },
85 | });
86 | });
87 |
88 | // 开发任务入口
89 | gulp.task('dev:wechat', gulpSequence(
90 | ['build:sass', 'build:js-dev'],
91 | 'watch',
92 | 'nodemon:wechat-dev'
93 | ));
94 |
95 | gulp.task('dev:wap', gulpSequence(
96 | ['build:sass', 'build:js-dev'],
97 | 'watch',
98 | 'nodemon:wap-dev'
99 | ));
100 |
101 | //= ===========================================
102 | // # 发布到线上环境操作
103 | // ## 编译js
104 | // ## 文件md5后缀及文件中文件引入替换
105 | // ## 监听文件变化
106 | // ## nodemon模式启动
107 | //= ===========================================
108 |
109 | // # 生产环境中编译js
110 | gulp.task('build:js-pro', (cb) => {
111 | webpack(webpackProdCfg, (err, stats) => {
112 | if (err) {
113 | throw new gutil.PluginError('webpack', err);
114 | }
115 | gutil.log('[webpack]', stats.toString({
116 | colors: true,
117 | }));
118 | cb();
119 | });
120 | });
121 |
122 | // publish setting
123 | gulp.task('revision', () => {
124 | gulp.src(['public/src/**/*'])
125 | .pipe(plumber())
126 | .pipe(rev())
127 | .pipe(gulp.dest('public/publish'))
128 | .pipe(rev.manifest())
129 | .pipe(gulp.dest('public/publish'));
130 | });
131 | gulp.task('revreplace', () => {
132 | const manifest = gulp.src('public/publish/rev-manifest.json');
133 | return gulp.src('views/dev/**/*.html')
134 | .pipe(revReplace({
135 | manifest,
136 | }))
137 | .pipe(gulp.dest('views/prod'));
138 | });
139 |
140 | // nodemon setting
141 | gulp.task('nodemon:wap-preprod', () => {
142 | nodemon({
143 | script: 'app.js',
144 | ext: 'js hbs',
145 | ignore: [
146 | 'public/**/*', 'views/**/*',
147 | ],
148 | env: {
149 | NODE_ENV: 'wap-preprod',
150 | },
151 | });
152 | });
153 | gulp.task('nodemon:wechat-preprod', () => {
154 | nodemon({
155 | script: 'app.js',
156 | ext: 'js hbs',
157 | ignore: [
158 | 'public/**/*', 'views/**/*',
159 | ],
160 | env: {
161 | NODE_ENV: 'wechat-preprod',
162 | },
163 | });
164 | });
165 |
166 | // 发布任务入口
167 | gulp.task('publish:wechat', gulpSequence(
168 | 'clean', ['build:sass', 'build:js-pro'],
169 | 'revision',
170 | 'revreplace',
171 | 'nodemon:wechat-preprod'
172 | ));
173 | gulp.task('publish:wap', gulpSequence(
174 | 'clean', ['build:sass', 'build:js-pro'],
175 | 'revision',
176 | 'revreplace',
177 | 'nodemon:wap-preprod'
178 | ));
179 |
--------------------------------------------------------------------------------
/public/src/js/common.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["webpack:///./scripts/common/index.js","webpack:////Users/jaylinwang/Workspace/Mine/sunny-wechat/~/zepto/dist/zepto.js"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,KAAM,IAAI,oBAAQ,CAAR,CAAV,C;;;;;;ACAA;AACA;AACA;AACA,mDAAuB,yBAAyB;AAChD;AACA;AACA,EAAC;AACD;AACA;AACA;AACA,wBAAuB,iBAAiB;AACxC,kBAAiB,4GAA4G;AAC7H;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAK;AACL;AACA;AACA,oBAAmB;AACnB;AACA,eAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAK;AACL;AACA,wBAAuB;;AAEvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,+BAA8B;AAC9B,+BAA8B;AAC9B,+BAA8B;AAC9B,+BAA8B;AAC9B;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,4BAA2B,0CAA0C,sBAAsB;AAC3F,4BAA2B;AAC3B,4BAA2B,oDAAoD,sCAAsC;AACrH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAAyB,+CAA+C,oCAAoC;;AAE5G;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,gDAA+C,sCAAsC;AACrF;;AAEA;AACA;AACA,gBAAe,SAAS;AACxB;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,QAAO;AACP;;AAEA;AACA;AACA;AACA;AACA;AACA,QAAO;AACP;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gCAA+B,4BAA4B;AAC3D;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,MAAK;AACL;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAiB;AACjB;AACA;AACA,MAAK;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,gBAAe;AACf,aAAY;AACZ;;AAEA;AACA;AACA;AACA,kBAAiB,qBAAqB;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,kBAAiB,qBAAqB;AACtC;AACA,MAAK;AACL;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,IAAG;;AAEH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAiB,sBAAsB;AACvC;AACA;AACA;AACA;AACA,MAAK;;AAEL;AACA;AACA;AACA,4CAA2C,4BAA4B;AACvE,MAAK;AACL;AACA;AACA,MAAK;;AAEL;AACA;AACA;AACA;AACA,qEAAoE,cAAc;AAClF;AACA,MAAK;AACL;AACA;AACA,MAAK;AACL,yBAAwB,oBAAoB;AAC5C;AACA;AACA,MAAK;AACL;AACA;AACA;AACA;AACA,QAAO;AACP,MAAK;AACL;AACA;AACA;AACA,QAAO;AACP;AACA,MAAK;AACL;AACA;AACA;AACA;AACA,QAAO;AACP,MAAK;AACL;AACA;AACA,MAAK;AACL;AACA;AACA,MAAK;AACL;AACA;AACA;AACA;AACA;AACA,UAAS;AACT;AACA;AACA;AACA;AACA;AACA,UAAS;AACT;AACA;AACA,MAAK;AACL;AACA;AACA;AACA;AACA;AACA,QAAO;AACP,MAAK;AACL;AACA;AACA,MAAK;AACL;AACA;AACA;AACA,MAAK;AACL;AACA;AACA;AACA,MAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAW;AACX,UAAS;AACT;AACA,yCAAwC,mCAAmC;AAC3E;AACA,MAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,QAAO;AACP;AACA,MAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAS;AACT;AACA,MAAK;AACL;AACA;AACA,MAAK;AACL;AACA,2CAA0C,wBAAwB;AAClE,MAAK;AACL;AACA,mCAAkC,6DAA6D;AAC/F,MAAK;AACL;AACA;AACA,qEAAoE,oBAAoB;AACxF,QAAO;AACP,MAAK;AACL;AACA,mCAAkC,sBAAsB;AACxD,MAAK;AACL;AACA;AACA,uCAAsC,sBAAsB;AAC5D,MAAK;AACL;AACA;AACA;AACA;AACA;AACA,QAAO;AACP,MAAK;AACL;AACA;AACA,MAAK;AACL;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,QAAO;AACP,MAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,QAAO;AACP,MAAK;AACL;AACA;AACA;AACA,QAAO;AACP;AACA,MAAK;AACL;AACA,kCAAiC,8BAA8B;AAC/D,MAAK;AACL;AACA;AACA,MAAK;AACL;AACA;AACA;AACA,UAAS;AACT,QAAO;AACP,MAAK;AACL,8BAA6B,yEAAyE;AACtG,8BAA6B,qEAAqE;AAClG;AACA;AACA;AACA;AACA;AACA,UAAS;AACT;AACA,MAAK;AACL;AACA;AACA;AACA;AACA;AACA,UAAS;AACT;AACA,MAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAS;AACT,MAAK;AACL;AACA,mCAAkC;AAClC;AACA,QAAO,QAAQ;AACf,MAAK;AACL;AACA;AACA;AACA;AACA;AACA,UAAS;AACT;AACA,MAAK;AACL;AACA;AACA,mCAAkC,oBAAoB;AACtD,MAAK;AACL;AACA;;AAEA;AACA;AACA;;AAEA;AACA,MAAK;AACL;AACA;AACA;AACA;AACA;AACA,UAAS;AACT,QAAO;AACP;AACA,wDAAuD,uBAAuB;AAC9E;AACA;AACA,MAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,QAAO;AACP;AACA;AACA,iBAAgB;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,UAAS;AACT;AACA;AACA;AACA;AACA;AACA,YAAW;AACX;AACA;AACA;;AAEA;AACA;AACA;AACA,gCAA+B,iDAAiD;AAChF;AACA;AACA,QAAO;AACP;AACA;AACA,kCAAiC,4CAA4C;AAC7E;AACA,8EAA6E;AAC7E;;AAEA,mCAAkC,yBAAyB,SAAS;AACpE,MAAK;AACL;AACA;AACA,MAAK;AACL;AACA;AACA;AACA;AACA,QAAO;AACP,MAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAS;AACT;AACA,QAAO;AACP,MAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAS;AACT;AACA,QAAO;AACP,MAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAS;AACT,QAAO;AACP,MAAK;AACL;AACA;AACA;AACA;AACA;AACA,oBAAmB,yBAAyB;AAC5C,oBAAmB,qCAAqC;AACxD,MAAK;AACL;AACA;AACA;AACA;AACA;AACA,oBAAmB,0BAA0B;AAC7C,oBAAmB,qCAAqC;AACxD,MAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,qEAAoE,kBAAkB;;AAEtF;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,MAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,QAAO;AACP;AACA;;AAEA;AACA;;AAEA;AACA,IAAG;AACH;AACA,0CAAyC,4BAA4B;;AAErE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAO;AACP;AACA,IAAG;;AAEH;AACA;AACA,kDAAiD,SAAS;AAC1D;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAe;AACf;AACA;AACA;AACA;AACA,YAAW;AACX;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAW;AACX,UAAS;AACT,QAAO;AACP;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAG;;AAEH;;AAEA;AACA;AACA;AACA;;AAEA;AACA,EAAC;;AAED;AACA;;AAEA,EAAC;AACD;AACA;AACA;AACA,gCAA+B,gCAAgC;AAC/D,oBAAmB;AACnB,uBAAsB;AACtB;AACA,gBAAe,qCAAqC;AACpD,gBAAe;;AAEf;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAK;AACL;AACA;AACA;AACA,aAAY;AACZ;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAK;AACL;AACA;AACA;AACA,MAAK;AACL;AACA;AACA;AACA;AACA,QAAO;AACP,MAAK;AACL;;AAEA,cAAa;;AAEb;AACA;AACA;AACA,gCAA+B;AAC/B;AACA;AACA,MAAK;AACL;AACA;AACA;AACA,QAAO;AACP;AACA;AACA,MAAK;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,+BAA8B,YAAY;AAC1C,gCAA+B,aAAa;AAC5C;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAO;;AAEP;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,uBAAsB;AACtB;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,QAAO;AACP;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,2CAA0C,yCAAyC;AACnF;AACA;AACA;;AAEA;AACA,MAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,QAAO;AACP;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA,MAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAO;AACP,MAAK;AACL;AACA;;AAEA;AACA,IAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,EAAC;;AAED,EAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAO;AACP,cAAa,eAAe;;AAE5B;;AAEA;AACA;AACA;;AAEA;AACA;AACA,QAAO;AACP;AACA;;AAEA;AACA;AACA;;AAEA;AACA,MAAK;;AAEL;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,MAAK;;AAEL;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,mCAAkC;AAClC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,8CAA6C,IAAI;AACjD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,+BAA8B,eAAe;AAC7C;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,oBAAmB,EAAE;AACrB,4CAA2C,8CAA8C;AACzF;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAa,YAAY;;AAEzB;AACA;;AAEA;AACA,UAAS;AACT;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,QAAO;;AAEP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAC;;AAED,EAAC;AACD;AACA;AACA;AACA;AACA,sBAAqB,2BAA2B;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA,MAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,EAAC;;AAED,EAAC;AACD;AACA;AACA;AACA;AACA,IAAG;AACH;AACA;AACA;AACA;AACA,QAAO;AACP;AACA;AACA;AACA;AACA,EAAC;AACD;AACA,EAAC","file":"common.js","sourcesContent":["const $ = require('zepto');\n\n\n\n/** WEBPACK FOOTER **\n ** ./scripts/common/index.js\n **/","/* Zepto v1.2.0 - zepto event ajax form ie - zeptojs.com/license */\n(function(global, factory) {\n if (typeof define === 'function' && define.amd)\n define(function() { return factory(global) })\n else\n factory(global)\n}(this, function(window) {\n var Zepto = (function() {\n var undefined, key, $, classList, emptyArray = [], concat = emptyArray.concat, filter = emptyArray.filter, slice = emptyArray.slice,\n document = window.document,\n elementDisplay = {}, classCache = {},\n cssNumber = { 'column-count': 1, 'columns': 1, 'font-weight': 1, 'line-height': 1,'opacity': 1, 'z-index': 1, 'zoom': 1 },\n fragmentRE = /^\\s*<(\\w+|!)[^>]*>/,\n singleTagRE = /^<(\\w+)\\s*\\/?>(?:<\\/\\1>|)$/,\n tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/ig,\n rootNodeRE = /^(?:body|html)$/i,\n capitalRE = /([A-Z])/g,\n\n // special attributes that should be get/set via method calls\n methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'],\n\n adjacencyOperators = [ 'after', 'prepend', 'before', 'append' ],\n table = document.createElement('table'),\n tableRow = document.createElement('tr'),\n containers = {\n 'tr': document.createElement('tbody'),\n 'tbody': table, 'thead': table, 'tfoot': table,\n 'td': tableRow, 'th': tableRow,\n '*': document.createElement('div')\n },\n readyRE = /complete|loaded|interactive/,\n simpleSelectorRE = /^[\\w-]*$/,\n class2type = {},\n toString = class2type.toString,\n zepto = {},\n camelize, uniq,\n tempParent = document.createElement('div'),\n propMap = {\n 'tabindex': 'tabIndex',\n 'readonly': 'readOnly',\n 'for': 'htmlFor',\n 'class': 'className',\n 'maxlength': 'maxLength',\n 'cellspacing': 'cellSpacing',\n 'cellpadding': 'cellPadding',\n 'rowspan': 'rowSpan',\n 'colspan': 'colSpan',\n 'usemap': 'useMap',\n 'frameborder': 'frameBorder',\n 'contenteditable': 'contentEditable'\n },\n isArray = Array.isArray ||\n function(object){ return object instanceof Array }\n\n zepto.matches = function(element, selector) {\n if (!selector || !element || element.nodeType !== 1) return false\n var matchesSelector = element.matches || element.webkitMatchesSelector ||\n element.mozMatchesSelector || element.oMatchesSelector ||\n element.matchesSelector\n if (matchesSelector) return matchesSelector.call(element, selector)\n // fall back to performing a selector:\n var match, parent = element.parentNode, temp = !parent\n if (temp) (parent = tempParent).appendChild(element)\n match = ~zepto.qsa(parent, selector).indexOf(element)\n temp && tempParent.removeChild(element)\n return match\n }\n\n function type(obj) {\n return obj == null ? String(obj) :\n class2type[toString.call(obj)] || \"object\"\n }\n\n function isFunction(value) { return type(value) == \"function\" }\n function isWindow(obj) { return obj != null && obj == obj.window }\n function isDocument(obj) { return obj != null && obj.nodeType == obj.DOCUMENT_NODE }\n function isObject(obj) { return type(obj) == \"object\" }\n function isPlainObject(obj) {\n return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype\n }\n\n function likeArray(obj) {\n var length = !!obj && 'length' in obj && obj.length,\n type = $.type(obj)\n\n return 'function' != type && !isWindow(obj) && (\n 'array' == type || length === 0 ||\n (typeof length == 'number' && length > 0 && (length - 1) in obj)\n )\n }\n\n function compact(array) { return filter.call(array, function(item){ return item != null }) }\n function flatten(array) { return array.length > 0 ? $.fn.concat.apply([], array) : array }\n camelize = function(str){ return str.replace(/-+(.)?/g, function(match, chr){ return chr ? chr.toUpperCase() : '' }) }\n function dasherize(str) {\n return str.replace(/::/g, '/')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')\n .replace(/([a-z\\d])([A-Z])/g, '$1_$2')\n .replace(/_/g, '-')\n .toLowerCase()\n }\n uniq = function(array){ return filter.call(array, function(item, idx){ return array.indexOf(item) == idx }) }\n\n function classRE(name) {\n return name in classCache ?\n classCache[name] : (classCache[name] = new RegExp('(^|\\\\s)' + name + '(\\\\s|$)'))\n }\n\n function maybeAddPx(name, value) {\n return (typeof value == \"number\" && !cssNumber[dasherize(name)]) ? value + \"px\" : value\n }\n\n function defaultDisplay(nodeName) {\n var element, display\n if (!elementDisplay[nodeName]) {\n element = document.createElement(nodeName)\n document.body.appendChild(element)\n display = getComputedStyle(element, '').getPropertyValue(\"display\")\n element.parentNode.removeChild(element)\n display == \"none\" && (display = \"block\")\n elementDisplay[nodeName] = display\n }\n return elementDisplay[nodeName]\n }\n\n function children(element) {\n return 'children' in element ?\n slice.call(element.children) :\n $.map(element.childNodes, function(node){ if (node.nodeType == 1) return node })\n }\n\n function Z(dom, selector) {\n var i, len = dom ? dom.length : 0\n for (i = 0; i < len; i++) this[i] = dom[i]\n this.length = len\n this.selector = selector || ''\n }\n\n // `$.zepto.fragment` takes a html string and an optional tag name\n // to generate DOM nodes from the given html string.\n // The generated DOM nodes are returned as an array.\n // This function can be overridden in plugins for example to make\n // it compatible with browsers that don't support the DOM fully.\n zepto.fragment = function(html, name, properties) {\n var dom, nodes, container\n\n // A special case optimization for a single tag\n if (singleTagRE.test(html)) dom = $(document.createElement(RegExp.$1))\n\n if (!dom) {\n if (html.replace) html = html.replace(tagExpanderRE, \"<$1>$2>\")\n if (name === undefined) name = fragmentRE.test(html) && RegExp.$1\n if (!(name in containers)) name = '*'\n\n container = containers[name]\n container.innerHTML = '' + html\n dom = $.each(slice.call(container.childNodes), function(){\n container.removeChild(this)\n })\n }\n\n if (isPlainObject(properties)) {\n nodes = $(dom)\n $.each(properties, function(key, value) {\n if (methodAttributes.indexOf(key) > -1) nodes[key](value)\n else nodes.attr(key, value)\n })\n }\n\n return dom\n }\n\n // `$.zepto.Z` swaps out the prototype of the given `dom` array\n // of nodes with `$.fn` and thus supplying all the Zepto functions\n // to the array. This method can be overridden in plugins.\n zepto.Z = function(dom, selector) {\n return new Z(dom, selector)\n }\n\n // `$.zepto.isZ` should return `true` if the given object is a Zepto\n // collection. This method can be overridden in plugins.\n zepto.isZ = function(object) {\n return object instanceof zepto.Z\n }\n\n // `$.zepto.init` is Zepto's counterpart to jQuery's `$.fn.init` and\n // takes a CSS selector and an optional context (and handles various\n // special cases).\n // This method can be overridden in plugins.\n zepto.init = function(selector, context) {\n var dom\n // If nothing given, return an empty Zepto collection\n if (!selector) return zepto.Z()\n // Optimize for string selectors\n else if (typeof selector == 'string') {\n selector = selector.trim()\n // If it's a html fragment, create nodes from it\n // Note: In both Chrome 21 and Firefox 15, DOM error 12\n // is thrown if the fragment doesn't begin with <\n if (selector[0] == '<' && fragmentRE.test(selector))\n dom = zepto.fragment(selector, RegExp.$1, context), selector = null\n // If there's a context, create a collection on that context first, and select\n // nodes from there\n else if (context !== undefined) return $(context).find(selector)\n // If it's a CSS selector, use it to select nodes.\n else dom = zepto.qsa(document, selector)\n }\n // If a function is given, call it when the DOM is ready\n else if (isFunction(selector)) return $(document).ready(selector)\n // If a Zepto collection is given, just return it\n else if (zepto.isZ(selector)) return selector\n else {\n // normalize array if an array of nodes is given\n if (isArray(selector)) dom = compact(selector)\n // Wrap DOM nodes.\n else if (isObject(selector))\n dom = [selector], selector = null\n // If it's a html fragment, create nodes from it\n else if (fragmentRE.test(selector))\n dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null\n // If there's a context, create a collection on that context first, and select\n // nodes from there\n else if (context !== undefined) return $(context).find(selector)\n // And last but no least, if it's a CSS selector, use it to select nodes.\n else dom = zepto.qsa(document, selector)\n }\n // create a new Zepto collection from the nodes found\n return zepto.Z(dom, selector)\n }\n\n // `$` will be the base `Zepto` object. When calling this\n // function just call `$.zepto.init, which makes the implementation\n // details of selecting nodes and creating Zepto collections\n // patchable in plugins.\n $ = function(selector, context){\n return zepto.init(selector, context)\n }\n\n function extend(target, source, deep) {\n for (key in source)\n if (deep && (isPlainObject(source[key]) || isArray(source[key]))) {\n if (isPlainObject(source[key]) && !isPlainObject(target[key]))\n target[key] = {}\n if (isArray(source[key]) && !isArray(target[key]))\n target[key] = []\n extend(target[key], source[key], deep)\n }\n else if (source[key] !== undefined) target[key] = source[key]\n }\n\n // Copy all but undefined properties from one or more\n // objects to the `target` object.\n $.extend = function(target){\n var deep, args = slice.call(arguments, 1)\n if (typeof target == 'boolean') {\n deep = target\n target = args.shift()\n }\n args.forEach(function(arg){ extend(target, arg, deep) })\n return target\n }\n\n // `$.zepto.qsa` is Zepto's CSS selector implementation which\n // uses `document.querySelectorAll` and optimizes for some special cases, like `#id`.\n // This method can be overridden in plugins.\n zepto.qsa = function(element, selector){\n var found,\n maybeID = selector[0] == '#',\n maybeClass = !maybeID && selector[0] == '.',\n nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, // Ensure that a 1 char tag name still gets checked\n isSimple = simpleSelectorRE.test(nameOnly)\n return (element.getElementById && isSimple && maybeID) ? // Safari DocumentFragment doesn't have getElementById\n ( (found = element.getElementById(nameOnly)) ? [found] : [] ) :\n (element.nodeType !== 1 && element.nodeType !== 9 && element.nodeType !== 11) ? [] :\n slice.call(\n isSimple && !maybeID && element.getElementsByClassName ? // DocumentFragment doesn't have getElementsByClassName/TagName\n maybeClass ? element.getElementsByClassName(nameOnly) : // If it's simple, it could be a class\n element.getElementsByTagName(selector) : // Or a tag\n element.querySelectorAll(selector) // Or it's not simple, and we need to query all\n )\n }\n\n function filtered(nodes, selector) {\n return selector == null ? $(nodes) : $(nodes).filter(selector)\n }\n\n $.contains = document.documentElement.contains ?\n function(parent, node) {\n return parent !== node && parent.contains(node)\n } :\n function(parent, node) {\n while (node && (node = node.parentNode))\n if (node === parent) return true\n return false\n }\n\n function funcArg(context, arg, idx, payload) {\n return isFunction(arg) ? arg.call(context, idx, payload) : arg\n }\n\n function setAttribute(node, name, value) {\n value == null ? node.removeAttribute(name) : node.setAttribute(name, value)\n }\n\n // access className property while respecting SVGAnimatedString\n function className(node, value){\n var klass = node.className || '',\n svg = klass && klass.baseVal !== undefined\n\n if (value === undefined) return svg ? klass.baseVal : klass\n svg ? (klass.baseVal = value) : (node.className = value)\n }\n\n // \"true\" => true\n // \"false\" => false\n // \"null\" => null\n // \"42\" => 42\n // \"42.5\" => 42.5\n // \"08\" => \"08\"\n // JSON => parse if valid\n // String => self\n function deserializeValue(value) {\n try {\n return value ?\n value == \"true\" ||\n ( value == \"false\" ? false :\n value == \"null\" ? null :\n +value + \"\" == value ? +value :\n /^[\\[\\{]/.test(value) ? $.parseJSON(value) :\n value )\n : value\n } catch(e) {\n return value\n }\n }\n\n $.type = type\n $.isFunction = isFunction\n $.isWindow = isWindow\n $.isArray = isArray\n $.isPlainObject = isPlainObject\n\n $.isEmptyObject = function(obj) {\n var name\n for (name in obj) return false\n return true\n }\n\n $.isNumeric = function(val) {\n var num = Number(val), type = typeof val\n return val != null && type != 'boolean' &&\n (type != 'string' || val.length) &&\n !isNaN(num) && isFinite(num) || false\n }\n\n $.inArray = function(elem, array, i){\n return emptyArray.indexOf.call(array, elem, i)\n }\n\n $.camelCase = camelize\n $.trim = function(str) {\n return str == null ? \"\" : String.prototype.trim.call(str)\n }\n\n // plugin compatibility\n $.uuid = 0\n $.support = { }\n $.expr = { }\n $.noop = function() {}\n\n $.map = function(elements, callback){\n var value, values = [], i, key\n if (likeArray(elements))\n for (i = 0; i < elements.length; i++) {\n value = callback(elements[i], i)\n if (value != null) values.push(value)\n }\n else\n for (key in elements) {\n value = callback(elements[key], key)\n if (value != null) values.push(value)\n }\n return flatten(values)\n }\n\n $.each = function(elements, callback){\n var i, key\n if (likeArray(elements)) {\n for (i = 0; i < elements.length; i++)\n if (callback.call(elements[i], i, elements[i]) === false) return elements\n } else {\n for (key in elements)\n if (callback.call(elements[key], key, elements[key]) === false) return elements\n }\n\n return elements\n }\n\n $.grep = function(elements, callback){\n return filter.call(elements, callback)\n }\n\n if (window.JSON) $.parseJSON = JSON.parse\n\n // Populate the class2type map\n $.each(\"Boolean Number String Function Array Date RegExp Object Error\".split(\" \"), function(i, name) {\n class2type[ \"[object \" + name + \"]\" ] = name.toLowerCase()\n })\n\n // Define methods that will be available on all\n // Zepto collections\n $.fn = {\n constructor: zepto.Z,\n length: 0,\n\n // Because a collection acts like an array\n // copy over these useful array functions.\n forEach: emptyArray.forEach,\n reduce: emptyArray.reduce,\n push: emptyArray.push,\n sort: emptyArray.sort,\n splice: emptyArray.splice,\n indexOf: emptyArray.indexOf,\n concat: function(){\n var i, value, args = []\n for (i = 0; i < arguments.length; i++) {\n value = arguments[i]\n args[i] = zepto.isZ(value) ? value.toArray() : value\n }\n return concat.apply(zepto.isZ(this) ? this.toArray() : this, args)\n },\n\n // `map` and `slice` in the jQuery API work differently\n // from their array counterparts\n map: function(fn){\n return $($.map(this, function(el, i){ return fn.call(el, i, el) }))\n },\n slice: function(){\n return $(slice.apply(this, arguments))\n },\n\n ready: function(callback){\n // need to check if document.body exists for IE as that browser reports\n // document ready when it hasn't yet created the body element\n if (readyRE.test(document.readyState) && document.body) callback($)\n else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false)\n return this\n },\n get: function(idx){\n return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length]\n },\n toArray: function(){ return this.get() },\n size: function(){\n return this.length\n },\n remove: function(){\n return this.each(function(){\n if (this.parentNode != null)\n this.parentNode.removeChild(this)\n })\n },\n each: function(callback){\n emptyArray.every.call(this, function(el, idx){\n return callback.call(el, idx, el) !== false\n })\n return this\n },\n filter: function(selector){\n if (isFunction(selector)) return this.not(this.not(selector))\n return $(filter.call(this, function(element){\n return zepto.matches(element, selector)\n }))\n },\n add: function(selector,context){\n return $(uniq(this.concat($(selector,context))))\n },\n is: function(selector){\n return this.length > 0 && zepto.matches(this[0], selector)\n },\n not: function(selector){\n var nodes=[]\n if (isFunction(selector) && selector.call !== undefined)\n this.each(function(idx){\n if (!selector.call(this,idx)) nodes.push(this)\n })\n else {\n var excludes = typeof selector == 'string' ? this.filter(selector) :\n (likeArray(selector) && isFunction(selector.item)) ? slice.call(selector) : $(selector)\n this.forEach(function(el){\n if (excludes.indexOf(el) < 0) nodes.push(el)\n })\n }\n return $(nodes)\n },\n has: function(selector){\n return this.filter(function(){\n return isObject(selector) ?\n $.contains(this, selector) :\n $(this).find(selector).size()\n })\n },\n eq: function(idx){\n return idx === -1 ? this.slice(idx) : this.slice(idx, + idx + 1)\n },\n first: function(){\n var el = this[0]\n return el && !isObject(el) ? el : $(el)\n },\n last: function(){\n var el = this[this.length - 1]\n return el && !isObject(el) ? el : $(el)\n },\n find: function(selector){\n var result, $this = this\n if (!selector) result = $()\n else if (typeof selector == 'object')\n result = $(selector).filter(function(){\n var node = this\n return emptyArray.some.call($this, function(parent){\n return $.contains(parent, node)\n })\n })\n else if (this.length == 1) result = $(zepto.qsa(this[0], selector))\n else result = this.map(function(){ return zepto.qsa(this, selector) })\n return result\n },\n closest: function(selector, context){\n var nodes = [], collection = typeof selector == 'object' && $(selector)\n this.each(function(_, node){\n while (node && !(collection ? collection.indexOf(node) >= 0 : zepto.matches(node, selector)))\n node = node !== context && !isDocument(node) && node.parentNode\n if (node && nodes.indexOf(node) < 0) nodes.push(node)\n })\n return $(nodes)\n },\n parents: function(selector){\n var ancestors = [], nodes = this\n while (nodes.length > 0)\n nodes = $.map(nodes, function(node){\n if ((node = node.parentNode) && !isDocument(node) && ancestors.indexOf(node) < 0) {\n ancestors.push(node)\n return node\n }\n })\n return filtered(ancestors, selector)\n },\n parent: function(selector){\n return filtered(uniq(this.pluck('parentNode')), selector)\n },\n children: function(selector){\n return filtered(this.map(function(){ return children(this) }), selector)\n },\n contents: function() {\n return this.map(function() { return this.contentDocument || slice.call(this.childNodes) })\n },\n siblings: function(selector){\n return filtered(this.map(function(i, el){\n return filter.call(children(el.parentNode), function(child){ return child!==el })\n }), selector)\n },\n empty: function(){\n return this.each(function(){ this.innerHTML = '' })\n },\n // `pluck` is borrowed from Prototype.js\n pluck: function(property){\n return $.map(this, function(el){ return el[property] })\n },\n show: function(){\n return this.each(function(){\n this.style.display == \"none\" && (this.style.display = '')\n if (getComputedStyle(this, '').getPropertyValue(\"display\") == \"none\")\n this.style.display = defaultDisplay(this.nodeName)\n })\n },\n replaceWith: function(newContent){\n return this.before(newContent).remove()\n },\n wrap: function(structure){\n var func = isFunction(structure)\n if (this[0] && !func)\n var dom = $(structure).get(0),\n clone = dom.parentNode || this.length > 1\n\n return this.each(function(index){\n $(this).wrapAll(\n func ? structure.call(this, index) :\n clone ? dom.cloneNode(true) : dom\n )\n })\n },\n wrapAll: function(structure){\n if (this[0]) {\n $(this[0]).before(structure = $(structure))\n var children\n // drill down to the inmost element\n while ((children = structure.children()).length) structure = children.first()\n $(structure).append(this)\n }\n return this\n },\n wrapInner: function(structure){\n var func = isFunction(structure)\n return this.each(function(index){\n var self = $(this), contents = self.contents(),\n dom = func ? structure.call(this, index) : structure\n contents.length ? contents.wrapAll(dom) : self.append(dom)\n })\n },\n unwrap: function(){\n this.parent().each(function(){\n $(this).replaceWith($(this).children())\n })\n return this\n },\n clone: function(){\n return this.map(function(){ return this.cloneNode(true) })\n },\n hide: function(){\n return this.css(\"display\", \"none\")\n },\n toggle: function(setting){\n return this.each(function(){\n var el = $(this)\n ;(setting === undefined ? el.css(\"display\") == \"none\" : setting) ? el.show() : el.hide()\n })\n },\n prev: function(selector){ return $(this.pluck('previousElementSibling')).filter(selector || '*') },\n next: function(selector){ return $(this.pluck('nextElementSibling')).filter(selector || '*') },\n html: function(html){\n return 0 in arguments ?\n this.each(function(idx){\n var originHtml = this.innerHTML\n $(this).empty().append( funcArg(this, html, idx, originHtml) )\n }) :\n (0 in this ? this[0].innerHTML : null)\n },\n text: function(text){\n return 0 in arguments ?\n this.each(function(idx){\n var newText = funcArg(this, text, idx, this.textContent)\n this.textContent = newText == null ? '' : ''+newText\n }) :\n (0 in this ? this.pluck('textContent').join(\"\") : null)\n },\n attr: function(name, value){\n var result\n return (typeof name == 'string' && !(1 in arguments)) ?\n (0 in this && this[0].nodeType == 1 && (result = this[0].getAttribute(name)) != null ? result : undefined) :\n this.each(function(idx){\n if (this.nodeType !== 1) return\n if (isObject(name)) for (key in name) setAttribute(this, key, name[key])\n else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name)))\n })\n },\n removeAttr: function(name){\n return this.each(function(){ this.nodeType === 1 && name.split(' ').forEach(function(attribute){\n setAttribute(this, attribute)\n }, this)})\n },\n prop: function(name, value){\n name = propMap[name] || name\n return (1 in arguments) ?\n this.each(function(idx){\n this[name] = funcArg(this, value, idx, this[name])\n }) :\n (this[0] && this[0][name])\n },\n removeProp: function(name){\n name = propMap[name] || name\n return this.each(function(){ delete this[name] })\n },\n data: function(name, value){\n var attrName = 'data-' + name.replace(capitalRE, '-$1').toLowerCase()\n\n var data = (1 in arguments) ?\n this.attr(attrName, value) :\n this.attr(attrName)\n\n return data !== null ? deserializeValue(data) : undefined\n },\n val: function(value){\n if (0 in arguments) {\n if (value == null) value = \"\"\n return this.each(function(idx){\n this.value = funcArg(this, value, idx, this.value)\n })\n } else {\n return this[0] && (this[0].multiple ?\n $(this[0]).find('option').filter(function(){ return this.selected }).pluck('value') :\n this[0].value)\n }\n },\n offset: function(coordinates){\n if (coordinates) return this.each(function(index){\n var $this = $(this),\n coords = funcArg(this, coordinates, index, $this.offset()),\n parentOffset = $this.offsetParent().offset(),\n props = {\n top: coords.top - parentOffset.top,\n left: coords.left - parentOffset.left\n }\n\n if ($this.css('position') == 'static') props['position'] = 'relative'\n $this.css(props)\n })\n if (!this.length) return null\n if (document.documentElement !== this[0] && !$.contains(document.documentElement, this[0]))\n return {top: 0, left: 0}\n var obj = this[0].getBoundingClientRect()\n return {\n left: obj.left + window.pageXOffset,\n top: obj.top + window.pageYOffset,\n width: Math.round(obj.width),\n height: Math.round(obj.height)\n }\n },\n css: function(property, value){\n if (arguments.length < 2) {\n var element = this[0]\n if (typeof property == 'string') {\n if (!element) return\n return element.style[camelize(property)] || getComputedStyle(element, '').getPropertyValue(property)\n } else if (isArray(property)) {\n if (!element) return\n var props = {}\n var computedStyle = getComputedStyle(element, '')\n $.each(property, function(_, prop){\n props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop))\n })\n return props\n }\n }\n\n var css = ''\n if (type(property) == 'string') {\n if (!value && value !== 0)\n this.each(function(){ this.style.removeProperty(dasherize(property)) })\n else\n css = dasherize(property) + \":\" + maybeAddPx(property, value)\n } else {\n for (key in property)\n if (!property[key] && property[key] !== 0)\n this.each(function(){ this.style.removeProperty(dasherize(key)) })\n else\n css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';'\n }\n\n return this.each(function(){ this.style.cssText += ';' + css })\n },\n index: function(element){\n return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0])\n },\n hasClass: function(name){\n if (!name) return false\n return emptyArray.some.call(this, function(el){\n return this.test(className(el))\n }, classRE(name))\n },\n addClass: function(name){\n if (!name) return this\n return this.each(function(idx){\n if (!('className' in this)) return\n classList = []\n var cls = className(this), newName = funcArg(this, name, idx, cls)\n newName.split(/\\s+/g).forEach(function(klass){\n if (!$(this).hasClass(klass)) classList.push(klass)\n }, this)\n classList.length && className(this, cls + (cls ? \" \" : \"\") + classList.join(\" \"))\n })\n },\n removeClass: function(name){\n return this.each(function(idx){\n if (!('className' in this)) return\n if (name === undefined) return className(this, '')\n classList = className(this)\n funcArg(this, name, idx, classList).split(/\\s+/g).forEach(function(klass){\n classList = classList.replace(classRE(klass), \" \")\n })\n className(this, classList.trim())\n })\n },\n toggleClass: function(name, when){\n if (!name) return this\n return this.each(function(idx){\n var $this = $(this), names = funcArg(this, name, idx, className(this))\n names.split(/\\s+/g).forEach(function(klass){\n (when === undefined ? !$this.hasClass(klass) : when) ?\n $this.addClass(klass) : $this.removeClass(klass)\n })\n })\n },\n scrollTop: function(value){\n if (!this.length) return\n var hasScrollTop = 'scrollTop' in this[0]\n if (value === undefined) return hasScrollTop ? this[0].scrollTop : this[0].pageYOffset\n return this.each(hasScrollTop ?\n function(){ this.scrollTop = value } :\n function(){ this.scrollTo(this.scrollX, value) })\n },\n scrollLeft: function(value){\n if (!this.length) return\n var hasScrollLeft = 'scrollLeft' in this[0]\n if (value === undefined) return hasScrollLeft ? this[0].scrollLeft : this[0].pageXOffset\n return this.each(hasScrollLeft ?\n function(){ this.scrollLeft = value } :\n function(){ this.scrollTo(value, this.scrollY) })\n },\n position: function() {\n if (!this.length) return\n\n var elem = this[0],\n // Get *real* offsetParent\n offsetParent = this.offsetParent(),\n // Get correct offsets\n offset = this.offset(),\n parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset()\n\n // Subtract element margins\n // note: when an element has margin: auto the offsetLeft and marginLeft\n // are the same in Safari causing offset.left to incorrectly be 0\n offset.top -= parseFloat( $(elem).css('margin-top') ) || 0\n offset.left -= parseFloat( $(elem).css('margin-left') ) || 0\n\n // Add offsetParent borders\n parentOffset.top += parseFloat( $(offsetParent[0]).css('border-top-width') ) || 0\n parentOffset.left += parseFloat( $(offsetParent[0]).css('border-left-width') ) || 0\n\n // Subtract the two offsets\n return {\n top: offset.top - parentOffset.top,\n left: offset.left - parentOffset.left\n }\n },\n offsetParent: function() {\n return this.map(function(){\n var parent = this.offsetParent || document.body\n while (parent && !rootNodeRE.test(parent.nodeName) && $(parent).css(\"position\") == \"static\")\n parent = parent.offsetParent\n return parent\n })\n }\n }\n\n // for now\n $.fn.detach = $.fn.remove\n\n // Generate the `width` and `height` functions\n ;['width', 'height'].forEach(function(dimension){\n var dimensionProperty =\n dimension.replace(/./, function(m){ return m[0].toUpperCase() })\n\n $.fn[dimension] = function(value){\n var offset, el = this[0]\n if (value === undefined) return isWindow(el) ? el['inner' + dimensionProperty] :\n isDocument(el) ? el.documentElement['scroll' + dimensionProperty] :\n (offset = this.offset()) && offset[dimension]\n else return this.each(function(idx){\n el = $(this)\n el.css(dimension, funcArg(this, value, idx, el[dimension]()))\n })\n }\n })\n\n function traverseNode(node, fun) {\n fun(node)\n for (var i = 0, len = node.childNodes.length; i < len; i++)\n traverseNode(node.childNodes[i], fun)\n }\n\n // Generate the `after`, `prepend`, `before`, `append`,\n // `insertAfter`, `insertBefore`, `appendTo`, and `prependTo` methods.\n adjacencyOperators.forEach(function(operator, operatorIndex) {\n var inside = operatorIndex % 2 //=> prepend, append\n\n $.fn[operator] = function(){\n // arguments can be nodes, arrays of nodes, Zepto objects and HTML strings\n var argType, nodes = $.map(arguments, function(arg) {\n var arr = []\n argType = type(arg)\n if (argType == \"array\") {\n arg.forEach(function(el) {\n if (el.nodeType !== undefined) return arr.push(el)\n else if ($.zepto.isZ(el)) return arr = arr.concat(el.get())\n arr = arr.concat(zepto.fragment(el))\n })\n return arr\n }\n return argType == \"object\" || arg == null ?\n arg : zepto.fragment(arg)\n }),\n parent, copyByClone = this.length > 1\n if (nodes.length < 1) return this\n\n return this.each(function(_, target){\n parent = inside ? target : target.parentNode\n\n // convert all methods to a \"before\" operation\n target = operatorIndex == 0 ? target.nextSibling :\n operatorIndex == 1 ? target.firstChild :\n operatorIndex == 2 ? target :\n null\n\n var parentInDocument = $.contains(document.documentElement, parent)\n\n nodes.forEach(function(node){\n if (copyByClone) node = node.cloneNode(true)\n else if (!parent) return $(node).remove()\n\n parent.insertBefore(node, target)\n if (parentInDocument) traverseNode(node, function(el){\n if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' &&\n (!el.type || el.type === 'text/javascript') && !el.src){\n var target = el.ownerDocument ? el.ownerDocument.defaultView : window\n target['eval'].call(target, el.innerHTML)\n }\n })\n })\n })\n }\n\n // after => insertAfter\n // prepend => prependTo\n // before => insertBefore\n // append => appendTo\n $.fn[inside ? operator+'To' : 'insert'+(operatorIndex ? 'Before' : 'After')] = function(html){\n $(html)[operator](this)\n return this\n }\n })\n\n zepto.Z.prototype = Z.prototype = $.fn\n\n // Export internal API functions in the `$.zepto` namespace\n zepto.uniq = uniq\n zepto.deserializeValue = deserializeValue\n $.zepto = zepto\n\n return $\n})()\n\nwindow.Zepto = Zepto\nwindow.$ === undefined && (window.$ = Zepto)\n\n;(function($){\n var _zid = 1, undefined,\n slice = Array.prototype.slice,\n isFunction = $.isFunction,\n isString = function(obj){ return typeof obj == 'string' },\n handlers = {},\n specialEvents={},\n focusinSupported = 'onfocusin' in window,\n focus = { focus: 'focusin', blur: 'focusout' },\n hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' }\n\n specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents'\n\n function zid(element) {\n return element._zid || (element._zid = _zid++)\n }\n function findHandlers(element, event, fn, selector) {\n event = parse(event)\n if (event.ns) var matcher = matcherFor(event.ns)\n return (handlers[zid(element)] || []).filter(function(handler) {\n return handler\n && (!event.e || handler.e == event.e)\n && (!event.ns || matcher.test(handler.ns))\n && (!fn || zid(handler.fn) === zid(fn))\n && (!selector || handler.sel == selector)\n })\n }\n function parse(event) {\n var parts = ('' + event).split('.')\n return {e: parts[0], ns: parts.slice(1).sort().join(' ')}\n }\n function matcherFor(ns) {\n return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)')\n }\n\n function eventCapture(handler, captureSetting) {\n return handler.del &&\n (!focusinSupported && (handler.e in focus)) ||\n !!captureSetting\n }\n\n function realEvent(type) {\n return hover[type] || (focusinSupported && focus[type]) || type\n }\n\n function add(element, events, fn, data, selector, delegator, capture){\n var id = zid(element), set = (handlers[id] || (handlers[id] = []))\n events.split(/\\s/).forEach(function(event){\n if (event == 'ready') return $(document).ready(fn)\n var handler = parse(event)\n handler.fn = fn\n handler.sel = selector\n // emulate mouseenter, mouseleave\n if (handler.e in hover) fn = function(e){\n var related = e.relatedTarget\n if (!related || (related !== this && !$.contains(this, related)))\n return handler.fn.apply(this, arguments)\n }\n handler.del = delegator\n var callback = delegator || fn\n handler.proxy = function(e){\n e = compatible(e)\n if (e.isImmediatePropagationStopped()) return\n e.data = data\n var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args))\n if (result === false) e.preventDefault(), e.stopPropagation()\n return result\n }\n handler.i = set.length\n set.push(handler)\n if ('addEventListener' in element)\n element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture))\n })\n }\n function remove(element, events, fn, selector, capture){\n var id = zid(element)\n ;(events || '').split(/\\s/).forEach(function(event){\n findHandlers(element, event, fn, selector).forEach(function(handler){\n delete handlers[id][handler.i]\n if ('removeEventListener' in element)\n element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture))\n })\n })\n }\n\n $.event = { add: add, remove: remove }\n\n $.proxy = function(fn, context) {\n var args = (2 in arguments) && slice.call(arguments, 2)\n if (isFunction(fn)) {\n var proxyFn = function(){ return fn.apply(context, args ? args.concat(slice.call(arguments)) : arguments) }\n proxyFn._zid = zid(fn)\n return proxyFn\n } else if (isString(context)) {\n if (args) {\n args.unshift(fn[context], fn)\n return $.proxy.apply(null, args)\n } else {\n return $.proxy(fn[context], fn)\n }\n } else {\n throw new TypeError(\"expected function\")\n }\n }\n\n $.fn.bind = function(event, data, callback){\n return this.on(event, data, callback)\n }\n $.fn.unbind = function(event, callback){\n return this.off(event, callback)\n }\n $.fn.one = function(event, selector, data, callback){\n return this.on(event, selector, data, callback, 1)\n }\n\n var returnTrue = function(){return true},\n returnFalse = function(){return false},\n ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$|webkitMovement[XY]$)/,\n eventMethods = {\n preventDefault: 'isDefaultPrevented',\n stopImmediatePropagation: 'isImmediatePropagationStopped',\n stopPropagation: 'isPropagationStopped'\n }\n\n function compatible(event, source) {\n if (source || !event.isDefaultPrevented) {\n source || (source = event)\n\n $.each(eventMethods, function(name, predicate) {\n var sourceMethod = source[name]\n event[name] = function(){\n this[predicate] = returnTrue\n return sourceMethod && sourceMethod.apply(source, arguments)\n }\n event[predicate] = returnFalse\n })\n\n event.timeStamp || (event.timeStamp = Date.now())\n\n if (source.defaultPrevented !== undefined ? source.defaultPrevented :\n 'returnValue' in source ? source.returnValue === false :\n source.getPreventDefault && source.getPreventDefault())\n event.isDefaultPrevented = returnTrue\n }\n return event\n }\n\n function createProxy(event) {\n var key, proxy = { originalEvent: event }\n for (key in event)\n if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key]\n\n return compatible(proxy, event)\n }\n\n $.fn.delegate = function(selector, event, callback){\n return this.on(event, selector, callback)\n }\n $.fn.undelegate = function(selector, event, callback){\n return this.off(event, selector, callback)\n }\n\n $.fn.live = function(event, callback){\n $(document.body).delegate(this.selector, event, callback)\n return this\n }\n $.fn.die = function(event, callback){\n $(document.body).undelegate(this.selector, event, callback)\n return this\n }\n\n $.fn.on = function(event, selector, data, callback, one){\n var autoRemove, delegator, $this = this\n if (event && !isString(event)) {\n $.each(event, function(type, fn){\n $this.on(type, selector, data, fn, one)\n })\n return $this\n }\n\n if (!isString(selector) && !isFunction(callback) && callback !== false)\n callback = data, data = selector, selector = undefined\n if (callback === undefined || data === false)\n callback = data, data = undefined\n\n if (callback === false) callback = returnFalse\n\n return $this.each(function(_, element){\n if (one) autoRemove = function(e){\n remove(element, e.type, callback)\n return callback.apply(this, arguments)\n }\n\n if (selector) delegator = function(e){\n var evt, match = $(e.target).closest(selector, element).get(0)\n if (match && match !== element) {\n evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element})\n return (autoRemove || callback).apply(match, [evt].concat(slice.call(arguments, 1)))\n }\n }\n\n add(element, event, callback, data, selector, delegator || autoRemove)\n })\n }\n $.fn.off = function(event, selector, callback){\n var $this = this\n if (event && !isString(event)) {\n $.each(event, function(type, fn){\n $this.off(type, selector, fn)\n })\n return $this\n }\n\n if (!isString(selector) && !isFunction(callback) && callback !== false)\n callback = selector, selector = undefined\n\n if (callback === false) callback = returnFalse\n\n return $this.each(function(){\n remove(this, event, callback, selector)\n })\n }\n\n $.fn.trigger = function(event, args){\n event = (isString(event) || $.isPlainObject(event)) ? $.Event(event) : compatible(event)\n event._args = args\n return this.each(function(){\n // handle focus(), blur() by calling them directly\n if (event.type in focus && typeof this[event.type] == \"function\") this[event.type]()\n // items in the collection might not be DOM elements\n else if ('dispatchEvent' in this) this.dispatchEvent(event)\n else $(this).triggerHandler(event, args)\n })\n }\n\n // triggers event handlers on current element just as if an event occurred,\n // doesn't trigger an actual event, doesn't bubble\n $.fn.triggerHandler = function(event, args){\n var e, result\n this.each(function(i, element){\n e = createProxy(isString(event) ? $.Event(event) : event)\n e._args = args\n e.target = element\n $.each(findHandlers(element, event.type || event), function(i, handler){\n result = handler.proxy(e)\n if (e.isImmediatePropagationStopped()) return false\n })\n })\n return result\n }\n\n // shortcut methods for `.bind(event, fn)` for each event type\n ;('focusin focusout focus blur load resize scroll unload click dblclick '+\n 'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave '+\n 'change select keydown keypress keyup error').split(' ').forEach(function(event) {\n $.fn[event] = function(callback) {\n return (0 in arguments) ?\n this.bind(event, callback) :\n this.trigger(event)\n }\n })\n\n $.Event = function(type, props) {\n if (!isString(type)) props = type, type = props.type\n var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true\n if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name])\n event.initEvent(type, bubbles, true)\n return compatible(event)\n }\n\n})(Zepto)\n\n;(function($){\n var jsonpID = +new Date(),\n document = window.document,\n key,\n name,\n rscript = /