This commit is contained in:
agapple
2013-06-07 20:24:33 +08:00
commit 36bb82b3bc
30 changed files with 4315 additions and 0 deletions

6
download.html Normal file
View File

@@ -0,0 +1,6 @@
<HTML><HEAD><TITLE>Canal Versions</TITLE></HEAD><BODY>
<H1>Canal Versions</H1>
<TABLE BORDER=0>
<TR><TD><A HREF="/download/canal.deployer-1.0.2.tar.gz">canal.deployer-1.0.2.tar.gz&nbsp;</TD><TD ALIGN=right>8470464 bytes&nbsp;</TD><TD>Mar 13, 2013 6:49:34 PM</TD></TR></TABLE>
</BODY></HTML>

BIN
images/arrow-down.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

BIN
images/bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

BIN
images/bg2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

BIN
images/bg_new.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
images/bodybg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
images/bubble-arrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
images/code.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
images/icons.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 127 KiB

BIN
images/lineseparator.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
images/octocat-small.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 B

BIN
images/pattern.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
images/tar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
images/top.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
images/zip.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

446
index.html Normal file
View File

@@ -0,0 +1,446 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>Canal by alibaba</title>
<link rel="stylesheet" href="stylesheets/styles.css">
<link rel="stylesheet" href="stylesheets/pygment_trac.css">
<script src="javascripts/scale.fix.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<div class="wrapper">
<header>
<h1 class="header">Canal</h1>
<p class="header">阿里巴巴mysql数据库binlog的增量订阅&amp;消费组件</p>
<ul>
<li class="download"><a class="buttons" href="https://github.com/alibaba/canal/zipball/master">Download ZIP</a></li>
<li class="download"><a class="buttons" href="https://github.com/alibaba/canal/tarball/master">Download TAR</a></li>
<li><a class="buttons github" href="https://github.com/alibaba/canal">View On GitHub</a></li>
</ul>
<p class="header">This project is maintained by <a class="header name" href="https://github.com/alibaba">alibaba</a></p>
</header>
<section>
<div>
<div>
<p> </p>
<h1>背景</h1>
<p> 早期,阿里巴巴B2B公司因为存在杭州和美国双机房部署,存在跨机房同步的业务需求。不过早期的数据库同步业务,主要是基于trigger的方式获取增量变更,不过从2010年开始,阿里系公司开始逐步的尝试基于数据库的日志解析,获取增量变更进行同步,由此衍生出了增量订阅&amp;消费的业务,从此开启了一段新纪元。ps. 目前内部使用的同步,已经支持mysql5.x和oracle部分版本的日志解析</p>
<p> </p>
<p>基于日志增量订阅&amp;消费支持的业务:</p>
<ol>
<li>数据库镜像</li>
<li>数据库实时备份</li>
<li>多级索引 (卖家和买家各自分库索引)</li>
<li>search build</li>
<li>业务cache刷新</li>
<li>价格变化等重要业务消息</li>
</ol>
<h1>项目介绍</h1>
<p> 名称:canal [kə'næl]</p>
<p> 译意: 水道/管道/沟渠 </p>
<p> 语言: 纯java开发</p>
<p> 定位: 基于数据库增量日志解析,提供增量数据订阅&amp;消费,目前主要支持了mysql</p>
<p> </p>
<h2>工作原理</h2>
<h3>mysql主备复制实现</h3>
<p><img src="http://dl.iteye.com/upload/attachment/0080/3086/468c1a14-e7ad-3290-9d3d-44ac501a7227.jpg" alt=""><br> 从上层来看,复制分成三步:</p>
<ol>
<li>master将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log events,可以通过show binlog events进行查看);</li>
<li>slave将master的binary log events拷贝到它的中继日志(relay log);</li>
<li>slave重做中继日志中的事件,将改变反映它自己的数据。</li>
</ol>
<h3>canal的工作原理:</h3>
<p><img width="590" src="http://dl.iteye.com/upload/attachment/0080/3107/c87b67ba-394c-3086-9577-9db05be04c95.jpg" alt="" height="273"></p>
<p>原理相对比较简单:</p>
<ol>
<li>canal模拟mysql slave的交互协议,伪装自己为mysql slave,向mysql master发送dump协议</li>
<li>mysql master收到dump请求,开始推送binary log给slave(也就是canal)</li>
<li>canal解析binary log对象(原始为byte流)</li>
</ol>
<h1>架构</h1>
<p><img width="548" src="http://dl.iteye.com/upload/attachment/0080/3126/49550085-0cd2-32fa-86a6-f676db5b597b.jpg" alt="" height="238"></p>
<p>说明:</p>
<ul>
<li>server代表一个canal运行实例,对应于一个jvm</li>
<li>instance对应于一个数据队列 (1个server对应1..n个instance)</li>
</ul>
<p>instance模块:</p>
<ul>
<li>eventParser (数据源接入,模拟slave协议和master进行交互,协议解析)</li>
<li>eventSink (Parser和Store链接器,进行数据过滤,加工,分发的工作)</li>
<li>eventStore (数据存储)</li>
<li>metaManager (增量订阅&amp;消费信息管理器)</li>
</ul>
<h3>数据对象格式:<a href="https://github.com/otter-projects/canal/blob/master/protocol/src/main/java/com/alibaba/otter/canal/protocol/EntryProtocol.proto">EntryProtocol.proto</a>
</h3>
<pre name="code">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 [具体的内容,注意为文本]</pre>
<p>说明:</p>
<ul>
<li>可以提供数据库变更前和变更后的字段内容,针对binlog中没有的name,isKey等信息进行补全</li>
<li>可以提供ddl的变更语句</li>
</ul>
<h1>QuickStart</h1>
<h2>几点说明:(mysql初始化)</h2>
<p>a. canal的原理是基于mysql binlog技术,所以这里一定需要开启mysql的binlog写入功能,并且配置binlog模式为row. </p>
<pre name="code">[mysqld]
log-bin=mysql-bin #添加这一行就ok
binlog-format=ROW #选择row模式
server_id=1 #配置mysql replaction需要定义,不能和canal的slaveId重复</pre>
b. canal的原理是模拟自己为mysql slave,所以这里一定需要做为mysql slave的相关权限.</div>
<div>
<pre name="code">CREATE USER canal IDENTIFIED BY 'canal';
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
-- GRANT ALL PRIVILEGES ON *.* TO 'canal'@'%' ;
FLUSH PRIVILEGES;</pre>
<p>针对已有的账户可通过grants查询权限:</p>
<h2>启动步骤:</h2>
<p>1. 下载canal</p>
<p>下载部署包</p>
<pre name="code">wget http://canal4mysql.googlecode.com/files/canal.deployer-1.0.0.tar.gz</pre>
<p>or </p>
<p>自己编译 </p>
<pre name="code">git clone git@github.com:otter-projects/canal.git
cd canal;
mvn clean install -Dmaven.test.skip -Denv=release</pre>
<p> 编译完成后,会在根目录下产生target/canal.deployer-$version.tar.gz </p>
<p> </p>
<p>2. 解压缩</p>
<pre name="code">mkdir /tmp/canal
tar zxvf canal.deployer-1.0.0.tar.gz -C /tmp/canal</pre>
<p> </p>
<p> 解压完成后,进入/tmp/canal目录,可以看到如下结构:</p>
<p> </p>
<pre name="code">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</pre>
<p> </p>
<p>3. 配置修改</p>
<p> </p>
<p>公用参数: </p>
<pre name="code">vi conf/canal.properties</pre>
<pre name="code">#################################################
######### 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</pre>
<p> </p>
<p>应用参数:</p>
<pre name="code">vi conf/example/instance.properties</pre>
<pre name="code">#################################################
## 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 = .*\\..*
#################################################
</pre>
<p> </p>
<p> </p>
<p> 说明:</p>
<ul>
<li>canal.instance.connectionCharset 代表数据库的编码方式对应到java中的编码类型,比如UTF-8,GBK , ISO-8859-1</li>
<li>canal.instance.connectionCharsetNumber 代表数据库的编码方式对应mysql中的唯一id,详细的映射关系可查看:com.mysql.jdbc.CharsetMapping.INDEX_TO_CHARSET<br>针对常见的编码:<br>utf-8 &lt;=&gt; 33<br>gb2312 &lt;=&gt; 24<br>gbk &lt;=&gt; 28</li>
</ul>
<p>4. 准备启动</p>
<p> </p>
<pre name="code">sh bin/startup.sh</pre>
<p> </p>
<p>5. 查看日志</p>
<pre name="code">vi logs/canal/canal.log</pre>
<pre name="code">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 ......</pre>
<p> </p>
<p> 具体instance的日志:</p>
<pre name="code">vi logs/example/example.log</pre>
<pre name="code">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....</pre>
<p> </p>
<p>6. 关闭</p>
<pre name="code">sh bin/stop.sh</pre>
<p> </p>
<p>it's over. </p>
</div>
<h1>ClientExample</h1>
<p>依赖配置:(目前暂未正式发布到mvn仓库,所以需要各位下载canal源码后手工执行下mvn clean install -Dmaven.test.skip)</p>
<pre name="code">&lt;dependency&gt;
&lt;groupId&gt;com.alibaba.otter&lt;/groupId&gt;
&lt;artifactId&gt;canal.client&lt;/artifactId&gt;
&lt;version&gt;1.0.0&lt;/version&gt;
&lt;/dependency&gt;</pre>
<p> </p>
<p>1. 创建mvn标准工程:</p>
<pre name="code">mvn archetype:create -DgroupId=com.alibaba.otter -DartifactId=canal.sample</pre>
<p> </p>
<p>2. 修改pom.xml,添加依赖</p>
<p> </p>
<p>3. ClientSample代码</p>
<pre name="code">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 &lt; 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&lt;Entry&gt; 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("================&gt; 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("-------&gt; before");
printColumn(rowData.getBeforeColumnsList());
System.out.println("-------&gt; after");
printColumn(rowData.getAfterColumnsList());
}
}
}
}
private static void printColumn(List&lt;Column&gt; columns) {
for (Column column : columns) {
System.out.println(column.getName() + " : " + column.getValue() + " update=" + column.getUpdated());
}
}
}</pre>
<p> </p>
<p>4. 运行Client</p>
<p>首先启动Canal Server,可参加QuickStart : <a href="/blogs/1796070">http://agapple.iteye.com/blogs/1796070</a></p>
<p>启动Canal Client后,可以从控制台从看到类似消息:</p>
<pre name="code">empty count : 1
empty count : 2
empty count : 3
empty count : 4</pre>
<p> 此时代表当前数据库无变更数据</p>
<p> </p>
<p>5. 触发数据库变更</p>
<pre name="code">mysql&gt; use test;
Database changed
mysql&gt; CREATE TABLE `xdual` (
-&gt; `ID` int(11) NOT NULL AUTO_INCREMENT,
-&gt; `X` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-&gt; PRIMARY KEY (`ID`)
-&gt; ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 ;
Query OK, 0 rows affected (0.06 sec)
mysql&gt; insert into xdual(id,x) values(null,now());Query OK, 1 row affected (0.06 sec)</pre>
<p> </p>
<p>可以从控制台中看到:</p>
<pre name="code">empty count : 1
empty count : 2
empty count : 3
empty count : 4
================&gt; binlog[mysql-bin.001946:313661577] , name[test,xdual] , eventType : INSERT
ID : 4 update=true
X : 2013-02-05 23:29:46 update=true</pre>
<p> </p>
<h2>最后:</h2>
<p> 整个代码在附件中可以下载,如有问题可及时联系。 </p>
<p></p>
</div>
<p></p><div>
<a href="http://dl.iteye.com/topics/download/7a893f19-bafb-313a-8a7a-e371a4265ad9">canal.sample.tar.gz</a> (2.2 KB)
</div>
</section>
<footer>
<p><small>Hosted on <a href="https://pages.github.com">GitHub Pages</a> using the Dinky theme</small></p>
</footer>
</div>
<!--[if !IE]><script>fixScale(document);</script><![endif]-->
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
try {
var pageTracker = _gat._getTracker("UA-10379866-5");
pageTracker._trackPageview();
} catch(err) {}
</script>
</body>
</html>

4
javascripts/libs/jquery-1.7.1.min.js vendored Executable file

File diff suppressed because one or more lines are too long

771
javascripts/libs/marked.js Executable file
View File

@@ -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', /<!--[^\0]*?-->/)
('closed', /<(tag)[^\0]+?<\/\1>/)
('closing', /<tag(?!:\/|@)\b(?:"[^"]*"|'[^']*'|[^'">])*?>/)
(/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: /^<!--[^\0]*?-->|^<\/?\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]+?(?=[\\<!\[_*`]| {2,}\n|$)/
};
inline._linkInside = /(?:\[[^\]]*\]|[^\]]|\](?=[^\[]*\]))*/;
inline._linkHref = /\s*<?([^\s]*?)>?(?:\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]+?(?=[\\<!\[_*`]|https?:\/\/| {2,}\n|$)/
};
/**
* Inline Lexer
*/
inline.lexer = function(src) {
var out = ''
, links = tokens.links
, link
, text
, href
, cap;
while (src) {
// escape
if (cap = inline.escape.exec(src)) {
src = src.substring(cap[0].length);
out += cap[1];
continue;
}
// autolink
if (cap = inline.autolink.exec(src)) {
src = src.substring(cap[0].length);
if (cap[2] === '@') {
text = cap[1][6] === ':'
? mangle(cap[1].substring(7))
: mangle(cap[1]);
href = mangle('mailto:') + text;
} else {
text = escape(cap[1]);
href = text;
}
out += '<a href="'
+ href
+ '">'
+ text
+ '</a>';
continue;
}
// url (gfm)
if (cap = inline.url.exec(src)) {
src = src.substring(cap[0].length);
text = escape(cap[1]);
href = text;
out += '<a href="'
+ href
+ '">'
+ text
+ '</a>';
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 += '<strong>'
+ inline.lexer(cap[2] || cap[1])
+ '</strong>';
continue;
}
// em
if (cap = inline.em.exec(src)) {
src = src.substring(cap[0].length);
out += '<em>'
+ inline.lexer(cap[2] || cap[1])
+ '</em>';
continue;
}
// code
if (cap = inline.code.exec(src)) {
src = src.substring(cap[0].length);
out += '<code>'
+ escape(cap[2], true)
+ '</code>';
continue;
}
// br
if (cap = inline.br.exec(src)) {
src = src.substring(cap[0].length);
out += '<br>';
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 '<a href="'
+ escape(link.href)
+ '"'
+ (link.title
? ' title="'
+ escape(link.title)
+ '"'
: '')
+ '>'
+ inline.lexer(cap[1])
+ '</a>';
} else {
return '<img src="'
+ escape(link.href)
+ '" alt="'
+ escape(cap[1])
+ '"'
+ (link.title
? ' title="'
+ escape(link.title)
+ '"'
: '')
+ '>';
}
};
/**
* Parsing
*/
var tokens
, token;
var next = function() {
return token = tokens.pop();
};
var tok = function() {
switch (token.type) {
case 'space': {
return '';
}
case 'hr': {
return '<hr>\n';
}
case 'heading': {
return '<h'
+ token.depth
+ '>'
+ inline.lexer(token.text)
+ '</h'
+ token.depth
+ '>\n';
}
case 'code': {
return '<pre><code'
+ (token.lang
? ' class="'
+ token.lang
+ '"'
: '')
+ '>'
+ (token.escaped
? token.text
: escape(token.text, true))
+ '</code></pre>\n';
}
case 'blockquote_start': {
var body = '';
while (next().type !== 'blockquote_end') {
body += tok();
}
return '<blockquote>\n'
+ body
+ '</blockquote>\n';
}
case 'list_start': {
var type = token.ordered ? 'ol' : 'ul'
, body = '';
while (next().type !== 'list_end') {
body += tok();
}
return '<'
+ type
+ '>\n'
+ body
+ '</'
+ type
+ '>\n';
}
case 'list_item_start': {
var body = '';
while (next().type !== 'list_item_end') {
body += token.type === 'text'
? parseText()
: tok();
}
return '<li>'
+ body
+ '</li>\n';
}
case 'loose_item_start': {
var body = '';
while (next().type !== 'list_item_end') {
body += tok();
}
return '<li>'
+ body
+ '</li>\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 '<p>'
+ inline.lexer(token.text)
+ '</p>\n';
}
case 'text': {
return '<p>'
+ parseText()
+ '</p>\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, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
};
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);

4
javascripts/libs/modernizr-2.0.6.min.js vendored Executable file

File diff suppressed because one or more lines are too long

278
javascripts/releasenotes.js Normal file
View File

@@ -0,0 +1,278 @@
/*
* Copyright, Cedric Dugas,
* Do not sell or redistribute
*/
(function($)
{
// mardown parser options, do not touch
marked.setOptions({
gfm: true,
pedantic: false,
sanitize: true
});
// Default setting
var defaultSettings = {
milestonesShown : 10,
// If you want to show private repo
// You need to add repo credentials in api.php
phpApi : false,
phpApiPath : '/',
showDescription : true,
showComments : true,
// Used if phpApi is set to false
repo : 'rails',
username : 'rails'
};
$.fn.releaseNotes = function(settings){
settings = $.extend({}, defaultSettings, settings || {});
var apiPath = settings.phpApiPath+"api.php";
var respType = (settings.phpApi) ? "json" : "jsonp";
var releases = {
load: function(el){
var _this = this;
this.$el = $(el);
this.loadEvents();
var options = $.extend(settings, {
state: "closed",
action: "milestones",
sort:"due_date"
});
this.callApi(options).success(function(resp){
if(resp.data) resp= resp.data;
_this.showMilestones(resp);
}).error(function(resp){
console.log(resp)
});
},
loadEvents : function(){
var _this = this;
if(settings.showDescription) this.$el.delegate(".issue", "click", function(){ _this.loadIssueDesc(this); return false;});
if(settings.showComments) this.$el.delegate(".btnComments", "click", function(){ _this.loadComments(this); return false;});
},
loadIssueDesc : function(el){
var $issue = $(el);
var data = $issue.data("issue");
$bigIssue = $issue.find(".issueBig");
if(!$bigIssue.is(":visible")){
$(".issueBig").not($bigIssue).slideUp();
$bigIssue.find(".container").html(components.bigIssue(data, settings.showComments));
$bigIssue.slideDown();
}else{
$bigIssue.slideUp();
}
},
showMilestones : function(milestones){
var _this = this;
milestones.sort(this.sortDate);
$.each(milestones, function(i, milestone){
if(i == settings.milestonesShown) return false;
milestone.prettyDate = (milestone.due_on) ? _this.getPrettyDate(milestone.due_on) : _this.getPrettyDate(milestone.created_at);
_this.$el.append(components.milestone(milestone));
var options = $.extend(settings, {
milestone: milestone.number,
sort:"created",
action:"issues",
state:"closed"
});
_this.callApi(options).success(function(resp, textStatus, jqXHR){
if(resp.data) resp= resp.data;
_this.showIssues(resp);
});
});
},
loadComments : function(el){
var _this =this;
var issueid =$(el).attr("data-issue-id");
$(el).fadeOut().slideUp();
var options = $.extend(settings, {
issueid:issueid,
action:"comments"
});
this.callApi(options).success(function(resp, textStatus, jqXHR){
if(resp.data) resp= resp.data;
_this.showComments(resp, issueid);
});
},
showComments : function(comments,issueid){
var _this = this;
var $commentContainer = _this.$el.find("#issue"+issueid).find(".comments").empty();
$.each(comments, function(i, comment){
comment.prettyDate = _this.getPrettyDate(comment.created_at);
$commentContainer.append(components.comment(comment, issueid));
});
$commentContainer.slideDown();
},
showIssues : function(issues){
var _this = this;
var jqMilestone = _this.$el.find("[data-id-milestone="+issues[0].milestone.number+"]");
var jqMilestoneIssues = jqMilestone.find(".issues");
issues.sort(this.sortLabel);
$.each(issues, function(i, issue){
issue.prettyDate = _this.getPrettyDate(issue.closed_at);
jqMilestoneIssues.append(components.issue(issue));
});
jqMilestone.addClass("separator");
if(settings.showDescription) jqMilestone.find(".issue").addClass("cursor");
},
getPrettyDate : function(date){
var dateFormat = "";
var date = date.split("T");
var dateArray = date[0].split("-");
var dateObj = new Date(dateArray[0],(dateArray[1]-1),dateArray[2]);
var weekday=new Array("Sunday","Monday","Tuesday","Wednesday","Thursday", "Friday","Saturday");
var monthname=new Array("January","February","March","April","May","June","July","August", "September","October","November","December");
dateFormat += weekday[dateObj.getDay()] + ", ";
dateFormat += monthname[dateObj.getMonth()] + " ";
dateFormat += dateObj.getDate() + ", ";
dateFormat += dateObj.getFullYear();
return dateFormat;
},
sortDate : function (milestone1, milestone2) {
milestone1.dateTest = (milestone1.due_on) ? milestone1.due_on : milestone1.created_at;
milestone2.dateTest = (milestone2.due_on) ? milestone2.due_on : milestone2.created_at;
var date1 = new Date(milestone1.dateTest );
var date2 = new Date(milestone2.dateTest );
if (date1 < date2) return 1;
if (date1 > 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 $('<div data-id-milestone="'+data.number+'" class="milestoneContainer"> \
<h3 class="release">'+data.title+'</h3>\
<p class="dateRelease">Release Date: '+data.prettyDate+'</p>\
<div class="issues"></div>\
</div>').data("milestone", data);
},
issue : function(data){
var labels = "",
_this = this;
$.each(data.labels, function(i, label){ labels += _this.label(label); });
return $('<div id="issue'+data.number+'" class="issue" >\
<div class="issueSmall">\
<div class="issueTitle">'+labels+' '+$("<span>").html(data.title).text()+' </div>\
</div>\
<div style="display:none;" class="issueBig">\
<div class="container"></div>\
<div style="display:none;" class="comments"></div>\
</div>').data("issue", data);
},
label : function(data){
return '<span style="background-color:#'+data.color+';" class="label">'+data.name+'</span>';
},
bigIssue : function(data, showComment){
var commentLink = (data.comments != 0 && showComment) ? '<a data-issue-id="'+data.number+'" href="#" class="btnComments btn">See Comments</a>' : "";
return $('<div class="avatar-bubble js-comment-container">\
<span class="avatar"><img height="48" src="'+data.user.avatar_url+'" width="48"></span>\
<div class="bubble">\
<div class="comment starting-comment adminable" id="issue-3542089">\
<div class="body">\
<p class="author">Opened by <a href="'+data.user.url+'">'+data.user.login+'</a>, issue closed on '+data.prettyDate+'</p>\
<h2 class="content-title"> '+$("<span>").html(data.title).text()+'</h2>\
<div class="formatted-content"> \
<div class="content-body markdown-body markdown-format">\
'+marked(data.body)+'\
</div>\
</div>\
</div>\
</div>\
</div>\
</div>'+commentLink).data("issue", data);
},
comment : function(data){
return '<div class="avatar-bubble js-comment-container">\
<span class="avatar"><img height="48" src="'+data.user.avatar_url+'" width="48"></span>\
<div class="bubble">\
<div id="issuecomment-4369977" class="comment normal-comment adminable">\
<div class="cmeta">\
<p class="author">\
<span class="icon"></span>\
<strong class="author"><a href="'+data.user.url+'">'+data.user.login+'</a></strong>\
<em class="action-text">\
commented\
</em>\
</p>\
<p class="info">\
<em class="date"><time class="js-relative-date">'+data.prettyDate+'</time></em>\
</p>\
</div>\
<div class="body">\
<div class="formatted-content">\
<div class="content-body markdown-body markdown-format">'+marked(data.body)+'</div>\
</div>\
</div>\
</div>\
</div>\
</div>';
}
}
})(jQuery);

20
javascripts/scale.fix.js Normal file
View File

@@ -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);
}
};

99
javascripts/script.js Normal file
View File

@@ -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("<pre class='lines'>" + lines.join("\n") + "</pre>");
});
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)

