commit 36bb82b3bc5305d4918501802c458f83fcaad5e3 Author: agapple Date: Fri Jun 7 20:24:33 2013 +0800 init diff --git a/download.html b/download.html new file mode 100644 index 00000000..7edebd2f --- /dev/null +++ b/download.html @@ -0,0 +1,6 @@ +Canal Versions +

Canal Versions

+ + +
canal.deployer-1.0.2.tar.gz 8470464 bytes Mar 13, 2013 6:49:34 PM
+ diff --git a/images/arrow-down.png b/images/arrow-down.png new file mode 100644 index 00000000..585b0bdd Binary files /dev/null and b/images/arrow-down.png differ diff --git a/images/bg.jpg b/images/bg.jpg new file mode 100644 index 00000000..2242efc5 Binary files /dev/null and b/images/bg.jpg differ diff --git a/images/bg2.png b/images/bg2.png new file mode 100644 index 00000000..5e12d9ef Binary files /dev/null and b/images/bg2.png differ diff --git a/images/bg_new.png b/images/bg_new.png new file mode 100644 index 00000000..33e6f6b4 Binary files /dev/null and b/images/bg_new.png differ diff --git a/images/bodybg.png b/images/bodybg.png new file mode 100644 index 00000000..fe3da998 Binary files /dev/null and b/images/bodybg.png differ diff --git a/images/bubble-arrow.png b/images/bubble-arrow.png new file mode 100644 index 00000000..7795d7de Binary files /dev/null and b/images/bubble-arrow.png differ diff --git a/images/code.png b/images/code.png new file mode 100644 index 00000000..eb91cbf2 Binary files /dev/null and b/images/code.png differ diff --git a/images/icons.png b/images/icons.png new file mode 100644 index 00000000..924d73ea Binary files /dev/null and b/images/icons.png differ diff --git a/images/johnny_automatic_skew_gear.svg b/images/johnny_automatic_skew_gear.svg new file mode 100644 index 00000000..6b1f6326 --- /dev/null +++ b/images/johnny_automatic_skew_gear.svg @@ -0,0 +1,1273 @@ + + + + + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/lineseparator.png b/images/lineseparator.png new file mode 100644 index 00000000..3c82685a Binary files /dev/null and b/images/lineseparator.png differ diff --git a/images/octocat-small.png b/images/octocat-small.png new file mode 100644 index 00000000..66c25398 Binary files /dev/null and b/images/octocat-small.png differ diff --git a/images/pattern.png b/images/pattern.png new file mode 100644 index 00000000..5cb76aaf Binary files /dev/null and b/images/pattern.png differ diff --git a/images/tar.png b/images/tar.png new file mode 100644 index 00000000..1cb1bcf5 Binary files /dev/null and b/images/tar.png differ diff --git a/images/top.png b/images/top.png new file mode 100644 index 00000000..6ab34e5f Binary files /dev/null and b/images/top.png differ diff --git a/images/zip.png b/images/zip.png new file mode 100644 index 00000000..08637bb1 Binary files /dev/null and b/images/zip.png differ diff --git a/index.html b/index.html new file mode 100644 index 00000000..d93be264 --- /dev/null +++ b/index.html @@ -0,0 +1,446 @@ + + + + + + Canal by alibaba + + + + + + + + +
+
+

Canal

+

阿里巴巴mysql数据库binlog的增量订阅&消费组件

+ +
    +
  • Download ZIP
  • +
  • Download TAR
  • +
  • View On GitHub
  • +
+ +

This project is maintained by alibaba

+ + +
+
+
+
+

+

背景

+

早期,阿里巴巴B2B公司因为存在杭州和美国双机房部署,存在跨机房同步的业务需求。不过早期的数据库同步业务,主要是基于trigger的方式获取增量变更,不过从2010年开始,阿里系公司开始逐步的尝试基于数据库的日志解析,获取增量变更进行同步,由此衍生出了增量订阅&消费的业务,从此开启了一段新纪元。ps. 目前内部使用的同步,已经支持mysql5.x和oracle部分版本的日志解析

+

+

基于日志增量订阅&消费支持的业务:

+
    +
  1. 数据库镜像
  2. +
  3. 数据库实时备份
  4. +
  5. 多级索引 (卖家和买家各自分库索引)
  6. +
  7. search build
  8. +
  9. 业务cache刷新
  10. +
  11. 价格变化等重要业务消息
  12. +
+

项目介绍

+

名称:canal [kə'næl]

+

译意: 水道/管道/沟渠

+

语言: 纯java开发

+

定位: 基于数据库增量日志解析,提供增量数据订阅&消费,目前主要支持了mysql

+

+

工作原理

+

mysql主备复制实现

+


从上层来看,复制分成三步:

+
    +
  1. master将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log events,可以通过show binlog events进行查看);
  2. +
  3. slave将master的binary log events拷贝到它的中继日志(relay log);
  4. +
  5. slave重做中继日志中的事件,将改变反映它自己的数据。
  6. +
+

canal的工作原理:

+

+

原理相对比较简单:

+
    +
  1. canal模拟mysql slave的交互协议,伪装自己为mysql slave,向mysql master发送dump协议
  2. +
  3. mysql master收到dump请求,开始推送binary log给slave(也就是canal)
  4. +
  5. canal解析binary log对象(原始为byte流)
  6. +
+

架构

+

+

说明:

+
    +
  • server代表一个canal运行实例,对应于一个jvm
  • +
  • instance对应于一个数据队列 (1个server对应1..n个instance)
  • +
+

instance模块:

+
    +
  • eventParser (数据源接入,模拟slave协议和master进行交互,协议解析)
  • +
  • eventSink (Parser和Store链接器,进行数据过滤,加工,分发的工作)
  • +
  • eventStore (数据存储)
  • +
  • metaManager (增量订阅&消费信息管理器)
  • +
+

数据对象格式:EntryProtocol.proto +

+
Entry
+    Header
+        logfileName [binlog文件名]
+        logfileOffset [binlog position]
+        executeTime [发生的变更]
+        schemaName 
+        tableName
+        eventType [insert/update/delete类型]
+    entryType   [事务头BEGIN/事务尾END/数据ROWDATA]
+    storeValue  [byte数据,可展开,对应的类型为RowChange]
+    
+RowChange
+    isDdl       [是否是ddl变更操作,比如create table/drop table]
+    sql     [具体的ddl sql]
+    rowDatas    [具体insert/update/delete的变更数据,可为多条,1个binlog event事件可对应多条变更,比如批处理]
+        beforeColumns [Column类型的数组]
+        afterColumns [Column类型的数组]
+        
+Column 
+    index       
+    sqlType     [jdbc type]
+    name        [column name]
+    isKey       [是否为主键]
+    updated     [是否发生过变更]
+    isNull      [值是否为null]
+    value       [具体的内容,注意为文本]
+

说明:

+
    +
  • 可以提供数据库变更前和变更后的字段内容,针对binlog中没有的name,isKey等信息进行补全
  • +
  • 可以提供ddl的变更语句
  • +
+

QuickStart

+

几点说明:(mysql初始化)

+

a. canal的原理是基于mysql binlog技术,所以这里一定需要开启mysql的binlog写入功能,并且配置binlog模式为row.

+
[mysqld]
+log-bin=mysql-bin #添加这一行就ok
+binlog-format=ROW #选择row模式
+server_id=1 #配置mysql replaction需要定义,不能和canal的slaveId重复
+b. canal的原理是模拟自己为mysql slave,所以这里一定需要做为mysql slave的相关权限.
+
+
CREATE USER canal IDENTIFIED BY 'canal';  
+GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
+-- GRANT ALL PRIVILEGES ON *.* TO 'canal'@'%' ;
+FLUSH PRIVILEGES;
+

针对已有的账户可通过grants查询权限:

+

启动步骤:

+

1. 下载canal

+

下载部署包

+
wget http://canal4mysql.googlecode.com/files/canal.deployer-1.0.0.tar.gz
+

or

+

自己编译

+
git clone git@github.com:otter-projects/canal.git
+cd canal; 
+mvn clean install -Dmaven.test.skip -Denv=release
+

编译完成后,会在根目录下产生target/canal.deployer-$version.tar.gz

+

+

2. 解压缩

+
mkdir /tmp/canal
+tar zxvf canal.deployer-1.0.0.tar.gz  -C /tmp/canal
+

+

解压完成后,进入/tmp/canal目录,可以看到如下结构:

+

+
drwxr-xr-x 2 jianghang jianghang  136 2013-02-05 21:51 bin
+drwxr-xr-x 4 jianghang jianghang  160 2013-02-05 21:51 conf
+drwxr-xr-x 2 jianghang jianghang 1.3K 2013-02-05 21:51 lib
+drwxr-xr-x 2 jianghang jianghang   48 2013-02-05 21:29 logs
+

+

3. 配置修改

+

+

公用参数:

+
vi conf/canal.properties
+
#################################################
+#########               common argument         ############# 
+#################################################
+canal.id= 1
+canal.address=
+canal.port= 11111
+canal.zkServers=
+# flush data to zk
+canal.zookeeper.flush.period = 1000
+## memory store RingBuffer size, should be Math.pow(2,n)
+canal.instance.memory.buffer.size = 32768
+
+## detecing config
+canal.instance.detecting.enable = false
+canal.instance.detecting.sql = insert into retl.xdual values(1,now()) on duplicate key update x=now()
+canal.instance.detecting.interval.time = 3 
+canal.instance.detecting.retry.threshold = 3 
+canal.instance.detecting.heartbeatHaEnable = false
+
+# support maximum transaction size, more than the size of the transaction will be cut into multiple transactions delivery
+canal.instance.transactionn.size =  1024
+
+# network config
+canal.instance.network.receiveBufferSize = 16384
+canal.instance.network.sendBufferSize = 16384
+canal.instance.network.soTimeout = 30
+
+#################################################
+#########               destinations            ############# 
+#################################################
+canal.destinations= example
+
+canal.instance.global.mode = spring 
+canal.instance.global.lazy = true  ##修改为false,代表立马启动
+#canal.instance.global.manager.address = 127.0.0.1:1099
+canal.instance.global.spring.xml = classpath:spring/memory-instance.xml
+#canal.instance.global.spring.xml = classpath:spring/default-instance.xml
+

+

应用参数:

+
vi conf/example/instance.properties
+
#################################################
+## mysql serverId
+canal.instance.mysql.slaveId = 1234
+
+# position info
+canal.instance.master.address = 127.0.0.1:3306 #改成自己的数据库地址
+canal.instance.master.journal.name = 
+canal.instance.master.position = 
+canal.instance.master.timestamp = 
+
+#canal.instance.standby.address = 
+#canal.instance.standby.journal.name =
+#canal.instance.standby.position = 
+#canal.instance.standby.timestamp = 
+
+# username/password
+canal.instance.dbUsername = retl  #改成自己的数据库信息
+canal.instance.dbPassword = retl  #改成自己的数据库信息
+canal.instance.defaultDatabaseName =   #改成自己的数据库信息
+canal.instance.connectionCharsetNumber = 33  #改成自己的数据库信息
+canal.instance.connectionCharset = UTF-8  #改成自己的数据库信息
+
+# table regex
+canal.instance.filter.regex = .*\\..*
+
+#################################################
+
+

+

+

说明:

+
    +
  • canal.instance.connectionCharset 代表数据库的编码方式对应到java中的编码类型,比如UTF-8,GBK , ISO-8859-1
  • +
  • canal.instance.connectionCharsetNumber 代表数据库的编码方式对应mysql中的唯一id,详细的映射关系可查看:com.mysql.jdbc.CharsetMapping.INDEX_TO_CHARSET
    针对常见的编码:
    utf-8 <=> 33
    gb2312 <=> 24
    gbk <=> 28
  • +
+

4. 准备启动

+

+
sh bin/startup.sh
+

+

5. 查看日志

+
vi logs/canal/canal.log
+
2013-02-05 22:45:27.967 [main] INFO  com.alibaba.otter.canal.deployer.CanalLauncher - ## start the canal server.
+2013-02-05 22:45:28.113 [main] INFO  com.alibaba.otter.canal.deployer.CanalController - ## start the canal server[10.1.29.120:11111]
+2013-02-05 22:45:28.210 [main] INFO  com.alibaba.otter.canal.deployer.CanalLauncher - ## the canal server is running now ......
+