1
params.json Normal file

File diff suppressed because one or more lines are too long

46
release.html Executable file
View File

@@ -0,0 +1,46 @@
<!doctype html>
<!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en"> <![endif]-->
<!--[if IE 7]> <html class="no-js ie7 oldie" lang="en"> <![endif]-->
<!--[if IE 8]> <html class="no-js ie8 oldie" lang="en"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<title>Release Notes</title>
<link href="stylesheets/style.css" rel="stylesheet">
<link rel="stylesheet" href="stylesheets/releasenotes.plugin.css">
<script src="javascripts/libs/jquery-1.7.1.min.js"></script>
<script src="javascripts/libs/marked.js"></script>
<script src="javascripts/releasenotes.js"></script>
<script>
$(document).ready(function() {
$("#releaseNotesContainer").releaseNotes({
milestonesShown : 10,
// If you want to show private repo
// You need to add repo credentials in api.php
phpApi : false,
phpApiPath : '/',
showDescription : true,
showComments : true,
// Used if phpAPI is false
repo : 'canal',
username : 'alibaba'
});
});
</script>
</head>
<body>
<div id="websiteContainer">
<div class="containerRelease">
<h1>Release Notes</h1>
<div id="releaseNotesContainer" role="main"></div>
</div>
</div>
</body>
</html>

View File

@@ -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 }

View File

@@ -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;
}

30
stylesheets/style.css Executable file
View File

@@ -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;
}

413
stylesheets/styles.css Normal file
View File

@@ -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;
}
}

581
stylesheets/stylesheet.css Normal file
View File

@@ -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 */