+

具体instance的日志:

+
vi logs/example/example.log
+
2013-02-05 22:50:45.636 [main] INFO  c.a.o.c.i.spring.support.PropertyPlaceholderConfigurer - Loading properties file from class path resource [canal.properties]
+2013-02-05 22:50:45.641 [main] INFO  c.a.o.c.i.spring.support.PropertyPlaceholderConfigurer - Loading properties file from class path resource [example/instance.properties]
+2013-02-05 22:50:45.803 [main] INFO  c.a.otter.canal.instance.spring.CanalInstanceWithSpring - start CannalInstance for 1-example 
+2013-02-05 22:50:45.810 [main] INFO  c.a.otter.canal.instance.spring.CanalInstanceWithSpring - start successful....
+

+

6. 关闭

+
sh bin/stop.sh
+

+

it's over.

+
+ +

ClientExample

+ +

依赖配置:(目前暂未正式发布到mvn仓库,所以需要各位下载canal源码后手工执行下mvn clean install -Dmaven.test.skip)

+ +
<dependency>
+    <groupId>com.alibaba.otter</groupId>
+    <artifactId>canal.client</artifactId>
+    <version>1.0.0</version>
+</dependency>
+ +

+ +

1. 创建mvn标准工程:

+ +
mvn archetype:create -DgroupId=com.alibaba.otter -DartifactId=canal.sample
+ +

+ +

2. 修改pom.xml,添加依赖

+ +

+ +

3. ClientSample代码

+ +
package com.alibaba.otter.canal.sample;
+
+import java.net.InetSocketAddress;
+import java.util.List;
+
+import com.alibaba.otter.canal.common.utils.AddressUtils;
+import com.alibaba.otter.canal.protocol.Message;
+import com.alibaba.otter.canal.protocol.CanalEntry.Column;
+import com.alibaba.otter.canal.protocol.CanalEntry.Entry;
+import com.alibaba.otter.canal.protocol.CanalEntry.EntryType;
+import com.alibaba.otter.canal.protocol.CanalEntry.EventType;
+import com.alibaba.otter.canal.protocol.CanalEntry.RowChange;
+import com.alibaba.otter.canal.protocol.CanalEntry.RowData;
+
+public class SimpleCanalClientExample {
+
+    public static void main(String args[]) {
+        // 创建链接
+        CanalConnector connector = CanalConnectors.newSingleConnector(new InetSocketAddress(AddressUtils.getHostIp(),
+                                                                                            11111), "example", "", "");
+        int batchSize = 1000;
+        int emptyCount = 0;
+        try {
+            connector.connect();
+            connector.subscribe(".*\\..*");
+            connector.rollback();
+            int totalEmtryCount = 120;
+            while (emptyCount < totalEmtryCount) {
+                Message message = connector.getWithoutAck(batchSize); // 获取指定数量的数据
+                long batchId = message.getId();
+                int size = message.getEntries().size();
+                if (batchId == -1 || size == 0) {
+                    emptyCount++;
+                    System.out.println("empty count : " + emptyCount);
+                    try {
+                        Thread.sleep(1000);
+                    } catch (InterruptedException e) {
+                    }
+                } else {
+                    emptyCount = 0;
+                    // System.out.printf("message[batchId=%s,size=%s] \n", batchId, size);
+                    printEntry(message.getEntries());
+                }
+
+                connector.ack(batchId); // 提交确认
+                // connector.rollback(batchId); // 处理失败, 回滚数据
+            }
+
+            System.out.println("empty too many times, exit");
+        } finally {
+            connector.disconnect();
+        }
+    }
+
+    private static void printEntry(List<Entry> entrys) {
+        for (Entry entry : entrys) {
+            if (entry.getEntryType() == EntryType.TRANSACTIONBEGIN || entry.getEntryType() == EntryType.TRANSACTIONEND) {
+                continue;
+            }
+
+            RowChange rowChage = null;
+            try {
+                rowChage = RowChange.parseFrom(entry.getStoreValue());
+            } catch (Exception e) {
+                throw new RuntimeException("ERROR ## parser of eromanga-event has an error , data:" + entry.toString(),
+                                           e);
+            }
+
+            EventType eventType = rowChage.getEventType();
+            System.out.println(String.format("================> binlog[%s:%s] , name[%s,%s] , eventType : %s",
+                                             entry.getHeader().getLogfileName(), entry.getHeader().getLogfileOffset(),
+                                             entry.getHeader().getSchemaName(), entry.getHeader().getTableName(),
+                                             eventType));
+
+            for (RowData rowData : rowChage.getRowDatasList()) {
+                if (eventType == EventType.DELETE) {
+                    printColumn(rowData.getBeforeColumnsList());
+                } else if (eventType == EventType.INSERT) {
+                    printColumn(rowData.getAfterColumnsList());
+                } else {
+                    System.out.println("-------> before");
+                    printColumn(rowData.getBeforeColumnsList());
+                    System.out.println("-------> after");
+                    printColumn(rowData.getAfterColumnsList());
+                }
+            }
+        }
+    }
+
+    private static void printColumn(List<Column> columns) {
+        for (Column column : columns) {
+            System.out.println(column.getName() + " : " + column.getValue() + "    update=" + column.getUpdated());
+        }
+    }
+}
+ +

+ +

4. 运行Client

+ +

首先启动Canal Server,可参加QuickStart : http://agapple.iteye.com/blogs/1796070

+ +

启动Canal Client后,可以从控制台从看到类似消息:

+ +
empty count : 1
+empty count : 2
+empty count : 3
+empty count : 4
+ +

此时代表当前数据库无变更数据

+ +

+ +

5. 触发数据库变更

+ +
mysql> use test;
+Database changed
+mysql> CREATE TABLE `xdual` (
+    ->   `ID` int(11) NOT NULL AUTO_INCREMENT,
+    ->   `X` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    ->   PRIMARY KEY (`ID`)
+    -> ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 ;
+Query OK, 0 rows affected (0.06 sec)
+
+mysql> insert into xdual(id,x) values(null,now());Query OK, 1 row affected (0.06 sec)
+ +

+ +

可以从控制台中看到:

+ +
empty count : 1
+empty count : 2
+empty count : 3
+empty count : 4
+================> binlog[mysql-bin.001946:313661577] , name[test,xdual] , eventType : INSERT
+ID : 4    update=true
+X : 2013-02-05 23:29:46    update=true
+ +

+ +

最后:

+ +

整个代码在附件中可以下载,如有问题可及时联系。

+ +

+
+ +

+canal.sample.tar.gz (2.2 KB) +
+
+
+

Hosted on GitHub Pages using the Dinky theme

+
+
+ + + + + + \ No newline at end of file diff --git a/javascripts/libs/jquery-1.7.1.min.js b/javascripts/libs/jquery-1.7.1.min.js new file mode 100755 index 00000000..198b3ff0 --- /dev/null +++ b/javascripts/libs/jquery-1.7.1.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.7.1 jquery.com | jquery.org/license */ +(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"":"")+""),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;g=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
a",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="
"+""+"
",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="
t
",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="
",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")}; +f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&i.push({elem:this,matches:d.slice(e)});for(j=0;j0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function() +{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); \ No newline at end of file diff --git a/javascripts/libs/marked.js b/javascripts/libs/marked.js new file mode 100755 index 00000000..25c31cf3 --- /dev/null +++ b/javascripts/libs/marked.js @@ -0,0 +1,771 @@ +/** + * marked - A markdown parser (https://github.com/chjj/marked) + * Copyright (c) 2011-2012, Christopher Jeffrey. (MIT Licensed) + */ + +;(function() { + +/** + * Block-Level Grammar + */ + +var block = { + newline: /^\n+/, + code: /^( {4}[^\n]+\n*)+/, + fences: noop, + hr: /^( *[\-*_]){3,} *(?:\n+|$)/, + heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/, + lheading: /^([^\n]+)\n *(=|-){3,} *\n*/, + blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/, + list: /^( *)([*+-]|\d+\.) [^\0]+?(?:\n{2,}(?! )(?!\1bullet)\n*|\s*$)/, + html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/, + def: /^ *\[([^\]]+)\]: *([^\s]+)(?: +["(]([^\n]+)[")])? *(?:\n+|$)/, + paragraph: /^([^\n]+\n?(?!body))+\n*/, + text: /^[^\n]+/ +}; + +block.list = replace(block.list) + ('bullet', /(?:[*+-](?!(?: *[-*]){2,})|\d+\.)/) + (); + +block.html = replace(block.html) + ('comment', //) + ('closed', /<(tag)[^\0]+?<\/\1>/) + ('closing', /])*?>/) + (/tag/g, tag()) + (); + +block.paragraph = (function() { + var paragraph = block.paragraph.source + , body = []; + + (function push(rule) { + rule = block[rule] ? block[rule].source : rule; + body.push(rule.replace(/(^|[^\[])\^/g, '$1')); + return push; + }) + ('hr') + ('heading') + ('lheading') + ('blockquote') + ('<' + tag()) + ('def'); + + return new + RegExp(paragraph.replace('body', body.join('|'))); +})(); + +block.normal = { + fences: block.fences, + paragraph: block.paragraph +}; + +block.gfm = { + fences: /^ *``` *(\w+)? *\n([^\0]+?)\s*``` *(?:\n+|$)/, + paragraph: /^/ +}; + +block.gfm.paragraph = replace(block.paragraph) + ('(?!', '(?!' + block.gfm.fences.source.replace(/(^|[^\[])\^/g, '$1') + '|') + (); + +/** + * Block Lexer + */ + +block.lexer = function(src) { + var tokens = []; + + tokens.links = {}; + + src = src + .replace(/\r\n|\r/g, '\n') + .replace(/\t/g, ' '); + + return block.token(src, tokens, true); +}; + +block.token = function(src, tokens, top) { + var src = src.replace(/^ +$/gm, '') + , next + , loose + , cap + , item + , space + , i + , l; + + while (src) { + // newline + if (cap = block.newline.exec(src)) { + src = src.substring(cap[0].length); + if (cap[0].length > 1) { + tokens.push({ + type: 'space' + }); + } + } + + // code + if (cap = block.code.exec(src)) { + src = src.substring(cap[0].length); + cap = cap[0].replace(/^ {4}/gm, ''); + tokens.push({ + type: 'code', + text: !options.pedantic + ? cap.replace(/\n+$/, '') + : cap + }); + continue; + } + + // fences (gfm) + if (cap = block.fences.exec(src)) { + src = src.substring(cap[0].length); + tokens.push({ + type: 'code', + lang: cap[1], + text: cap[2] + }); + continue; + } + + // heading + if (cap = block.heading.exec(src)) { + src = src.substring(cap[0].length); + tokens.push({ + type: 'heading', + depth: cap[1].length, + text: cap[2] + }); + continue; + } + + // lheading + if (cap = block.lheading.exec(src)) { + src = src.substring(cap[0].length); + tokens.push({ + type: 'heading', + depth: cap[2] === '=' ? 1 : 2, + text: cap[1] + }); + continue; + } + + // hr + if (cap = block.hr.exec(src)) { + src = src.substring(cap[0].length); + tokens.push({ + type: 'hr' + }); + continue; + } + + // blockquote + if (cap = block.blockquote.exec(src)) { + src = src.substring(cap[0].length); + + tokens.push({ + type: 'blockquote_start' + }); + + cap = cap[0].replace(/^ *> ?/gm, ''); + + // Pass `top` to keep the current + // "toplevel" state. This is exactly + // how markdown.pl works. + block.token(cap, tokens, top); + + tokens.push({ + type: 'blockquote_end' + }); + + continue; + } + + // list + if (cap = block.list.exec(src)) { + src = src.substring(cap[0].length); + + tokens.push({ + type: 'list_start', + ordered: isFinite(cap[2]) + }); + + // Get each top-level item. + cap = cap[0].match( + /^( *)([*+-]|\d+\.) [^\n]*(?:\n(?!\1(?:[*+-]|\d+\.) )[^\n]*)*/gm + ); + + next = false; + l = cap.length; + i = 0; + + for (; i < l; i++) { + item = cap[i]; + + // Remove the list item's bullet + // so it is seen as the next token. + space = item.length; + item = item.replace(/^ *([*+-]|\d+\.) +/, ''); + + // Outdent whatever the + // list item contains. Hacky. + if (~item.indexOf('\n ')) { + space -= item.length; + item = !options.pedantic + ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') + : item.replace(/^ {1,4}/gm, ''); + } + + // Determine whether item is loose or not. + // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/ + // for discount behavior. + loose = next || /\n\n(?!\s*$)/.test(item); + if (i !== l - 1) { + next = item[item.length-1] === '\n'; + if (!loose) loose = next; + } + + tokens.push({ + type: loose + ? 'loose_item_start' + : 'list_item_start' + }); + + // Recurse. + block.token(item, tokens); + + tokens.push({ + type: 'list_item_end' + }); + } + + tokens.push({ + type: 'list_end' + }); + + continue; + } + + // html + if (cap = block.html.exec(src)) { + src = src.substring(cap[0].length); + tokens.push({ + type: 'html', + pre: cap[1] === 'pre', + text: cap[0] + }); + continue; + } + + // def + if (top && (cap = block.def.exec(src))) { + src = src.substring(cap[0].length); + tokens.links[cap[1].toLowerCase()] = { + href: cap[2], + title: cap[3] + }; + continue; + } + + // top-level paragraph + if (top && (cap = block.paragraph.exec(src))) { + src = src.substring(cap[0].length); + tokens.push({ + type: 'paragraph', + text: cap[0] + }); + continue; + } + + // text + if (cap = block.text.exec(src)) { + // Top-level should never reach here. + src = src.substring(cap[0].length); + tokens.push({ + type: 'text', + text: cap[0] + }); + continue; + } + } + + return tokens; +}; + +/** + * Inline Processing + */ + +var inline = { + escape: /^\\([\\`*{}\[\]()#+\-.!_>])/, + autolink: /^<([^ >]+(@|:\/)[^ >]+)>/, + url: noop, + tag: /^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/, + link: /^!?\[(inside)\]\(href\)/, + reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/, + nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/, + strong: /^__([^\0]+?)__(?!_)|^\*\*([^\0]+?)\*\*(?!\*)/, + em: /^\b_((?:__|[^\0])+?)_\b|^\*((?:\*\*|[^\0])+?)\*(?!\*)/, + code: /^(`+)([^\0]*?[^`])\1(?!`)/, + br: /^ {2,}\n(?!\s*$)/, + text: /^[^\0]+?(?=[\\?(?:\s+['"]([^\0]*?)['"])?\s*/; + +inline.link = replace(inline.link) + ('inside', inline._linkInside) + ('href', inline._linkHref) + (); + +inline.reflink = replace(inline.reflink) + ('inside', inline._linkInside) + (); + +inline.normal = { + url: inline.url, + strong: inline.strong, + em: inline.em, + text: inline.text +}; + +inline.pedantic = { + strong: /^__(?=\S)([^\0]*?\S)__(?!_)|^\*\*(?=\S)([^\0]*?\S)\*\*(?!\*)/, + em: /^_(?=\S)([^\0]*?\S)_(?!_)|^\*(?=\S)([^\0]*?\S)\*(?!\*)/ +}; + +inline.gfm = { + url: /^(https?:\/\/[^\s]+[^.,:;"')\]\s])/, + text: /^[^\0]+?(?=[\\' + + text + + ''; + continue; + } + + // url (gfm) + if (cap = inline.url.exec(src)) { + src = src.substring(cap[0].length); + text = escape(cap[1]); + href = text; + out += '' + + text + + ''; + continue; + } + + // tag + if (cap = inline.tag.exec(src)) { + src = src.substring(cap[0].length); + out += options.sanitize + ? escape(cap[0]) + : cap[0]; + continue; + } + + // link + if (cap = inline.link.exec(src)) { + src = src.substring(cap[0].length); + out += outputLink(cap, { + href: cap[2], + title: cap[3] + }); + continue; + } + + // reflink, nolink + if ((cap = inline.reflink.exec(src)) + || (cap = inline.nolink.exec(src))) { + src = src.substring(cap[0].length); + link = (cap[2] || cap[1]).replace(/\s+/g, ' '); + link = links[link.toLowerCase()]; + if (!link || !link.href) { + out += cap[0][0]; + src = cap[0].substring(1) + src; + continue; + } + out += outputLink(cap, link); + continue; + } + + // strong + if (cap = inline.strong.exec(src)) { + src = src.substring(cap[0].length); + out += '' + + inline.lexer(cap[2] || cap[1]) + + ''; + continue; + } + + // em + if (cap = inline.em.exec(src)) { + src = src.substring(cap[0].length); + out += '' + + inline.lexer(cap[2] || cap[1]) + + ''; + continue; + } + + // code + if (cap = inline.code.exec(src)) { + src = src.substring(cap[0].length); + out += '' + + escape(cap[2], true) + + ''; + continue; + } + + // br + if (cap = inline.br.exec(src)) { + src = src.substring(cap[0].length); + out += '
'; + continue; + } + + // text + if (cap = inline.text.exec(src)) { + src = src.substring(cap[0].length); + out += escape(cap[0]); + continue; + } + } + + return out; +}; + +var outputLink = function(cap, link) { + if (cap[0][0] !== '!') { + return '' + + inline.lexer(cap[1]) + + ''; + } else { + return ''
+      + escape(cap[1])
+      + ''; + } +}; + +/** + * Parsing + */ + +var tokens + , token; + +var next = function() { + return token = tokens.pop(); +}; + +var tok = function() { + switch (token.type) { + case 'space': { + return ''; + } + case 'hr': { + return '
\n'; + } + case 'heading': { + return '' + + inline.lexer(token.text) + + '\n'; + } + case 'code': { + return '
'
+        + (token.escaped
+        ? token.text
+        : escape(token.text, true))
+        + '
\n'; + } + case 'blockquote_start': { + var body = ''; + + while (next().type !== 'blockquote_end') { + body += tok(); + } + + return '
\n' + + body + + '
\n'; + } + case 'list_start': { + var type = token.ordered ? 'ol' : 'ul' + , body = ''; + + while (next().type !== 'list_end') { + body += tok(); + } + + return '<' + + type + + '>\n' + + body + + '\n'; + } + case 'list_item_start': { + var body = ''; + + while (next().type !== 'list_item_end') { + body += token.type === 'text' + ? parseText() + : tok(); + } + + return '
  • ' + + body + + '
  • \n'; + } + case 'loose_item_start': { + var body = ''; + + while (next().type !== 'list_item_end') { + body += tok(); + } + + return '
  • ' + + body + + '
  • \n'; + } + case 'html': { + if (options.sanitize) { + return inline.lexer(token.text); + } + return !token.pre && !options.pedantic + ? inline.lexer(token.text) + : token.text; + } + case 'paragraph': { + return '

    ' + + inline.lexer(token.text) + + '

    \n'; + } + case 'text': { + return '

    ' + + parseText() + + '

    \n'; + } + } +}; + +var parseText = function() { + var body = token.text + , top; + + while ((top = tokens[tokens.length-1]) + && top.type === 'text') { + body += '\n' + next().text; + } + + return inline.lexer(body); +}; + +var parse = function(src) { + tokens = src.reverse(); + + var out = ''; + while (next()) { + out += tok(); + } + + tokens = null; + token = null; + + return out; +}; + +/** + * Helpers + */ + +var escape = function(html, encode) { + return html + .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); +}; + +var mangle = function(text) { + var out = '' + , l = text.length + , i = 0 + , ch; + + for (; i < l; i++) { + ch = text.charCodeAt(i); + if (Math.random() > 0.5) { + ch = 'x' + ch.toString(16); + } + out += '&#' + ch + ';'; + } + + return out; +}; + +function tag() { + var tag = '(?!(?:' + + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code' + + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo' + + '|span|br|wbr|ins|del|img)\\b)\\w+'; + + return tag; +} + +function replace(regex) { + regex = regex.source; + return function self(name, val) { + if (!name) return new RegExp(regex); + regex = regex.replace(name, val.source || val); + return self; + }; +} + +function noop() {} +noop.exec = noop; + +/** + * Marked + */ + +var marked = function(src, opt) { + setOptions(opt); + return parse(block.lexer(src)); +}; + +/** + * Options + */ + +var options + , defaults; + +var setOptions = function(opt) { + if (!opt) opt = defaults; + if (options === opt) return; + options = opt; + + if (options.gfm) { + block.fences = block.gfm.fences; + block.paragraph = block.gfm.paragraph; + inline.text = inline.gfm.text; + inline.url = inline.gfm.url; + } else { + block.fences = block.normal.fences; + block.paragraph = block.normal.paragraph; + inline.text = inline.normal.text; + inline.url = inline.normal.url; + } + + if (options.pedantic) { + inline.em = inline.pedantic.em; + inline.strong = inline.pedantic.strong; + } else { + inline.em = inline.normal.em; + inline.strong = inline.normal.strong; + } +}; + +marked.options = +marked.setOptions = function(opt) { + defaults = opt; + setOptions(opt); +}; + +marked.options({ + gfm: true, + pedantic: false, + sanitize: false +}); + +/** + * Expose + */ + +marked.parser = function(src, opt) { + setOptions(opt); + return parse(src); +}; + +marked.lexer = function(src, opt) { + setOptions(opt); + return block.lexer(src); +}; + +marked.parse = marked; + +if (typeof module !== 'undefined') { + module.exports = marked; +} else { + this.marked = marked; +} + +}).call(this); diff --git a/javascripts/libs/modernizr-2.0.6.min.js b/javascripts/libs/modernizr-2.0.6.min.js new file mode 100755 index 00000000..c02c2650 --- /dev/null +++ b/javascripts/libs/modernizr-2.0.6.min.js @@ -0,0 +1,4 @@ +/* Modernizr 2.0.6 | MIT & BSD + * Contains: All core tests, html5shiv, yepnope, respond.js. Get your own custom build at www.modernizr.com/download/ + */ +;window.Modernizr=function(a,b,c){function I(){e.input=function(a){for(var b=0,c=a.length;b",a,""].join(""),k.id=i,k.innerHTML+=f,g.appendChild(k),h=c(k,a),k.parentNode.removeChild(k);return!!h},w=function(b){if(a.matchMedia)return matchMedia(b).matches;var c;v("@media "+b+" { #"+i+" { position: absolute; } }",function(b){c=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle).position=="absolute"});return c},x=function(){function d(d,e){e=e||b.createElement(a[d]||"div"),d="on"+d;var f=d in e;f||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(d,""),f=D(e[d],"function"),D(e[d],c)||(e[d]=c),e.removeAttribute(d))),e=null;return f}var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return d}(),y,z={}.hasOwnProperty,A;!D(z,c)&&!D(z.call,c)?A=function(a,b){return z.call(a,b)}:A=function(a,b){return b in a&&D(a.constructor.prototype[b],c)};var H=function(c,d){var f=c.join(""),g=d.length;v(f,function(c,d){var f=b.styleSheets[b.styleSheets.length-1],h=f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"",i=c.childNodes,j={};while(g--)j[i[g].id]=i[g];e.touch="ontouchstart"in a||j.touch.offsetTop===9,e.csstransforms3d=j.csstransforms3d.offsetLeft===9,e.generatedcontent=j.generatedcontent.offsetHeight>=1,e.fontface=/src/i.test(h)&&h.indexOf(d.split(" ")[0])===0},g,d)}(['@font-face {font-family:"font";src:url("https://")}',["@media (",o.join("touch-enabled),("),i,")","{#touch{top:9px;position:absolute}}"].join(""),["@media (",o.join("transform-3d),("),i,")","{#csstransforms3d{left:9px;position:absolute}}"].join(""),['#generatedcontent:after{content:"',m,'";visibility:hidden}'].join("")],["fontface","touch","csstransforms3d","generatedcontent"]);r.flexbox=function(){function c(a,b,c,d){a.style.cssText=o.join(b+":"+c+";")+(d||"")}function a(a,b,c,d){b+=":",a.style.cssText=(b+o.join(c+";"+b)).slice(0,-b.length)+(d||"")}var d=b.createElement("div"),e=b.createElement("div");a(d,"display","box","width:42px;padding:0;"),c(e,"box-flex","1","width:10px;"),d.appendChild(e),g.appendChild(d);var f=e.offsetWidth===42;d.removeChild(e),g.removeChild(d);return f},r.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},r.canvastext=function(){return!!e.canvas&&!!D(b.createElement("canvas").getContext("2d").fillText,"function")},r.webgl=function(){return!!a.WebGLRenderingContext},r.touch=function(){return e.touch},r.geolocation=function(){return!!navigator.geolocation},r.postmessage=function(){return!!a.postMessage},r.websqldatabase=function(){var b=!!a.openDatabase;return b},r.indexedDB=function(){for(var b=-1,c=p.length;++b7)},r.history=function(){return!!a.history&&!!history.pushState},r.draganddrop=function(){return x("dragstart")&&x("drop")},r.websockets=function(){for(var b=-1,c=p.length;++b";return(a.firstChild&&a.firstChild.namespaceURI)==q.svg},r.smil=function(){return!!b.createElementNS&&/SVG/.test(n.call(b.createElementNS(q.svg,"animate")))},r.svgclippaths=function(){return!!b.createElementNS&&/SVG/.test(n.call(b.createElementNS(q.svg,"clipPath")))};for(var J in r)A(r,J)&&(y=J.toLowerCase(),e[y]=r[J](),u.push((e[y]?"":"no-")+y));e.input||I(),e.addTest=function(a,b){if(typeof a=="object")for(var d in a)A(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return;b=typeof b=="boolean"?b:!!b(),g.className+=" "+(b?"":"no-")+a,e[a]=b}return e},B(""),j=l=null,a.attachEvent&&function(){var a=b.createElement("div");a.innerHTML="";return a.childNodes.length!==1}()&&function(a,b){function s(a){var b=-1;while(++b=u.minw)&&(!u.maxw||u.maxw&&l<=u.maxw))m[u.media]||(m[u.media]=[]),m[u.media].push(f[u.rules])}for(var t in g)g[t]&&g[t].parentNode===j&&j.removeChild(g[t]);for(var t in m){var v=c.createElement("style"),w=m[t].join("\n");v.type="text/css",v.media=t,v.styleSheet?v.styleSheet.cssText=w:v.appendChild(c.createTextNode(w)),n.appendChild(v),g.push(v)}j.insertBefore(n,o.nextSibling)}},s=function(a,b){var c=t();if(!!c){c.open("GET",a,!0),c.onreadystatechange=function(){c.readyState==4&&(c.status==200||c.status==304)&&b(c.responseText)};if(c.readyState==4)return;c.send()}},t=function(){var a=!1,b=[function(){return new ActiveXObject("Microsoft.XMLHTTP")},function(){return new XMLHttpRequest}],c=b.length;while(c--){try{a=b[c]()}catch(d){continue}break}return function(){return a}}();m(),respond.update=m,a.addEventListener?a.addEventListener("resize",u,!1):a.attachEvent&&a.attachEvent("onresize",u)}}(this,Modernizr.mq("only all")),function(a,b,c){function k(a){return!a||a=="loaded"||a=="complete"}function j(){var a=1,b=-1;while(p.length- ++b)if(p[b].s&&!(a=p[b].r))break;a&&g()}function i(a){var c=b.createElement("script"),d;c.src=a.s,c.onreadystatechange=c.onload=function(){!d&&k(c.readyState)&&(d=1,j(),c.onload=c.onreadystatechange=null)},m(function(){d||(d=1,j())},H.errorTimeout),a.e?c.onload():n.parentNode.insertBefore(c,n)}function h(a){var c=b.createElement("link"),d;c.href=a.s,c.rel="stylesheet",c.type="text/css";if(!a.e&&(w||r)){var e=function(a){m(function(){if(!d)try{a.sheet.cssRules.length?(d=1,j()):e(a)}catch(b){b.code==1e3||b.message=="security"||b.message=="denied"?(d=1,m(function(){j()},0)):e(a)}},0)};e(c)}else c.onload=function(){d||(d=1,m(function(){j()},0))},a.e&&c.onload();m(function(){d||(d=1,j())},H.errorTimeout),!a.e&&n.parentNode.insertBefore(c,n)}function g(){var a=p.shift();q=1,a?a.t?m(function(){a.t=="c"?h(a):i(a)},0):(a(),j()):q=0}function f(a,c,d,e,f,h){function i(){!o&&k(l.readyState)&&(r.r=o=1,!q&&j(),l.onload=l.onreadystatechange=null,m(function(){u.removeChild(l)},0))}var l=b.createElement(a),o=0,r={t:d,s:c,e:h};l.src=l.data=c,!s&&(l.style.display="none"),l.width=l.height="0",a!="object"&&(l.type=d),l.onload=l.onreadystatechange=i,a=="img"?l.onerror=i:a=="script"&&(l.onerror=function(){r.e=r.r=1,g()}),p.splice(e,0,r),u.insertBefore(l,s?null:n),m(function(){o||(u.removeChild(l),r.r=r.e=o=1,j())},H.errorTimeout)}function e(a,b,c){var d=b=="c"?z:y;q=0,b=b||"j",C(a)?f(d,a,b,this.i++,l,c):(p.splice(this.i++,0,a),p.length==1&&g());return this}function d(){var a=H;a.loader={load:e,i:0};return a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=r&&!s,u=s?l:n.parentNode,v=a.opera&&o.call(a.opera)=="[object Opera]",w="webkitAppearance"in l.style,x=w&&"async"in b.createElement("script"),y=r?"object":v||x?"img":"script",z=w?"img":y,A=Array.isArray||function(a){return o.call(a)=="[object Array]"},B=function(a){return Object(a)===a},C=function(a){return typeof a=="string"},D=function(a){return o.call(a)=="[object Function]"},E=[],F={},G,H;H=function(a){function f(a){var b=a.split("!"),c=E.length,d=b.pop(),e=b.length,f={url:d,origUrl:d,prefixes:b},g,h;for(h=0;h date2) return -1; + return 0; + }, + sortLabel :function(thisObject,thatObject) { + if(!thisObject.labels.length) return 1; + if(!thatObject.labels.length) return -1; + if (thisObject.labels[0].name > thatObject.labels[0].name){ + return 1; + } + else if (thisObject.labels[0].name < thatObject.labels[0].name){ + return -1; + } + return 0; + }, + callApi: function(options){ + var myoption = $.extend({}, options); + if(myoption.repo) delete myoption.repo; + return $.ajax({ + url:this.urls[options.action](options), + dataType:respType, + data:myoption + }); + }, + urls : { + domainName : "https://api.github.com", + milestones : function(){ + if(!settings.phpApi){ + return $url = this.domainName+ "/repos/"+settings.username +"/"+ settings.repo +"/milestones"; + }else{ + return apiPath; + }; + }, + issues : function(){ + if(!settings.phpApi){ + return $url = this.domainName+"/repos/"+ settings.username +"/"+ settings.repo +"/issues"; + }else{ + return apiPath; + }; + }, + comments : function(options){ + if(!settings.phpApi){ + return $url = this.domainName+"/repos/"+ settings.username +"/"+ settings.repo+"/issues/"+ options.issueid +"/comments"; + }else{ + return apiPath; + } + } + } + }; + + return this.each(function(){ + releases.load(this, settings); + }); + }; + var components = { + milestone : function(data){ + return $('
    \ +

    '+data.title+'

    \ +

    Release Date: '+data.prettyDate+'

    \ +
    \ +
    ').data("milestone", data); + }, + issue : function(data){ + var labels = "", + _this = this; + + $.each(data.labels, function(i, label){ labels += _this.label(label); }); + return $('
    \ +
    \ +
    '+labels+' '+$("").html(data.title).text()+'
    \ +
    \ +
    \ +
    \ +
    \ +
    ').data("issue", data); + }, + label : function(data){ + return ''+data.name+''; + }, + bigIssue : function(data, showComment){ + var commentLink = (data.comments != 0 && showComment) ? 'See Comments' : ""; + + return $('
    \ + \ +
    \ +
    \ +
    \ +

    Opened by '+data.user.login+', issue closed on '+data.prettyDate+'

    \ +

    '+$("").html(data.title).text()+'

    \ +
    \ +
    \ + '+marked(data.body)+'\ +
    \ +
    \ +
    \ +
    \ +
    \ +
    '+commentLink).data("issue", data); + }, + comment : function(data){ + return '
    \ + \ +
    \ +
    \ +
    \ +

    \ + \ + '+data.user.login+'\ + \ + commented\ + \ +

    \ +

    \ + '+data.prettyDate+'\ +

    \ +
    \ +
    \ +
    \ +
    '+marked(data.body)+'
    \ +
    \ +
    \ +
    \ +
    \ +
    '; + } + } +})(jQuery); \ No newline at end of file diff --git a/javascripts/scale.fix.js b/javascripts/scale.fix.js new file mode 100644 index 00000000..08716c00 --- /dev/null +++ b/javascripts/scale.fix.js @@ -0,0 +1,20 @@ +fixScale = function(doc) { + + var addEvent = 'addEventListener', + type = 'gesturestart', + qsa = 'querySelectorAll', + scales = [1, 1], + meta = qsa in doc ? doc[qsa]('meta[name=viewport]') : []; + + function fix() { + meta.content = 'width=device-width,minimum-scale=' + scales[0] + ',maximum-scale=' + scales[1]; + doc.removeEventListener(type, fix, true); + } + + if ((meta = meta[meta.length - 1]) && addEvent in doc) { + fix(); + scales = [.25, 1.6]; + doc[addEvent](type, fix, true); + } + +}; \ No newline at end of file diff --git a/javascripts/script.js b/javascripts/script.js new file mode 100644 index 00000000..ac839012 --- /dev/null +++ b/javascripts/script.js @@ -0,0 +1,99 @@ +(function($) { +$(document).ready(function(){ + + // putting lines by the pre blocks + $("pre").each(function(){ + var pre = $(this).text().split("\n"); + var lines = new Array(pre.length+1); + for(var i = 0; i < pre.length; i++) { + var wrap = Math.floor(pre[i].split("").length / 70) + if (pre[i]==""&&i==pre.length-1) { + lines.splice(i, 1); + } else { + lines[i] = i+1; + for(var j = 0; j < wrap; j++) { + lines[i] += "\n"; + } + } + } + $(this).before("
    " + lines.join("\n") + "
    "); + }); + + var headings = []; + + var collectHeaders = function(){ + headings.push({"top":$(this).offset().top - 15,"text":$(this).text()}); + } + + if($(".markdown-body h1").length > 1) $(".markdown-body h1").each(collectHeaders) + else if($(".markdown-body h2").length > 1) $(".markdown-body h2").each(collectHeaders) + else if($(".markdown-body h3").length > 1) $(".markdown-body h3").each(collectHeaders) + + $(window).scroll(function(){ + if(headings.length==0) return true; + var scrolltop = $(window).scrollTop() || 0; + if(headings[0] && scrolltop < headings[0].top) { + $(".current-section").css({"opacity":0,"visibility":"hidden"}); + return false; + } + $(".current-section").css({"opacity":1,"visibility":"visible"}); + for(var i in headings) { + if(scrolltop >= headings[i].top) { + $(".current-section .name").text(headings[i].text); + } + } + }); + + $(".current-section a").click(function(){ + $(window).scrollTop(0); + return false; + }) +}); +} +var defaultSettings = { + milestoneNumber : 10, + usePHPapi : true, + apiPath : '/', + repo : 'rails', + username : 'rails' + }; +$.fn.releaseNotes = function(settings){ + settings = $.extend({}, defaultSettings, settings || {}); + var apiPath = apiPath."api.php"; + var respType = (settings.usePHPapi) ? "jsonp" : "json" + + return this.each(function(){ + releases.load(this, settings); + }); + + var releases = { + + load: function(){ + this.callApi({ + action:"milestones" + }).success(function(resp){ + console.log(resp) + }) + }, + callApi: function(action){ + + return $.ajax({ + url:this.urls[action](), + dataType:respType, + data:settings + }) + }, + urls : { + milestones : function(){ + if(settings.usePHPapi){ + return $url = "/repos/". $configs["username"] ."/". $configs["repo"] ."/milestones"; + }else{ + return apiPath; + } + } + } + } + + + } +)(jQuery) diff --git a/params.json b/params.json new file mode 100644 index 00000000..943f1d68 --- /dev/null +++ b/params.json @@ -0,0 +1 @@ +{"name":"Canal","tagline":"阿里巴巴mysql数据库binlog的增量订阅&消费组件","body":"
    \r\n
    \r\n

    \r\n

    背景

    \r\n

    早期,阿里巴巴B2B公司因为存在杭州和美国双机房部署,存在跨机房同步的业务需求。不过早期的数据库同步业务,主要是基于trigger的方式获取增量变更,不过从2010年开始,阿里系公司开始逐步的尝试基于数据库的日志解析,获取增量变更进行同步,由此衍生出了增量订阅&消费的业务,从此开启了一段新纪元。ps. 目前内部使用的同步,已经支持mysql5.x和oracle部分版本的日志解析

    \r\n

    \r\n

    基于日志增量订阅&消费支持的业务:

    \r\n
      \r\n
    1. 数据库镜像
    2. \r\n
    3. 数据库实时备份
    4. \r\n
    5. 多级索引 (卖家和买家各自分库索引)
    6. \r\n
    7. search build
    8. \r\n
    9. 业务cache刷新
    10. \r\n
    11. 价格变化等重要业务消息
    12. \r\n
    \r\n

    项目介绍

    \r\n

    名称:canal [kə'næl]

    \r\n

    译意: 水道/管道/沟渠

    \r\n

    语言: 纯java开发

    \r\n

    定位: 基于数据库增量日志解析,提供增量数据订阅&消费,目前主要支持了mysql

    \r\n

    \r\n

    工作原理

    \r\n

    mysql主备复制实现

    \r\n

    \"\"
    从上层来看,复制分成三步:

    \r\n
      \r\n
    1. master将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log events,可以通过show binlog events进行查看);
    2. \r\n
    3. slave将master的binary log events拷贝到它的中继日志(relay log);
    4. \r\n
    5. slave重做中继日志中的事件,将改变反映它自己的数据。
    6. \r\n
    \r\n

    canal的工作原理:

    \r\n

    \"\"

    \r\n

    原理相对比较简单:

    \r\n
      \r\n
    1. canal模拟mysql slave的交互协议,伪装自己为mysql slave,向mysql master发送dump协议
    2. \r\n
    3. mysql master收到dump请求,开始推送binary log给slave(也就是canal)
    4. \r\n
    5. canal解析binary log对象(原始为byte流)
    6. \r\n
    \r\n

    架构

    \r\n

    \"\"

    \r\n

    说明:

    \r\n
      \r\n
    • server代表一个canal运行实例,对应于一个jvm
    • \r\n
    • instance对应于一个数据队列 (1个server对应1..n个instance)
    • \r\n
    \r\n

    instance模块:

    \r\n
      \r\n
    • eventParser (数据源接入,模拟slave协议和master进行交互,协议解析)
    • \r\n
    • eventSink (Parser和Store链接器,进行数据过滤,加工,分发的工作)
    • \r\n
    • eventStore (数据存储)
    • \r\n
    • metaManager (增量订阅&消费信息管理器)
    • \r\n
    \r\n

    数据对象格式:EntryProtocol.proto\r\n

    \r\n
    Entry\r\n    Header\r\n\t\tlogfileName [binlog文件名]\r\n\t\tlogfileOffset [binlog position]\r\n\t\texecuteTime [发生的变更]\r\n\t\tschemaName \r\n\t\ttableName\r\n\t\teventType [insert/update/delete类型]\r\n\tentryType \t[事务头BEGIN/事务尾END/数据ROWDATA]\r\n\tstoreValue \t[byte数据,可展开,对应的类型为RowChange]\r\n\t\r\nRowChange\r\n\tisDdl\t\t[是否是ddl变更操作,比如create table/drop table]\r\n\tsql\t\t[具体的ddl sql]\r\n\trowDatas\t[具体insert/update/delete的变更数据,可为多条,1个binlog event事件可对应多条变更,比如批处理]\r\n\t\tbeforeColumns [Column类型的数组]\r\n\t\tafterColumns [Column类型的数组]\r\n\t\t\r\nColumn \r\n\tindex\t\t\r\n\tsqlType\t\t[jdbc type]\r\n\tname\t\t[column name]\r\n\tisKey\t\t[是否为主键]\r\n\tupdated\t\t[是否发生过变更]\r\n\tisNull\t\t[值是否为null]\r\n\tvalue\t\t[具体的内容,注意为文本]
    \r\n

    说明:

    \r\n
      \r\n
    • 可以提供数据库变更前和变更后的字段内容,针对binlog中没有的name,isKey等信息进行补全
    • \r\n
    • 可以提供ddl的变更语句
    • \r\n
    \r\n

    QuickStart

    \r\n

    几点说明:(mysql初始化)

    \r\n

    a. canal的原理是基于mysql binlog技术,所以这里一定需要开启mysql的binlog写入功能,并且配置binlog模式为row.

    \r\n
    [mysqld]\r\nlog-bin=mysql-bin #添加这一行就ok\r\nbinlog-format=ROW #选择row模式\r\nserver_id=1 #配置mysql replaction需要定义,不能和canal的slaveId重复
    \r\nb. canal的原理是模拟自己为mysql slave,所以这里一定需要做为mysql slave的相关权限.
    \r\n
    \r\n
    CREATE USER canal IDENTIFIED BY 'canal';  \r\nGRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';\r\n-- GRANT ALL PRIVILEGES ON *.* TO 'canal'@'%' ;\r\nFLUSH PRIVILEGES;
    \r\n

    针对已有的账户可通过grants查询权限:

    \r\n

    启动步骤:

    \r\n

    1. 下载canal

    \r\n

    下载部署包

    \r\n
    wget http://canal4mysql.googlecode.com/files/canal.deployer-1.0.0.tar.gz
    \r\n

    or

    \r\n

    自己编译

    \r\n
    git clone git@github.com:otter-projects/canal.git\r\ncd canal; \r\nmvn clean install -Dmaven.test.skip -Denv=release
    \r\n

    编译完成后,会在根目录下产生target/canal.deployer-$version.tar.gz

    \r\n

    \r\n

    2. 解压缩

    \r\n
    mkdir /tmp/canal\r\ntar zxvf canal.deployer-1.0.0.tar.gz  -C /tmp/canal
    \r\n

    \r\n

    解压完成后,进入/tmp/canal目录,可以看到如下结构:

    \r\n

    \r\n
    drwxr-xr-x 2 jianghang jianghang  136 2013-02-05 21:51 bin\r\ndrwxr-xr-x 4 jianghang jianghang  160 2013-02-05 21:51 conf\r\ndrwxr-xr-x 2 jianghang jianghang 1.3K 2013-02-05 21:51 lib\r\ndrwxr-xr-x 2 jianghang jianghang   48 2013-02-05 21:29 logs
    \r\n

    \r\n

    3. 配置修改

    \r\n

    \r\n

    公用参数:

    \r\n
    vi conf/canal.properties
    \r\n
    #################################################\r\n#########               common argument         ############# \r\n#################################################\r\ncanal.id= 1\r\ncanal.address=\r\ncanal.port= 11111\r\ncanal.zkServers=\r\n# flush data to zk\r\ncanal.zookeeper.flush.period = 1000\r\n## memory store RingBuffer size, should be Math.pow(2,n)\r\ncanal.instance.memory.buffer.size = 32768\r\n\r\n## detecing config\r\ncanal.instance.detecting.enable = false\r\ncanal.instance.detecting.sql = insert into retl.xdual values(1,now()) on duplicate key update x=now()\r\ncanal.instance.detecting.interval.time = 3 \r\ncanal.instance.detecting.retry.threshold = 3 \r\ncanal.instance.detecting.heartbeatHaEnable = false\r\n\r\n# support maximum transaction size, more than the size of the transaction will be cut into multiple transactions delivery\r\ncanal.instance.transactionn.size =  1024\r\n\r\n# network config\r\ncanal.instance.network.receiveBufferSize = 16384\r\ncanal.instance.network.sendBufferSize = 16384\r\ncanal.instance.network.soTimeout = 30\r\n\r\n#################################################\r\n#########               destinations            ############# \r\n#################################################\r\ncanal.destinations= example\r\n\r\ncanal.instance.global.mode = spring \r\ncanal.instance.global.lazy = true  ##修改为false,代表立马启动\r\n#canal.instance.global.manager.address = 127.0.0.1:1099\r\ncanal.instance.global.spring.xml = classpath:spring/memory-instance.xml\r\n#canal.instance.global.spring.xml = classpath:spring/default-instance.xml
    \r\n

    \r\n

    应用参数:

    \r\n
    vi conf/example/instance.properties
    \r\n
    #################################################\r\n## mysql serverId\r\ncanal.instance.mysql.slaveId = 1234\r\n\r\n# position info\r\ncanal.instance.master.address = 127.0.0.1:3306 #改成自己的数据库地址\r\ncanal.instance.master.journal.name = \r\ncanal.instance.master.position = \r\ncanal.instance.master.timestamp = \r\n\r\n#canal.instance.standby.address = \r\n#canal.instance.standby.journal.name =\r\n#canal.instance.standby.position = \r\n#canal.instance.standby.timestamp = \r\n\r\n# username/password\r\ncanal.instance.dbUsername = retl  #改成自己的数据库信息\r\ncanal.instance.dbPassword = retl  #改成自己的数据库信息\r\ncanal.instance.defaultDatabaseName =   #改成自己的数据库信息\r\ncanal.instance.connectionCharsetNumber = 33  #改成自己的数据库信息\r\ncanal.instance.connectionCharset = UTF-8  #改成自己的数据库信息\r\n\r\n# table regex\r\ncanal.instance.filter.regex = .*\\\\..*\r\n\r\n#################################################\r\n
    \r\n

    \r\n

    \r\n

    说明:

    \r\n
      \r\n
    • canal.instance.connectionCharset 代表数据库的编码方式对应到java中的编码类型,比如UTF-8,GBK , ISO-8859-1
    • \r\n
    • canal.instance.connectionCharsetNumber 代表数据库的编码方式对应mysql中的唯一id,详细的映射关系可查看:com.mysql.jdbc.CharsetMapping.INDEX_TO_CHARSET
      针对常见的编码:
      utf-8 <=> 33
      gb2312 <=> 24
      gbk <=> 28
    • \r\n
    \r\n

    4. 准备启动

    \r\n

    \r\n
    sh bin/startup.sh
    \r\n

    \r\n

    5. 查看日志

    \r\n
    vi logs/canal/canal.log
    \r\n
    2013-02-05 22:45:27.967 [main] INFO  com.alibaba.otter.canal.deployer.CanalLauncher - ## start the canal server.\r\n2013-02-05 22:45:28.113 [main] INFO  com.alibaba.otter.canal.deployer.CanalController - ## start the canal server[10.1.29.120:11111]\r\n2013-02-05 22:45:28.210 [main] INFO  com.alibaba.otter.canal.deployer.CanalLauncher - ## the canal server is running now ......
    \r\n

    \r\n

    具体instance的日志:

    \r\n
    vi logs/example/example.log
    \r\n
    2013-02-05 22:50:45.636 [main] INFO  c.a.o.c.i.spring.support.PropertyPlaceholderConfigurer - Loading properties file from class path resource [canal.properties]\r\n2013-02-05 22:50:45.641 [main] INFO  c.a.o.c.i.spring.support.PropertyPlaceholderConfigurer - Loading properties file from class path resource [example/instance.properties]\r\n2013-02-05 22:50:45.803 [main] INFO  c.a.otter.canal.instance.spring.CanalInstanceWithSpring - start CannalInstance for 1-example \r\n2013-02-05 22:50:45.810 [main] INFO  c.a.otter.canal.instance.spring.CanalInstanceWithSpring - start successful....
    \r\n

    \r\n

    6. 关闭

    \r\n
    sh bin/stop.sh
    \r\n

    \r\n

    it's over.

    \r\n
    \r\n

    ClientExample

    \r\n

    依赖配置:(目前暂未正式发布到mvn仓库,所以需要各位下载canal源码后手工执行下mvn clean install -Dmaven.test.skip)

    \r\n
    <dependency>\r\n    <groupId>com.alibaba.otter</groupId>\r\n    <artifactId>canal.client</artifactId>\r\n    <version>1.0.0</version>\r\n</dependency>
    \r\n

    \r\n

    1. 创建mvn标准工程:

    \r\n
    mvn archetype:create -DgroupId=com.alibaba.otter -DartifactId=canal.sample
    \r\n

    \r\n

    2. 修改pom.xml,添加依赖

    \r\n

    \r\n

    3. ClientSample代码

    \r\n
    package com.alibaba.otter.canal.sample;\r\n\r\nimport java.net.InetSocketAddress;\r\nimport java.util.List;\r\n\r\nimport com.alibaba.otter.canal.common.utils.AddressUtils;\r\nimport com.alibaba.otter.canal.protocol.Message;\r\nimport com.alibaba.otter.canal.protocol.CanalEntry.Column;\r\nimport com.alibaba.otter.canal.protocol.CanalEntry.Entry;\r\nimport com.alibaba.otter.canal.protocol.CanalEntry.EntryType;\r\nimport com.alibaba.otter.canal.protocol.CanalEntry.EventType;\r\nimport com.alibaba.otter.canal.protocol.CanalEntry.RowChange;\r\nimport com.alibaba.otter.canal.protocol.CanalEntry.RowData;\r\n\r\npublic class SimpleCanalClientExample {\r\n\r\n    public static void main(String args[]) {\r\n        // 创建链接\r\n        CanalConnector connector = CanalConnectors.newSingleConnector(new InetSocketAddress(AddressUtils.getHostIp(),\r\n                                                                                            11111), \"example\", \"\", \"\");\r\n        int batchSize = 1000;\r\n        int emptyCount = 0;\r\n        try {\r\n            connector.connect();\r\n            connector.subscribe(\".*\\\\..*\");\r\n            connector.rollback();\r\n            int totalEmtryCount = 120;\r\n            while (emptyCount < totalEmtryCount) {\r\n                Message message = connector.getWithoutAck(batchSize); // 获取指定数量的数据\r\n                long batchId = message.getId();\r\n                int size = message.getEntries().size();\r\n                if (batchId == -1 || size == 0) {\r\n                    emptyCount++;\r\n                    System.out.println(\"empty count : \" + emptyCount);\r\n                    try {\r\n                        Thread.sleep(1000);\r\n                    } catch (InterruptedException e) {\r\n                    }\r\n                } else {\r\n                    emptyCount = 0;\r\n                    // System.out.printf(\"message[batchId=%s,size=%s] \\n\", batchId, size);\r\n                    printEntry(message.getEntries());\r\n                }\r\n\r\n                connector.ack(batchId); // 提交确认\r\n                // connector.rollback(batchId); // 处理失败, 回滚数据\r\n            }\r\n\r\n            System.out.println(\"empty too many times, exit\");\r\n        } finally {\r\n            connector.disconnect();\r\n        }\r\n    }\r\n\r\n    private static void printEntry(List<Entry> entrys) {\r\n        for (Entry entry : entrys) {\r\n            if (entry.getEntryType() == EntryType.TRANSACTIONBEGIN || entry.getEntryType() == EntryType.TRANSACTIONEND) {\r\n                continue;\r\n            }\r\n\r\n            RowChange rowChage = null;\r\n            try {\r\n                rowChage = RowChange.parseFrom(entry.getStoreValue());\r\n            } catch (Exception e) {\r\n                throw new RuntimeException(\"ERROR ## parser of eromanga-event has an error , data:\" + entry.toString(),\r\n                                           e);\r\n            }\r\n\r\n            EventType eventType = rowChage.getEventType();\r\n            System.out.println(String.format(\"================> binlog[%s:%s] , name[%s,%s] , eventType : %s\",\r\n                                             entry.getHeader().getLogfileName(), entry.getHeader().getLogfileOffset(),\r\n                                             entry.getHeader().getSchemaName(), entry.getHeader().getTableName(),\r\n                                             eventType));\r\n\r\n            for (RowData rowData : rowChage.getRowDatasList()) {\r\n                if (eventType == EventType.DELETE) {\r\n                    printColumn(rowData.getBeforeColumnsList());\r\n                } else if (eventType == EventType.INSERT) {\r\n                    printColumn(rowData.getAfterColumnsList());\r\n                } else {\r\n                    System.out.println(\"-------> before\");\r\n                    printColumn(rowData.getBeforeColumnsList());\r\n                    System.out.println(\"-------> after\");\r\n                    printColumn(rowData.getAfterColumnsList());\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    private static void printColumn(List<Column> columns) {\r\n        for (Column column : columns) {\r\n            System.out.println(column.getName() + \" : \" + column.getValue() + \"    update=\" + column.getUpdated());\r\n        }\r\n    }\r\n}
    \r\n

    \r\n

    4. 运行Client

    \r\n

    首先启动Canal Server,可参加QuickStart : http://agapple.iteye.com/blogs/1796070

    \r\n

    启动Canal Client后,可以从控制台从看到类似消息:

    \r\n
    empty count : 1\r\nempty count : 2\r\nempty count : 3\r\nempty count : 4
    \r\n

    此时代表当前数据库无变更数据

    \r\n

    \r\n

    5. 触发数据库变更

    \r\n
    mysql> use test;\r\nDatabase changed\r\nmysql> CREATE TABLE `xdual` (\r\n    ->   `ID` int(11) NOT NULL AUTO_INCREMENT,\r\n    ->   `X` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n    ->   PRIMARY KEY (`ID`)\r\n    -> ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 ;\r\nQuery OK, 0 rows affected (0.06 sec)\r\n\r\nmysql> insert into xdual(id,x) values(null,now());Query OK, 1 row affected (0.06 sec)
    \r\n

    \r\n

    可以从控制台中看到:

    \r\n
    empty count : 1\r\nempty count : 2\r\nempty count : 3\r\nempty count : 4\r\n================> binlog[mysql-bin.001946:313661577] , name[test,xdual] , eventType : INSERT\r\nID : 4    update=true\r\nX : 2013-02-05 23:29:46    update=true
    \r\n

    \r\n

    最后:

    \r\n

    整个代码在附件中可以下载,如有问题可及时联系。

    \r\n
    \r\n \r\n
    \r\ncanal.sample.tar.gz (2.2 KB)\r\n
    \r\n","google":"UA-10379866-5","note":"Don't delete this file! It's used internally to help with page regeneration."} \ No newline at end of file diff --git a/release.html b/release.html new file mode 100755 index 00000000..33d973c6 --- /dev/null +++ b/release.html @@ -0,0 +1,46 @@ + + + + + + + + + + + Release Notes + + + + + + + + + + + +
    +
    +

    Release Notes

    +
    + +
    +
    + + diff --git a/stylesheets/pygment_trac.css b/stylesheets/pygment_trac.css new file mode 100644 index 00000000..c6a6452d --- /dev/null +++ b/stylesheets/pygment_trac.css @@ -0,0 +1,69 @@ +.highlight { background: #ffffff; } +.highlight .c { color: #999988; font-style: italic } /* Comment */ +.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +.highlight .k { font-weight: bold } /* Keyword */ +.highlight .o { font-weight: bold } /* Operator */ +.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ +.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ +.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #aa0000 } /* Generic.Error */ +.highlight .gh { color: #999999 } /* Generic.Heading */ +.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ +.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ +.highlight .go { color: #888888 } /* Generic.Output */ +.highlight .gp { color: #555555 } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold; } /* Generic.Subheading */ +.highlight .gt { color: #aa0000 } /* Generic.Traceback */ +.highlight .kc { font-weight: bold } /* Keyword.Constant */ +.highlight .kd { font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ +.highlight .m { color: #009999 } /* Literal.Number */ +.highlight .s { color: #d14 } /* Literal.String */ +.highlight .na { color: #008080 } /* Name.Attribute */ +.highlight .nb { color: #0086B3 } /* Name.Builtin */ +.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ +.highlight .no { color: #008080 } /* Name.Constant */ +.highlight .ni { color: #800080 } /* Name.Entity */ +.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ +.highlight .nn { color: #555555 } /* Name.Namespace */ +.highlight .nt { color: #000080 } /* Name.Tag */ +.highlight .nv { color: #008080 } /* Name.Variable */ +.highlight .ow { font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mf { color: #009999 } /* Literal.Number.Float */ +.highlight .mh { color: #009999 } /* Literal.Number.Hex */ +.highlight .mi { color: #009999 } /* Literal.Number.Integer */ +.highlight .mo { color: #009999 } /* Literal.Number.Oct */ +.highlight .sb { color: #d14 } /* Literal.String.Backtick */ +.highlight .sc { color: #d14 } /* Literal.String.Char */ +.highlight .sd { color: #d14 } /* Literal.String.Doc */ +.highlight .s2 { color: #d14 } /* Literal.String.Double */ +.highlight .se { color: #d14 } /* Literal.String.Escape */ +.highlight .sh { color: #d14 } /* Literal.String.Heredoc */ +.highlight .si { color: #d14 } /* Literal.String.Interpol */ +.highlight .sx { color: #d14 } /* Literal.String.Other */ +.highlight .sr { color: #009926 } /* Literal.String.Regex */ +.highlight .s1 { color: #d14 } /* Literal.String.Single */ +.highlight .ss { color: #990073 } /* Literal.String.Symbol */ +.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #008080 } /* Name.Variable.Class */ +.highlight .vg { color: #008080 } /* Name.Variable.Global */ +.highlight .vi { color: #008080 } /* Name.Variable.Instance */ +.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ + +.type-csharp .highlight .k { color: #0000FF } +.type-csharp .highlight .kt { color: #0000FF } +.type-csharp .highlight .nf { color: #000000; font-weight: normal } +.type-csharp .highlight .nc { color: #2B91AF } +.type-csharp .highlight .nn { color: #000000 } +.type-csharp .highlight .s { color: #A31515 } +.type-csharp .highlight .sc { color: #A31515 } diff --git a/stylesheets/releasenotes.plugin.css b/stylesheets/releasenotes.plugin.css new file mode 100644 index 00000000..dc27faa5 --- /dev/null +++ b/stylesheets/releasenotes.plugin.css @@ -0,0 +1,274 @@ + + + + +.milestoneContainer{ + padding-bottom:35px; + margin-bottom:10px; +} + .milestoneContainer.separator{background:url("../images/lineseparator.png") bottom center no-repeat;} + .milestoneContainer .cursor:hover{cursor:pointer;} + +h3.release {margin:0 0 2px 0;font-size:18px;} +p.dateRelease{margin:0 0 10px 0; font-size:14px;} + + .milestoneContainer .body p{padding:5px 0; margin:0;} + .milestoneContainer pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12.025px; + line-height: 18px; + background-color: whiteSmoke; + border: 1px solid #CCC; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; + } + .milestoneContainer code, .milestoneContainer pre { + padding: 0 3px 2px; + font-family: Menlo,Monaco,"Courier New",monospace; + font-size: 12px; + color: #333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + + + /* BUTTONS */ + .milestoneContainer .btn { + display: inline-block; + text-decoration:none; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + padding: 4px 10px 4px; + margin-bottom: 0; + font-size: 13px; + line-height: 18px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); + border: 1px solid #cccccc; + border-bottom-color: #b3b3b3; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + cursor: pointer; + *margin-left: .3em; + } + .milestoneContainer .btn:hover, + .milestoneContainer .btn:active{ + background-color: #e6e6e6; + } + .milestoneContainer .btn:active, + .milestoneContainer .btn.active { + background-color: #cccccc \9; + } + .milestoneContainer .btn:first-child { + *margin-left: 0; + } + .milestoneContainer .btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; + } + .milestoneContainer .btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; + } + .milestoneContainer .btn:active { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + outline: 0; + } + + + /* ISSUE DESCRIPTION */ + .milestoneContainer .date{ + font-size:14px; + } + .milestoneContainer .cmeta .date {font-size:11px;} + .milestoneContainer .issue{ + padding-bottom: 3px; + } + .milestoneContainer .issues{ + color:#555; + } + .milestoneContainer .issueTitle{ + line-height:24px; + font-size:13px; + } + .milestoneContainer .label{ + display:inline-block; + font-family: arial; + font-weight:normal; + line-height: 13px; + color: white; + vertical-align: middle; + white-space: nowrap; + font-size:12px; + color:#fff; + text-shadow: 1px 1px 1 #000; + padding:3px 4px; + border-radius:5px; + margin-top: -6px; + margin-right:5px; + } + + + .milestoneContainer .btnComments{ + margin:-8px 0 15px 63px ; + } + + .milestoneContainer .hidden{display:none;} + .milestoneContainer .content-body{ + padding-top:10px; + margin-top:15px; + border-top:1px solid #CACACA; + } + .milestoneContainer .normal-comment .content-body{ + padding-top: 0px; + margin-top: 0px; + border-top: none; + } + + /* COMMENTS */ + + .milestoneContainer .new-comments .bubble .comment { margin: 0 } + .milestoneContainer .view-pull-request .new-comments .bubble .commit-comment { margin-top: 3px } + .milestoneContainer .new-comments .bubble .commit-comment.thread-start { margin-top: 0 } + .milestoneContainer .bubble .comment-form { margin: 0 } + + .milestoneContainer .avatar-bubble { + margin: 20px 0; + padding-left: 60px; + background: url('../images/bubble-arrow.png') 51px 20px no-repeat; + } + .milestoneContainer .avatar-bubble>.avatar { + position: relative; + float: left; + margin-left: -60px; + } + .bubble { + padding: 3px; + background: #eee; + border-radius: 3px; + } + .milestoneContainer .avatar-bubble .form-actions { margin-top: 10px } + .milestoneContainer .bubble .file-box { margin-bottom: 0 } + + .milestoneContainer .avatar img { border-radius: 3px } + + .milestoneContainer .starting-comment { + margin: 0; + background: #fff; + padding:0px; + border: 1px solid #CACACA; + border-radius: 2px; + } + .milestoneContainer .normal-comment .starting-comment{ padding:10px;} + .milestoneContainer .starting-comment .content-title { border-bottom: none } + .milestoneContainer .starting-comment h2.content-title { + margin: 0 0 -6px; + font-size: 20px; + font-weight: bold; + } + .milestoneContainer .starting-comment .body p.author { + margin: 0px 0 0; + color: #666; + font-size: 12px; + } + .milestoneContainer .starting-comment p.author a { + font-weight: bold; + color: #666; + } + .milestoneContainer .new-comments .starting-comment .body { + padding: 0 10px; + font-size: 13px; + background: #fff; + } + .milestoneContainer .comment .cmeta { + height: 33px; + padding: 0 10px; + border-bottom: 1px solid #CCC; + background-color: #F8F8F8; + background-image: -moz-linear-gradient(#F8F8F8,#E1E1E1); + background-image: -webkit-linear-gradient(#F8F8F8,#E1E1E1); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#f8f8f8',endColorstr='#e1e1e1',GradientType=0)"; + } + .milestoneContainer .comment .cmeta p.author { + margin: 0; + float: left; + max-width: 600px; + font-size: 12px; + height: 33px; + line-height: 33px; + text-shadow: 1px 1px 0 rgba(255, 255, 255, 0.7); + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + .milestoneContainer .comment .cmeta .icon { + display: inline-block; + margin-top: -2px; + margin-left: 0px; + width: 16px; + height: 16px; + vertical-align: middle; + background: url('../images/icons.png') 0 0 no-repeat; + } + .milestoneContainer .comment .cmeta p.author a { + color: #222; + } + + .milestoneContainer .comment .cmeta p.info { + float: right; + margin: 0; + font-size: 11px; + height: 33px; + line-height: 33px; + } + + .milestoneContainer .comment > .body { + position: relative; + padding: 10px; + color: #333; + font-size: 12px; + background: #FBFBFB; + } \ No newline at end of file diff --git a/stylesheets/style.css b/stylesheets/style.css new file mode 100755 index 00000000..cbf814ca --- /dev/null +++ b/stylesheets/style.css @@ -0,0 +1,30 @@ +body{ + background:url(../images/bg.jpg); + text-shadow: 1px 1px 0px white; + margin: 0; + font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; + font-size: 13px; + line-height: 18px; + color: #333; +} + +h1, h2, h3, h4, h5, h6 { + margin: 0; + font-family: inherit; + font-weight: bold; + color: inherit; + text-rendering: optimizelegibility; +} +h1 { + font-size: 30px; + line-height: 36px; + padding: 50px 0 20px; +} +#websiteContainer{ + background:url(../images/bg2.png) top left no-repeat; + height: 529px; +} +.containerRelease{ + width:780px; + margin-left:230px; +} diff --git a/stylesheets/styles.css b/stylesheets/styles.css new file mode 100644 index 00000000..f14d9e46 --- /dev/null +++ b/stylesheets/styles.css @@ -0,0 +1,413 @@ +@import url(https://fonts.googleapis.com/css?family=Arvo:400,700,400italic); + +/* MeyerWeb Reset */ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font: inherit; + vertical-align: baseline; +} + + +/* Base text styles */ + +body { + padding:10px 50px 0 0; + font-family:"Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + color: #232323; + background-color: #FBFAF7; + margin: 0; + line-height: 1.8em; + -webkit-font-smoothing: antialiased; + +} + +h1, h2, h3, h4, h5, h6 { + color:#232323; + margin:36px 0 10px; +} + +p, ul, ol, table, dl { + margin:0 0 22px; +} + +h1, h2, h3 { + font-family: Arvo, Monaco, serif; + line-height:1.3; + font-weight: normal; +} + +h1,h2, h3 { + display: block; + border-bottom: 1px solid #ccc; + padding-bottom: 5px; +} + +h1 { + font-size: 30px; +} + +h2 { + font-size: 24px; +} + +h3 { + font-size: 18px; +} + +h4, h5, h6 { + font-family: Arvo, Monaco, serif; + font-weight: 700; +} + +a { + color:#C30000; + font-weight:200; + text-decoration:none; +} + +a:hover { + text-decoration: underline; +} + +a small { + font-size: 12px; +} + +em { + font-style: italic; +} + +strong { + font-weight:700; +} + +ul li { + list-style: inside; + padding-left: 25px; +} + +ol li { + list-style: decimal inside; + padding-left: 20px; +} + +blockquote { + margin: 0; + padding: 0 0 0 20px; + font-style: italic; +} + +dl, dt, dd, dl p { + font-color: #444; +} + +dl dt { + font-weight: bold; +} + +dl dd { + padding-left: 20px; + font-style: italic; +} + +dl p { + padding-left: 20px; + font-style: italic; +} + +hr { + border:0; + background:#ccc; + height:1px; + margin:0 0 24px; +} + +/* Images */ + +img { + position: relative; + margin: 0 auto; + max-width: 650px; + padding: 5px; + margin: 10px 0 32px 0; + border: 1px solid #ccc; +} + + +/* Code blocks */ + +code, pre { + font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; + color:#000; + font-size:14px; +} + +pre { + padding: 4px 12px; + background: #FDFEFB; + border-radius:4px; + border:1px solid #D7D8C8; + overflow: auto; + overflow-y: hidden; + margin-bottom: 32px; +} + + +/* Tables */ + +table { + width:100%; +} + +table { + border: 1px solid #ccc; + margin-bottom: 32px; + text-align: left; + } + +th { + font-family: 'Arvo', Helvetica, Arial, sans-serif; + font-size: 18px; + font-weight: normal; + padding: 10px; + background: #232323; + color: #FDFEFB; + } + +td { + padding: 10px; + background: #ccc; + } + + +/* Wrapper */ +.wrapper { + width:960px; +} + + +/* Header */ + +header { + background-color: #171717; + color: #FDFDFB; + width:170px; + float:left; + position:fixed; + border: 1px solid #000; + -webkit-border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 4px; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + padding: 34px 25px 22px 50px; + margin: 30px 25px 0 0; + -webkit-font-smoothing: antialiased; +} + +p.header { + font-size: 16px; +} + +h1.header { + font-family: Arvo, sans-serif; + font-size: 30px; + font-weight: 300; + line-height: 1.3em; + border-bottom: none; + margin-top: 0; +} + + +h1.header, a.header, a.name, header a{ + color: #fff; +} + +a.header { + text-decoration: underline; +} + +a.name { + white-space: nowrap; +} + +header ul { + list-style:none; + padding:0; +} + +header li { + list-style-type: none; + width:132px; + height:15px; + margin-bottom: 12px; + line-height: 1em; + padding: 6px 6px 6px 7px; + + background: #AF0011; + background: -moz-linear-gradient(top, #AF0011 0%, #820011 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#dddddd)); + background: -webkit-linear-gradient(top, #AF0011 0%,#820011 100%); + background: -o-linear-gradient(top, #AF0011 0%,#820011 100%); + background: -ms-linear-gradient(top, #AF0011 0%,#820011 100%); + background: linear-gradient(top, #AF0011 0%,#820011 100%); + + border-radius:4px; + border:1px solid #0D0D0D; + + -webkit-box-shadow: inset 0px 1px 1px 0 rgba(233,2,38, 1); + box-shadow: inset 0px 1px 1px 0 rgba(233,2,38, 1); + +} + +header li:hover { + background: #C3001D; + background: -moz-linear-gradient(top, #C3001D 0%, #950119 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#dddddd)); + background: -webkit-linear-gradient(top, #C3001D 0%,#950119 100%); + background: -o-linear-gradient(top, #C3001D 0%,#950119 100%); + background: -ms-linear-gradient(top, #C3001D 0%,#950119 100%); + background: linear-gradient(top, #C3001D 0%,#950119 100%); +} + +a.buttons { + -webkit-font-smoothing: antialiased; + background: url(../images/arrow-down.png) no-repeat; + font-weight: normal; + text-shadow: rgba(0, 0, 0, 0.4) 0 -1px 0; + padding: 2px 2px 2px 22px; + height: 30px; +} + +a.github { + background: url(../images/octocat-small.png) no-repeat 1px; +} + +a.buttons:hover { + color: #fff; + text-decoration: none; +} + + +/* Section - for main page content */ + +section { + width:650px; + float:right; + padding-bottom:50px; +} + + +/* Footer */ + +footer { + width:170px; + float:left; + position:fixed; + bottom:10px; + padding-left: 50px; +} + +@media print, screen and (max-width: 960px) { + + div.wrapper { + width:auto; + margin:0; + } + + header, section, footer { + float:none; + position:static; + width:auto; + } + + footer { + border-top: 1px solid #ccc; + margin:0 84px 0 50px; + padding:0; + } + + header { + padding-right:320px; + } + + section { + padding:20px 84px 20px 50px; + margin:0 0 20px; + } + + header a small { + display:inline; + } + + header ul { + position:absolute; + right:130px; + top:84px; + } +} + +@media print, screen and (max-width: 720px) { + body { + word-wrap:break-word; + } + + header { + padding:10px 20px 0; + margin-right: 0; + } + + section { + padding:10px 0 10px 20px; + margin:0 0 30px; + } + + footer { + margin: 0 0 0 30px; + } + + header ul, header p.view { + position:static; + } +} + +@media print, screen and (max-width: 480px) { + + header ul li.download { + display:none; + } + + footer { + margin: 0 0 0 20px; + } + + footer a{ + display:block; + } + +} + +@media print { + body { + padding:0.4in; + font-size:12pt; + color:#444; + } +} \ No newline at end of file diff --git a/stylesheets/stylesheet.css b/stylesheets/stylesheet.css new file mode 100644 index 00000000..6a618f31 --- /dev/null +++ b/stylesheets/stylesheet.css @@ -0,0 +1,581 @@ +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} + +/* Style */ + +body { + font-size: 15px; + font-family: Arial, Arial, Helvetica, sans-serif; + line-height: 1.5; + background: #D1D1D1; +} + +a { + color: #63a52a; + text-decoration: none; + -webkit-transition: color ease-in-out 0.3s; +} + +a:hover { + text-decoration: underline; + color: #90D355; +} + +h1.title { + margin: 30px 20px 10px; + font-size: 60px; + font-weight: bold; + font-style: italic; + font-family:Georgia, serif; + text-align: center; +} + +.wrapper { + width: 675px; + margin: 0 auto; +} + +#container { + border: 1px solid #2a2a2a; + background: #ddd url(../images/pattern.png); + box-shadow: 0 0 5px #b1b1b1; +} + +p.tagline { + padding: 20px 20px 0; + color: #fff; + font-size: 17px; +} + +#main { + margin-top: 20px; + padding: 0 20px 90px; + background-color: #fff; +} + +.download-bar { + background: #222; + border: 5px solid #444; + padding: 10px; + margin: 0 -35px 20px; + position: relative; +} + +.download-bar .inner { + overflow: hidden; +} + +.download-bar .watch-fork iframe { + display: block; + float: left; + border-right: 1px solid #ddd; + padding-right: 5px; +} +.download-bar .watch-fork iframe.last { + border-right: 0 none; + padding-right: 0; + padding-left: 5px; + border-left: 1px solid #fff; +} +.download-bar .watch-fork { + overflow: hidden; + float: right; + background-color: #eee; + padding: 5px; + border-radius: 3px; +} + +.download-bar .blc { + border: 10px solid black; + border-color: transparent transparent black; + width: 0; + height: 0; + display: block; + position: absolute; + bottom: -15px; + left: 0; + -moz-transform: rotate(45deg); + -webkit-transform: rotate(45deg); +} + +.download-bar .trc { + border: 10px solid black; + border-color: black transparent transparent; + width: 0; + height: 0; + display: block; + position: absolute; + top: -15px; + right: 0; + -moz-transform: rotate(45deg); + -webkit-transform: rotate(45deg); +} + +.download-bar .avatar { + border: 1px solid black; + display: block; + padding: 4px; + float: left; +} + +.download-bar .avatar img { + display: block; +} + +.download-bar a.code { + background: transparent url(../images/code.png) no-repeat 0 2px; + padding-left: 35px; + margin-top: 8px; + display: block; + float: left; + text-indent: 0; + width: auto; + height: auto; + opacity: 1; + -moz-opacity: 1; + filter:alpha(opacity=1); +} + +.current-section { + position: fixed; + top: 0; + left: 50%; + width: 693px; + margin-left: -352px; + background: #222; + border: 5px solid #444; + color: #fff; + opacity: 0; + visibility: hidden; + -webkit-transition: opacity ease-in-out 0.3s; +} + +.current-section p { + padding: 5px 27px; + font-size: 24px; + font-weight: bold; +} + +.current-section a { + float: right; + text-indent: -10000px; + background: transparent url(../images/top.png) no-repeat 0 0; + width: 20px; + height: 20px; + opacity: 0.8; + margin-right: 12px; + margin-top: 12px; + -moz-opacity: 0.8; + filter:alpha(opacity=8); + -webkit-transition: opacity ease-in-out 0.3s; +} + +.current-section a:hover { + opacity: 1; + -moz-opacity: 1; + filter:alpha(opacity=1); +} + +.current-section a.zip { + margin-right: 8px; +} + +a.zip, +a.zip span { + background: transparent url(../images/zip.png) no-repeat 0 0; + width: 30px; + height: 21px; + opacity: 0.8; + display: inline-block; + text-indent: -10000px; + -moz-opacity: 0.8; + filter:alpha(opacity=8); + -webkit-transition: opacity ease-in-out 0.3s; +} + +a.tar, +a.tar span { + background: transparent url(../images/tar.png) no-repeat 0 0; + width: 30px; + height: 21px; + opacity: 0.8; + display: inline-block; + text-indent: -10000px; + -moz-opacity: 0.8; + filter:alpha(opacity=8); + -webkit-transition: opacity ease-in-out 0.3s; +} + +a.code { + background: transparent url(../images/code.png) no-repeat 0 2px; + width: 30px; + height: 21px; + display: block; + opacity: 0.8; + display: inline-block; + text-indent: -10000px; + -moz-opacity: 0.8; + filter:alpha(opacity=8); + -webkit-transition: opacity ease-in-out 0.3s; +} + +a.zip:hover, +a.tar:hover, +a.code:hover { + opacity: 1; + -moz-opacity: 1; + filter:alpha(opacity=1); +} + +a.download-button { + border: 1px solid black; + border-radius: 3px; + display: inline-block; + text-indent: 0!important; + width: auto; + float: right; + background: #999; /* for non-css3 browsers */ + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#37ADD4', endColorstr='#1B657E'); /* for IE */ + background: -webkit-gradient(linear, left top, left bottom, from(#37ADD4), to(#1B657E)); /* for webkit browsers */ + background: -moz-linear-gradient(top, #37ADD4, #1B657E); /* for firefox 3.6+ */ + height: auto; + margin-left: 10px; +} + +a.download-button span { + background-position: 10px 5px; + width: auto; + height: auto; + padding: 5px 10px; + padding-left: 45px; + display: inline-block; + text-indent: 0!important; + color: #fff; +} + +footer { + margin-bottom: 60px; + padding-bottom: 60px; +} + +footer .owner { + background: #222; + border: 5px solid #444; + padding: 5px 15px; + margin: -67px -10px 35px; + color: #d6d6d6; +} + +footer .creds small { + float: right; + font-size: 10px; + text-align: right; + margin-left: 15px; +} + +footer .owner .avatar { + background-color: #666; + display: block; + margin: -19px 10px 0 0; + width: 60px; + float: left; +} + +footer .owner img { + display: block; + border: 1px solid #2a2a2a; + margin: 5px; +} + +footer .owner p { + font-family:Georgia, serif; +} + +footer .owner p a { + font-size: 16px; + font-style: italic; +} + +/* Markdown */ +.markdown-body h1, +.markdown-body h2, +.markdown-body h3, +.markdown-body h4, +.markdown-body h5, +.markdown-body h6, +.markdown-body p, +.markdown-body pre, +.markdown-body ul, +.markdown-body ol, +.markdown-body dl, +.markdown-body table, +.markdown-body blockquote { + margin-bottom: 20px; +} + +.markdown-body h1, +.markdown-body h2, +.markdown-body h3, +.markdown-body h4, +.markdown-body h5, +.markdown-body h6 { + font-weight: bold; +} + +.markdown-body h1 { + font-size: 28px; +} + +.markdown-body h2 { + font-size: 24px; + color: #557398; +} + +.markdown-body h3 { + font-size: 20px; +} + +.markdown-body h4 { + font-size: 18px; +} + +.markdown-body h5 { + font-size: 16px; +} + +.markdown-body pre { + padding: 10px 70px 10px 0; + margin-left: -20px; + margin-right: -20px; + font-family: 'Monaco', 'Lucida Console', monospace; + font-size: 13px; + line-height: 20px; + box-shadow: inset 0 0 5px #000; + word-wrap: break-word; + background-color:#3b3b3b; + color: #d6d6d6; +} + +.markdown-body pre.lines { + font-size: 12px; + margin:0 10px 0 -20px; + padding: 10px; + float: left; + display: block; + text-align: right; + box-shadow: none; + background-color:#2a2a2a; + color: #d6d6d6; +} + +.markdown-body ul, +.markdown-body ol { + padding-left: 30px; +} + +.markdown-body ul { + list-style-type: disc; +} + +.markdown-body li, +.markdown-body li p, +.markdown-body dd, +.markdown-body dd p { + margin-bottom: 10px; +} + +.markdown-body li pre, +.markdown-body li pre.lines, +.markdown-body dd pre, +.markdown-body dd pre.lines { + margin-left: -35px; +} + +.markdown-body dt { + font-weight: bold; + font-style: italic; +} + +.markdown-body dd { + margin-left: 15px; +} + +.markdown-body table { + width: 673px; + margin-left: -20px; + margin-right: -20px; +} + +.markdown-body tbody { + border-top: 2px solid #557398; + border-bottom: 2px solid #557398; + background-color: #EBEFF4; +} + +.markdown-body table td * { + margin: 0; +} + +.markdown-body td { + border-right: 1px solid #557398; + border-bottom: 1px solid #557398; + padding: 5px; +} + +.markdown-body td:first-child, +.markdown-body th:first-child { + width: 30%; + padding-left: 20px; +} + +.markdown-body td:last-child { + border-right: 0 none; +} + +.markdown-body th { + font-size: 18px; + font-weight: bold; + text-align: left; + padding: 5px; +} + +.markdown-body tt { + background-color:#3b3b3b; + color: #d6d6d6; + padding: 2px 3px; +} + +.markdown-body blockquote { + font-style: italic; + font-family:Georgia, serif; + font-size: 17px; + border-top: 3px solid #333; + border-bottom: 3px solid #333; + padding: 10px 20px; + padding-left: 50px; +} + +.markdown-body blockquote:before { + font-style: italic; + font-family: Georgia, serif; + font-size: 90px; + height: 90px; + margin-left: -60px; + margin-top: -25px; + content: "‟"; + display: block; + float: left; +} + +.markdown-body img { + max-width: 100%; + @include box-sizing(border-box); +} + +.highlight { background: #ffffff; } +.highlight .c { color: #999988; font-style: italic } /* Comment */ +.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +.highlight .k { font-weight: bold } /* Keyword */ +.highlight .o { font-weight: bold } /* Operator */ +.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ +.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ +.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #aa0000 } /* Generic.Error */ +.highlight .gh { color: #999999 } /* Generic.Heading */ +.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ +.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ +.highlight .go { color: #888888 } /* Generic.Output */ +.highlight .gp { color: #555555 } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold; } /* Generic.Subheading */ +.highlight .gt { color: #aa0000 } /* Generic.Traceback */ +.highlight .kc { font-weight: bold } /* Keyword.Constant */ +.highlight .kd { font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ +.highlight .m { color: #009999 } /* Literal.Number */ +.highlight .s { color: #d14 } /* Literal.String */ +.highlight .na { color: #008080 } /* Name.Attribute */ +.highlight .nb { color: #0086B3 } /* Name.Builtin */ +.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ +.highlight .no { color: #008080 } /* Name.Constant */ +.highlight .ni { color: #800080 } /* Name.Entity */ +.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ +.highlight .nn { color: #555555 } /* Name.Namespace */ +.highlight .nt { color: #000080 } /* Name.Tag */ +.highlight .nv { color: #008080 } /* Name.Variable */ +.highlight .ow { font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mf { color: #009999 } /* Literal.Number.Float */ +.highlight .mh { color: #009999 } /* Literal.Number.Hex */ +.highlight .mi { color: #009999 } /* Literal.Number.Integer */ +.highlight .mo { color: #009999 } /* Literal.Number.Oct */ +.highlight .sb { color: #d14 } /* Literal.String.Backtick */ +.highlight .sc { color: #d14 } /* Literal.String.Char */ +.highlight .sd { color: #d14 } /* Literal.String.Doc */ +.highlight .s2 { color: #d14 } /* Literal.String.Double */ +.highlight .se { color: #d14 } /* Literal.String.Escape */ +.highlight .sh { color: #d14 } /* Literal.String.Heredoc */ +.highlight .si { color: #d14 } /* Literal.String.Interpol */ +.highlight .sx { color: #d14 } /* Literal.String.Other */ +.highlight .sr { color: #009926 } /* Literal.String.Regex */ +.highlight .s1 { color: #d14 } /* Literal.String.Single */ +.highlight .ss { color: #990073 } /* Literal.String.Symbol */ +.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #008080 } /* Name.Variable.Class */ +.highlight .vg { color: #008080 } /* Name.Variable.Global */ +.highlight .vi { color: #008080 } /* Name.Variable.Instance */ +.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ \ No newline at end of file