").append(b.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,o||[e.responseText,t,e])}),this},b.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){b.fn[t]=function(e){return this.on(t,e)}}),b.each(["get","post"],function(e,n){b[n]=function(e,r,i,o){return b.isFunction(r)&&(o=o||i,i=r,r=t),b.ajax({url:e,type:n,dataType:o,data:r,success:i})}}),b.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:yn,type:"GET",isLocal:Nn.test(mn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Dn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":b.parseJSON,"text xml":b.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Mn(Mn(e,b.ajaxSettings),t):Mn(b.ajaxSettings,e)},ajaxPrefilter:Hn(An),ajaxTransport:Hn(jn),ajax:function(e,n){"object"==typeof e&&(n=e,e=t),n=n||{};var r,i,o,a,s,u,l,c,p=b.ajaxSetup({},n),f=p.context||p,d=p.context&&(f.nodeType||f.jquery)?b(f):b.event,h=b.Deferred(),g=b.Callbacks("once memory"),m=p.statusCode||{},y={},v={},x=0,T="canceled",N={readyState:0,getResponseHeader:function(e){var t;if(2===x){if(!c){c={};while(t=Tn.exec(a))c[t[1].toLowerCase()]=t[2]}t=c[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===x?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return x||(e=v[n]=v[n]||e,y[e]=t),this},overrideMimeType:function(e){return x||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>x)for(t in e)m[t]=[m[t],e[t]];else N.always(e[N.status]);return this},abort:function(e){var t=e||T;return l&&l.abort(t),k(0,t),this}};if(h.promise(N).complete=g.add,N.success=N.done,N.error=N.fail,p.url=((e||p.url||yn)+"").replace(xn,"").replace(kn,mn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=b.trim(p.dataType||"*").toLowerCase().match(w)||[""],null==p.crossDomain&&(r=En.exec(p.url.toLowerCase()),p.crossDomain=!(!r||r[1]===mn[1]&&r[2]===mn[2]&&(r[3]||("http:"===r[1]?80:443))==(mn[3]||("http:"===mn[1]?80:443)))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=b.param(p.data,p.traditional)),qn(An,p,n,N),2===x)return N;u=p.global,u&&0===b.active++&&b.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!Cn.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(bn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=wn.test(o)?o.replace(wn,"$1_="+vn++):o+(bn.test(o)?"&":"?")+"_="+vn++)),p.ifModified&&(b.lastModified[o]&&N.setRequestHeader("If-Modified-Since",b.lastModified[o]),b.etag[o]&&N.setRequestHeader("If-None-Match",b.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&N.setRequestHeader("Content-Type",p.contentType),N.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+Dn+"; q=0.01":""):p.accepts["*"]);for(i in p.headers)N.setRequestHeader(i,p.headers[i]);if(p.beforeSend&&(p.beforeSend.call(f,N,p)===!1||2===x))return N.abort();T="abort";for(i in{success:1,error:1,complete:1})N[i](p[i]);if(l=qn(jn,p,n,N)){N.readyState=1,u&&d.trigger("ajaxSend",[N,p]),p.async&&p.timeout>0&&(s=setTimeout(function(){N.abort("timeout")},p.timeout));try{x=1,l.send(y,k)}catch(C){if(!(2>x))throw C;k(-1,C)}}else k(-1,"No Transport");function k(e,n,r,i){var c,y,v,w,T,C=n;2!==x&&(x=2,s&&clearTimeout(s),l=t,a=i||"",N.readyState=e>0?4:0,r&&(w=_n(p,N,r)),e>=200&&300>e||304===e?(p.ifModified&&(T=N.getResponseHeader("Last-Modified"),T&&(b.lastModified[o]=T),T=N.getResponseHeader("etag"),T&&(b.etag[o]=T)),204===e?(c=!0,C="nocontent"):304===e?(c=!0,C="notmodified"):(c=Fn(p,w),C=c.state,y=c.data,v=c.error,c=!v)):(v=C,(e||!C)&&(C="error",0>e&&(e=0))),N.status=e,N.statusText=(n||C)+"",c?h.resolveWith(f,[y,C,N]):h.rejectWith(f,[N,C,v]),N.statusCode(m),m=t,u&&d.trigger(c?"ajaxSuccess":"ajaxError",[N,p,c?y:v]),g.fireWith(f,[N,C]),u&&(d.trigger("ajaxComplete",[N,p]),--b.active||b.event.trigger("ajaxStop")))}return N},getScript:function(e,n){return b.get(e,t,n,"script")},getJSON:function(e,t,n){return b.get(e,t,n,"json")}});function _n(e,n,r){var i,o,a,s,u=e.contents,l=e.dataTypes,c=e.responseFields;for(s in c)s in r&&(n[c[s]]=r[s]);while("*"===l[0])l.shift(),o===t&&(o=e.mimeType||n.getResponseHeader("Content-Type"));if(o)for(s in u)if(u[s]&&u[s].test(o)){l.unshift(s);break}if(l[0]in r)a=l[0];else{for(s in r){if(!l[0]||e.converters[s+" "+l[0]]){a=s;break}i||(i=s)}a=a||i}return a?(a!==l[0]&&l.unshift(a),r[a]):t}function Fn(e,t){var n,r,i,o,a={},s=0,u=e.dataTypes.slice(),l=u[0];if(e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u[1])for(i in e.converters)a[i.toLowerCase()]=e.converters[i];for(;r=u[++s];)if("*"!==r){if("*"!==l&&l!==r){if(i=a[l+" "+r]||a["* "+r],!i)for(n in a)if(o=n.split(" "),o[1]===r&&(i=a[l+" "+o[0]]||a["* "+o[0]])){i===!0?i=a[n]:a[n]!==!0&&(r=o[0],u.splice(s--,0,r));break}if(i!==!0)if(i&&e["throws"])t=i(t);else try{t=i(t)}catch(c){return{state:"parsererror",error:i?c:"No conversion from "+l+" to "+r}}}l=r}return{state:"success",data:t}}b.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return b.globalEval(e),e}}}),b.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),b.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=o.head||b("head")[0]||o.documentElement;return{send:function(t,i){n=o.createElement("script"),n.async=!0,e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var On=[],Bn=/(=)\?(?=&|$)|\?\?/;b.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=On.pop()||b.expando+"_"+vn++;return this[e]=!0,e}}),b.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,u=n.jsonp!==!1&&(Bn.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Bn.test(n.data)&&"data");return u||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=b.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,u?n[u]=n[u].replace(Bn,"$1"+o):n.jsonp!==!1&&(n.url+=(bn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||b.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,On.push(o)),s&&b.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Pn,Rn,Wn=0,$n=e.ActiveXObject&&function(){var e;for(e in Pn)Pn[e](t,!0)};function In(){try{return new e.XMLHttpRequest}catch(t){}}function zn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}b.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&In()||zn()}:In,Rn=b.ajaxSettings.xhr(),b.support.cors=!!Rn&&"withCredentials"in Rn,Rn=b.support.ajax=!!Rn,Rn&&b.ajaxTransport(function(n){if(!n.crossDomain||b.support.cors){var r;return{send:function(i,o){var a,s,u=n.xhr();if(n.username?u.open(n.type,n.url,n.async,n.username,n.password):u.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)u[s]=n.xhrFields[s];n.mimeType&&u.overrideMimeType&&u.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)u.setRequestHeader(s,i[s])}catch(l){}u.send(n.hasContent&&n.data||null),r=function(e,i){var s,l,c,p;try{if(r&&(i||4===u.readyState))if(r=t,a&&(u.onreadystatechange=b.noop,$n&&delete Pn[a]),i)4!==u.readyState&&u.abort();else{p={},s=u.status,l=u.getAllResponseHeaders(),"string"==typeof u.responseText&&(p.text=u.responseText);try{c=u.statusText}catch(f){c=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=p.text?200:404}}catch(d){i||o(-1,d)}p&&o(s,c,p,l)},n.async?4===u.readyState?setTimeout(r):(a=++Wn,$n&&(Pn||(Pn={},b(e).unload($n)),Pn[a]=r),u.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Xn,Un,Vn=/^(?:toggle|show|hide)$/,Yn=RegExp("^(?:([+-])=|)("+x+")([a-z%]*)$","i"),Jn=/queueHooks$/,Gn=[nr],Qn={"*":[function(e,t){var n,r,i=this.createTween(e,t),o=Yn.exec(t),a=i.cur(),s=+a||0,u=1,l=20;if(o){if(n=+o[2],r=o[3]||(b.cssNumber[e]?"":"px"),"px"!==r&&s){s=b.css(i.elem,e,!0)||n||1;do u=u||".5",s/=u,b.style(i.elem,e,s+r);while(u!==(u=i.cur()/a)&&1!==u&&--l)}i.unit=r,i.start=s,i.end=o[1]?s+(o[1]+1)*n:n}return i}]};function Kn(){return setTimeout(function(){Xn=t}),Xn=b.now()}function Zn(e,t){b.each(t,function(t,n){var r=(Qn[t]||[]).concat(Qn["*"]),i=0,o=r.length;for(;o>i;i++)if(r[i].call(e,t,n))return})}function er(e,t,n){var r,i,o=0,a=Gn.length,s=b.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;var t=Xn||Kn(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,a=0,u=l.tweens.length;for(;u>a;a++)l.tweens[a].run(o);return s.notifyWith(e,[l,o,n]),1>o&&u?n:(s.resolveWith(e,[l]),!1)},l=s.promise({elem:e,props:b.extend({},t),opts:b.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Xn||Kn(),duration:n.duration,tweens:[],createTween:function(t,n){var r=b.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)l.tweens[n].run(1);return t?s.resolveWith(e,[l,t]):s.rejectWith(e,[l,t]),this}}),c=l.props;for(tr(c,l.opts.specialEasing);a>o;o++)if(r=Gn[o].call(l,e,c,l.opts))return r;return Zn(l,c),b.isFunction(l.opts.start)&&l.opts.start.call(e,l),b.fx.timer(b.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function tr(e,t){var n,r,i,o,a;for(i in e)if(r=b.camelCase(i),o=t[r],n=e[i],b.isArray(n)&&(o=n[1],n=e[i]=n[0]),i!==r&&(e[r]=n,delete e[i]),a=b.cssHooks[r],a&&"expand"in a){n=a.expand(n),delete e[r];for(i in n)i in e||(e[i]=n[i],t[i]=o)}else t[r]=o}b.Animation=b.extend(er,{tweener:function(e,t){b.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Qn[n]=Qn[n]||[],Qn[n].unshift(t)},prefilter:function(e,t){t?Gn.unshift(e):Gn.push(e)}});function nr(e,t,n){var r,i,o,a,s,u,l,c,p,f=this,d=e.style,h={},g=[],m=e.nodeType&&nn(e);n.queue||(c=b._queueHooks(e,"fx"),null==c.unqueued&&(c.unqueued=0,p=c.empty.fire,c.empty.fire=function(){c.unqueued||p()}),c.unqueued++,f.always(function(){f.always(function(){c.unqueued--,b.queue(e,"fx").length||c.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[d.overflow,d.overflowX,d.overflowY],"inline"===b.css(e,"display")&&"none"===b.css(e,"float")&&(b.support.inlineBlockNeedsLayout&&"inline"!==un(e.nodeName)?d.zoom=1:d.display="inline-block")),n.overflow&&(d.overflow="hidden",b.support.shrinkWrapBlocks||f.always(function(){d.overflow=n.overflow[0],d.overflowX=n.overflow[1],d.overflowY=n.overflow[2]}));for(i in t)if(a=t[i],Vn.exec(a)){if(delete t[i],u=u||"toggle"===a,a===(m?"hide":"show"))continue;g.push(i)}if(o=g.length){s=b._data(e,"fxshow")||b._data(e,"fxshow",{}),"hidden"in s&&(m=s.hidden),u&&(s.hidden=!m),m?b(e).show():f.done(function(){b(e).hide()}),f.done(function(){var t;b._removeData(e,"fxshow");for(t in h)b.style(e,t,h[t])});for(i=0;o>i;i++)r=g[i],l=f.createTween(r,m?s[r]:0),h[r]=s[r]||b.style(e,r),r in s||(s[r]=l.start,m&&(l.end=l.start,l.start="width"===r||"height"===r?1:0))}}function rr(e,t,n,r,i){return new rr.prototype.init(e,t,n,r,i)}b.Tween=rr,rr.prototype={constructor:rr,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(b.cssNumber[n]?"":"px")},cur:function(){var e=rr.propHooks[this.prop];return e&&e.get?e.get(this):rr.propHooks._default.get(this)},run:function(e){var t,n=rr.propHooks[this.prop];return this.pos=t=this.options.duration?b.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rr.propHooks._default.set(this),this}},rr.prototype.init.prototype=rr.prototype,rr.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=b.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){b.fx.step[e.prop]?b.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[b.cssProps[e.prop]]||b.cssHooks[e.prop])?b.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},rr.propHooks.scrollTop=rr.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},b.each(["toggle","show","hide"],function(e,t){var n=b.fn[t];b.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ir(t,!0),e,r,i)}}),b.fn.extend({fadeTo:function(e,t,n,r){return this.filter(nn).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=b.isEmptyObject(e),o=b.speed(t,n,r),a=function(){var t=er(this,b.extend({},e),o);a.finish=function(){t.stop(!0)},(i||b._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=b.timers,a=b._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&Jn.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&b.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=b._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=b.timers,a=r?r.length:0;for(n.finish=!0,b.queue(this,e,[]),i&&i.cur&&i.cur.finish&&i.cur.finish.call(this),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function ir(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=Zt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}b.each({slideDown:ir("show"),slideUp:ir("hide"),slideToggle:ir("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){b.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),b.speed=function(e,t,n){var r=e&&"object"==typeof e?b.extend({},e):{complete:n||!n&&t||b.isFunction(e)&&e,duration:e,easing:n&&t||t&&!b.isFunction(t)&&t};return r.duration=b.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in b.fx.speeds?b.fx.speeds[r.duration]:b.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){b.isFunction(r.old)&&r.old.call(this),r.queue&&b.dequeue(this,r.queue)},r},b.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},b.timers=[],b.fx=rr.prototype.init,b.fx.tick=function(){var e,n=b.timers,r=0;for(Xn=b.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||b.fx.stop(),Xn=t},b.fx.timer=function(e){e()&&b.timers.push(e)&&b.fx.start()},b.fx.interval=13,b.fx.start=function(){Un||(Un=setInterval(b.fx.tick,b.fx.interval))},b.fx.stop=function(){clearInterval(Un),Un=null},b.fx.speeds={slow:600,fast:200,_default:400},b.fx.step={},b.expr&&b.expr.filters&&(b.expr.filters.animated=function(e){return b.grep(b.timers,function(t){return e===t.elem}).length}),b.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){b.offset.setOffset(this,e,t)});var n,r,o={top:0,left:0},a=this[0],s=a&&a.ownerDocument;if(s)return n=s.documentElement,b.contains(n,a)?(typeof a.getBoundingClientRect!==i&&(o=a.getBoundingClientRect()),r=or(s),{top:o.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:o.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):o},b.offset={setOffset:function(e,t,n){var r=b.css(e,"position");"static"===r&&(e.style.position="relative");var i=b(e),o=i.offset(),a=b.css(e,"top"),s=b.css(e,"left"),u=("absolute"===r||"fixed"===r)&&b.inArray("auto",[a,s])>-1,l={},c={},p,f;u?(c=i.position(),p=c.top,f=c.left):(p=parseFloat(a)||0,f=parseFloat(s)||0),b.isFunction(t)&&(t=t.call(e,n,o)),null!=t.top&&(l.top=t.top-o.top+p),null!=t.left&&(l.left=t.left-o.left+f),"using"in t?t.using.call(e,l):i.css(l)}},b.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===b.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),b.nodeName(e[0],"html")||(n=e.offset()),n.top+=b.css(e[0],"borderTopWidth",!0),n.left+=b.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-b.css(r,"marginTop",!0),left:t.left-n.left-b.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||o.documentElement;while(e&&!b.nodeName(e,"html")&&"static"===b.css(e,"position"))e=e.offsetParent;return e||o.documentElement})}}),b.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);b.fn[e]=function(i){return b.access(this,function(e,i,o){var a=or(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?b(a).scrollLeft():o,r?o:b(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}});function or(e){return b.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}b.each({Height:"height",Width:"width"},function(e,n){b.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){b.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return b.access(this,function(n,r,i){var o;return b.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?b.css(n,r,s):b.style(n,r,i,s)},n,a?i:t,a,null)}})}),e.jQuery=e.$=b,"function"==typeof define&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return b})})(window);
diff --git a/.themes/classic/source/javascripts/libs/swfobject-dynamic.js b/.themes/classic/source/javascripts/libs/swfobject-dynamic.js
new file mode 100644
index 0000000..b021614
--- /dev/null
+++ b/.themes/classic/source/javascripts/libs/swfobject-dynamic.js
@@ -0,0 +1,298 @@
+/*! SWFObject v2.2
+ is released under the MIT License
+*/
+
+var swfobject = function() {
+
+ var UNDEF = "undefined",
+ OBJECT = "object",
+ SHOCKWAVE_FLASH = "Shockwave Flash",
+ SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash",
+ FLASH_MIME_TYPE = "application/x-shockwave-flash",
+ EXPRESS_INSTALL_ID = "SWFObjectExprInst",
+
+ win = window,
+ doc = document,
+ nav = navigator,
+
+ plugin = false,
+ regObjArr = [],
+ objIdArr = [],
+ storedAltContent,
+ storedAltContentId,
+ storedCallbackFn,
+ storedCallbackObj,
+ autoHideShow = true,
+
+ /* Centralized function for browser feature detection
+ - User agent string detection is only used when no good alternative is possible
+ - Is executed directly for optimal performance
+ */
+ ua = function() {
+ var w3cdom = typeof doc.getElementById != UNDEF && typeof doc.getElementsByTagName != UNDEF && typeof doc.createElement != UNDEF,
+ u = nav.userAgent.toLowerCase(),
+ p = nav.platform.toLowerCase(),
+ windows = p ? /win/.test(p) : /win/.test(u),
+ mac = p ? /mac/.test(p) : /mac/.test(u),
+ webkit = /webkit/.test(u) ? parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : false, // returns either the webkit version or false if not webkit
+ ie = !+"\v1", // feature detection based on Andrea Giammarchi's solution: http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html
+ playerVersion = [0,0,0],
+ d = null;
+ if (typeof nav.plugins != UNDEF && typeof nav.plugins[SHOCKWAVE_FLASH] == OBJECT) {
+ d = nav.plugins[SHOCKWAVE_FLASH].description;
+ if (d && !(typeof nav.mimeTypes != UNDEF && nav.mimeTypes[FLASH_MIME_TYPE] && !nav.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) { // navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin indicates whether plug-ins are enabled or disabled in Safari 3+
+ plugin = true;
+ ie = false; // cascaded feature detection for Internet Explorer
+ d = d.replace(/^.*\s+(\S+\s+\S+$)/, "$1");
+ playerVersion[0] = parseInt(d.replace(/^(.*)\..*$/, "$1"), 10);
+ playerVersion[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, "$1"), 10);
+ playerVersion[2] = /[a-zA-Z]/.test(d) ? parseInt(d.replace(/^.*[a-zA-Z]+(.*)$/, "$1"), 10) : 0;
+ }
+ }
+ else if (typeof win.ActiveXObject != UNDEF) {
+ try {
+ var a = new ActiveXObject(SHOCKWAVE_FLASH_AX);
+ if (a) { // a will return null when ActiveX is disabled
+ d = a.GetVariable("$version");
+ if (d) {
+ ie = true; // cascaded feature detection for Internet Explorer
+ d = d.split(" ")[1].split(",");
+ playerVersion = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
+ }
+ }
+ }
+ catch(e) {}
+ }
+ return { w3:w3cdom, pv:playerVersion, wk:webkit, ie:ie, win:windows, mac:mac };
+ }()
+
+
+ /* Main function
+ - Will preferably execute onDomLoad, otherwise onload (as a fallback)
+ */
+ function main() {
+ if (plugin) { testPlayerVersion(); }
+ else { matchVersions(); }
+ }
+
+ /* Detect the Flash Player version for non-Internet Explorer browsers
+ - Detecting the plug-in version via the object element is more precise than using the plugins collection item's description:
+ a. Both release and build numbers can be detected
+ b. Avoid wrong descriptions by corrupt installers provided by Adobe
+ c. Avoid wrong descriptions by multiple Flash Player entries in the plugin Array, caused by incorrect browser imports
+ - Disadvantage of this method is that it depends on the availability of the DOM, while the plugins collection is immediately available
+ */
+ function testPlayerVersion() {
+ var b = doc.getElementsByTagName("body")[0];
+ var o = createElement(OBJECT);
+ o.setAttribute("type", FLASH_MIME_TYPE);
+ var t = b.appendChild(o);
+ if (t) {
+ var counter = 0;
+ (function(){
+ if (typeof t.GetVariable != UNDEF) {
+ var d = t.GetVariable("$version");
+ if (d) {
+ d = d.split(" ")[1].split(",");
+ ua.pv = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
+ }
+ }
+ else if (counter < 10) {
+ counter++;
+ setTimeout(arguments.callee, 10);
+ return;
+ }
+ b.removeChild(o);
+ t = null;
+ matchVersions();
+ })();
+ }
+ else {
+ matchVersions();
+ }
+ }
+
+
+ /* Cross-browser dynamic SWF creation
+ */
+ function createSWF(attObj, parObj, id) {
+ var r, el = getElementById(id);
+ if (ua.wk && ua.wk < 312) { return r; }
+ if (el) {
+ if (typeof attObj.id == UNDEF) { // if no 'id' is defined for the object element, it will inherit the 'id' from the alternative content
+ attObj.id = id;
+ }
+ if (ua.ie && ua.win) { // Internet Explorer + the HTML object element + W3C DOM methods do not combine: fall back to outerHTML
+ var att = "";
+ for (var i in attObj) {
+ if (attObj[i] != Object.prototype[i]) { // filter out prototype additions from other potential libraries
+ if (i.toLowerCase() == "data") {
+ parObj.movie = attObj[i];
+ }
+ else if (i.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
+ att += ' class="' + attObj[i] + '"';
+ }
+ else if (i.toLowerCase() != "classid") {
+ att += ' ' + i + '="' + attObj[i] + '"';
+ }
+ }
+ }
+ var par = "";
+ for (var j in parObj) {
+ if (parObj[j] != Object.prototype[j]) { // filter out prototype additions from other potential libraries
+ par += ' ';
+ }
+ }
+ el.outerHTML = '' + par + ' ';
+ objIdArr[objIdArr.length] = attObj.id; // stored to fix object 'leaks' on unload (dynamic publishing only)
+ r = getElementById(attObj.id);
+ }
+ else { // well-behaving browsers
+ var o = createElement(OBJECT);
+ o.setAttribute("type", FLASH_MIME_TYPE);
+ for (var m in attObj) {
+ if (attObj[m] != Object.prototype[m]) { // filter out prototype additions from other potential libraries
+ if (m.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
+ o.setAttribute("class", attObj[m]);
+ }
+ else if (m.toLowerCase() != "classid") { // filter out IE specific attribute
+ o.setAttribute(m, attObj[m]);
+ }
+ }
+ }
+ for (var n in parObj) {
+ if (parObj[n] != Object.prototype[n] && n.toLowerCase() != "movie") { // filter out prototype additions from other potential libraries and IE specific param element
+ createObjParam(o, n, parObj[n]);
+ }
+ }
+ el.parentNode.replaceChild(o, el);
+ r = o;
+ }
+ }
+ return r;
+ }
+
+ function createObjParam(el, pName, pValue) {
+ var p = createElement("param");
+ p.setAttribute("name", pName);
+ p.setAttribute("value", pValue);
+ el.appendChild(p);
+ }
+
+ /* Cross-browser SWF removal
+ - Especially needed to safely and completely remove a SWF in Internet Explorer
+ */
+ /* Functions to optimize JavaScript compression
+ */
+ function getElementById(id) {
+ var el = null;
+ try {
+ el = doc.getElementById(id);
+ }
+ catch (e) {}
+ return el;
+ }
+
+ function createElement(el) {
+ return doc.createElement(el);
+ }
+
+ /* Flash Player and SWF content version matching
+ */
+ function hasPlayerVersion(rv) {
+ var pv = ua.pv, v = rv.split(".");
+ v[0] = parseInt(v[0], 10);
+ v[1] = parseInt(v[1], 10) || 0; // supports short notation, e.g. "9" instead of "9.0.0"
+ v[2] = parseInt(v[2], 10) || 0;
+ return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false;
+ }
+
+
+ /* Filter to avoid XSS attacks
+ */
+ function urlEncodeIfNecessary(s) {
+ var regex = /[\\\"<>\.;]/;
+ var hasBadChars = regex.exec(s) != null;
+ return hasBadChars && typeof encodeURIComponent != UNDEF ? encodeURIComponent(s) : s;
+ }
+
+ return {
+ /* Public API
+ - Reference: http://code.google.com/p/swfobject/wiki/documentation
+ */
+
+ embedSWF: function(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, flashvarsObj, parObj, attObj, callbackFn) {
+ var callbackObj = {success:false, id:replaceElemIdStr};
+ if (ua.w3 && !(ua.wk && ua.wk < 312) && swfUrlStr && replaceElemIdStr && widthStr && heightStr && swfVersionStr) {
+ widthStr += ""; // auto-convert to string
+ heightStr += "";
+ var att = {};
+ if (attObj && typeof attObj === OBJECT) {
+ for (var i in attObj) { // copy object to avoid the use of references, because web authors often reuse attObj for multiple SWFs
+ att[i] = attObj[i];
+ }
+ }
+ att.data = swfUrlStr;
+ att.width = widthStr;
+ att.height = heightStr;
+ var par = {};
+ if (parObj && typeof parObj === OBJECT) {
+ for (var j in parObj) { // copy object to avoid the use of references, because web authors often reuse parObj for multiple SWFs
+ par[j] = parObj[j];
+ }
+ }
+ if (flashvarsObj && typeof flashvarsObj === OBJECT) {
+ for (var k in flashvarsObj) { // copy object to avoid the use of references, because web authors often reuse flashvarsObj for multiple SWFs
+ if (typeof par.flashvars != UNDEF) {
+ par.flashvars += "&" + k + "=" + flashvarsObj[k];
+ }
+ else {
+ par.flashvars = k + "=" + flashvarsObj[k];
+ }
+ }
+ }
+ if (hasPlayerVersion(swfVersionStr)) { // create SWF
+ var obj = createSWF(att, par, replaceElemIdStr);
+ callbackObj.success = true;
+ callbackObj.ref = obj;
+ }
+ if (callbackFn) { callbackFn(callbackObj); }
+ }
+ else if (callbackFn) { callbackFn(callbackObj); }
+ },
+
+ ua: ua,
+
+ getFlashPlayerVersion: function() {
+ return { major:ua.pv[0], minor:ua.pv[1], release:ua.pv[2] };
+ },
+
+ hasFlashPlayerVersion: hasPlayerVersion,
+
+ createSWF: function(attObj, parObj, replaceElemIdStr) {
+ if (ua.w3) {
+ return createSWF(attObj, parObj, replaceElemIdStr);
+ }
+ else {
+ return undefined;
+ }
+ },
+
+ getQueryParamValue: function(param) {
+ var q = doc.location.search || doc.location.hash;
+ if (q) {
+ if (/\?/.test(q)) { q = q.split("?")[1]; } // strip question mark
+ if (param == null) {
+ return urlEncodeIfNecessary(q);
+ }
+ var pairs = q.split("&");
+ for (var i = 0; i < pairs.length; i++) {
+ if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) {
+ return urlEncodeIfNecessary(pairs[i].substring((pairs[i].indexOf("=") + 1)));
+ }
+ }
+ }
+ return "";
+ }
+ };
+}();
diff --git a/.themes/classic/source/javascripts/modernizr-2.0.js b/.themes/classic/source/javascripts/modernizr-2.0.js
new file mode 100644
index 0000000..9dca7b0
--- /dev/null
+++ b/.themes/classic/source/javascripts/modernizr-2.0.js
@@ -0,0 +1,5 @@
+/* Modernizr 2.6.2 (Custom Build) | MIT & BSD
+ * Build: http://modernizr.com/download/#-video-mq-cssclasses-teststyles-testprop-testallprops-prefixes-domprefixes-load
+ */
+;window.Modernizr=function(a,b,c){function A(a){j.cssText=a}function B(a,b){return A(m.join(a+";")+(b||""))}function C(a,b){return typeof a===b}function D(a,b){return!!~(""+a).indexOf(b)}function E(a,b){for(var d in a){var e=a[d];if(!D(e,"-")&&j[e]!==c)return b=="pfx"?e:!0}return!1}function F(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:C(f,"function")?f.bind(d||b):f}return!1}function G(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+o.join(d+" ")+d).split(" ");return C(b,"string")||C(b,"undefined")?E(e,b):(e=(a+" "+p.join(d+" ")+d).split(" "),F(e,b,c))}var d="2.6.2",e={},f=!0,g=b.documentElement,h="modernizr",i=b.createElement(h),j=i.style,k,l={}.toString,m=" -webkit- -moz- -o- -ms- ".split(" "),n="Webkit Moz O ms",o=n.split(" "),p=n.toLowerCase().split(" "),q={},r={},s={},t=[],u=t.slice,v,w=function(a,c,d,e){var f,i,j,k,l=b.createElement("div"),m=b.body,n=m||b.createElement("body");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:h+(d+1),l.appendChild(j);return f=["",'"].join(""),l.id=h,(m?l:n).innerHTML+=f,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=g.style.overflow,g.style.overflow="hidden",g.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),g.style.overflow=k),!!i},x=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b).matches;var d;return w("@media "+b+" { #"+h+" { position: absolute; } }",function(b){d=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle)["position"]=="absolute"}),d},y={}.hasOwnProperty,z;!C(y,"undefined")&&!C(y.call,"undefined")?z=function(a,b){return y.call(a,b)}:z=function(a,b){return b in a&&C(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=u.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(u.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(u.call(arguments)))};return e}),q.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),c.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,"")}catch(d){}return c};for(var H in q)z(q,H)&&(v=H.toLowerCase(),e[v]=q[H](),t.push((e[v]?"":"no-")+v));return e.addTest=function(a,b){if(typeof a=="object")for(var d in a)z(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof f!="undefined"&&f&&(g.className+=" "+(b?"":"no-")+a),e[a]=b}return e},A(""),i=k=null,e._version=d,e._prefixes=m,e._domPrefixes=p,e._cssomPrefixes=o,e.mq=x,e.testProp=function(a){return E([a])},e.testAllProps=G,e.testStyles=w,g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+t.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},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=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f')
+ var mobileNav = $('fieldset.mobile-nav').append('');
+ mobileNav.find('select').append('Navigate… ');
+ var addOption = function(i, option) {
+ mobileNav.find('select').append('» ' + $(this).text() + ' ');
+ }
+ mainNav.find('a').each(addOption);
+ $('ul.subscription a').each(addOption);
+ mobileNav.find('select').bind('change', function(event) {
+ if (event.target.value) { window.location.href = event.target.value; }
+ });
+}
+
+function addSidebarToggler() {
+ if(!$('body').hasClass('sidebar-footer')) {
+ $('#content').append('');
+ $('.toggle-sidebar').bind('click', function(e) {
+ e.preventDefault();
+ $('body').toggleClass('collapse-sidebar');
+ });
+ }
+ var sections = $('aside.sidebar > section');
+ if (sections.length > 1) {
+ sections.each(function(index, section){
+ if ((sections.length >= 3) && index % 3 === 0) {
+ $(section).addClass("first");
+ }
+ var count = ((index +1) % 2) ? "odd" : "even";
+ $(section).addClass(count);
+ });
+ }
+ if (sections.length >= 3){ $('aside.sidebar').addClass('thirds'); }
+}
+
+function testFeatures() {
+ var features = ['maskImage'];
+ $(features).map(function(i, feature) {
+ if (Modernizr.testAllProps(feature)) {
+ $('html').addClass(feature);
+ } else {
+ $('html').addClass('no-'+feature);
+ }
+ });
+ if ("placeholder" in document.createElement("input")) {
+ $('html').addClass('placeholder');
+ } else {
+ $('html').addClass('no-placeholder');
+ }
+}
+
+function addCodeLineNumbers() {
+ if (navigator.appName === 'Microsoft Internet Explorer') { return; }
+ $('div.gist-highlight').each(function(code) {
+ var tableStart = '',
+ lineNumbers = '',
+ tableMiddle = ' ',
+ tableEnd = '
',
+ count = $('.line', code).length;
+ for (var i=1;i<=count; i++) {
+ lineNumbers += ''+i+' \n';
+ }
+ var table = tableStart + lineNumbers + tableMiddle + ''+$('pre', code).html()+' ' + tableEnd;
+ $(code).html(table);
+ });
+}
+
+function flashVideoFallback(){
+ var flashplayerlocation = "/assets/jwplayer/player.swf",
+ flashplayerskin = "/assets/jwplayer/glow/glow.xml";
+ $('video').each(function(i, video){
+ video = $(video);
+ if (!Modernizr.video.h264 && swfobject.getFlashPlayerVersion() || window.location.hash.indexOf("flash-test") !== -1){
+ video.children('source[src$=mp4]').first().map(i, function(source){
+ var src = $(source).attr('src'),
+ id = 'video_'+Math.round(1 + Math.random()*(100000)),
+ width = video.attr('width'),
+ height = parseInt(video.attr('height'), 10) + 30;
+ video.after('');
+ swfobject.embedSWF(flashplayerlocation, id, width, height + 30, "9.0.0",
+ { file : src, image : video.attr('poster'), skin : flashplayerskin } ,
+ { movie : src, wmode : "opaque", allowfullscreen : "true" }
+ );
+ });
+ video.remove();
+ }
+ });
+}
+
+function wrapFlashVideos() {
+ $('object').each(function(i, object) {
+ if( $(object).find('param[name=movie]').length ){
+ $(object).wrap('
')
+ }
+ });
+ $('iframe[src*=vimeo],iframe[src*=youtube]').wrap('
')
+}
+
+function renderDeliciousLinks(items) {
+ var output = "
";
+ $('#delicious').html(output);
+}
+
+$('document').ready(function() {
+ testFeatures();
+ wrapFlashVideos();
+ flashVideoFallback();
+ addCodeLineNumbers();
+ getNav();
+ addSidebarToggler();
+});
+
+// iOS scaling bug fix
+// Rewritten version
+// By @mathias, @cheeaun and @jdalton
+// Source url: https://gist.github.com/901295
+(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 = [0.25, 1.6];
+ doc[addEvent](type, fix, true);
+ }
+}(document));
+
+/*! SWFObject v2.2 modified by Brandon Mathis to contain only what is necessary to dynamically embed flash objects
+ * Uncompressed source in javascripts/libs/swfobject-dynamic.js
+ *
+ released under the MIT License
+*/
+var swfobject=function(){function s(a,b,d){var q,k=n(d);if(g.wk&&g.wk<312)return q;if(k){if(typeof a.id==l)a.id=d;if(g.ie&&g.win){var e="",c;for(c in a)if(a[c]!=Object.prototype[c])c.toLowerCase()=="data"?b.movie=a[c]:c.toLowerCase()=="styleclass"?e+=' class="'+a[c]+'"':c.toLowerCase()!="classid"&&(e+=" "+c+'="'+a[c]+'"');c="";for(var f in b)b[f]!=Object.prototype[f]&&(c+=' ');k.outerHTML='"+c+
+" ";q=n(a.id)}else{f=i.createElement(o);f.setAttribute("type",m);for(var h in a)a[h]!=Object.prototype[h]&&(h.toLowerCase()=="styleclass"?f.setAttribute("class",a[h]):h.toLowerCase()!="classid"&&f.setAttribute(h,a[h]));for(e in b)b[e]!=Object.prototype[e]&&e.toLowerCase()!="movie"&&(a=f,c=e,h=b[e],d=i.createElement("param"),d.setAttribute("name",c),d.setAttribute("value",h),a.appendChild(d));k.parentNode.replaceChild(f,k);q=f}}return q}function n(a){var b=null;try{b=i.getElementById(a)}catch(d){}return b}
+function t(a){var b=g.pv,a=a.split(".");a[0]=parseInt(a[0],10);a[1]=parseInt(a[1],10)||0;a[2]=parseInt(a[2],10)||0;return b[0]>a[0]||b[0]==a[0]&&b[1]>a[1]||b[0]==a[0]&&b[1]==a[1]&&b[2]>=a[2]?!0:!1}function u(a){return/[\\\"<>\.;]/.exec(a)!=null&&typeof encodeURIComponent!=l?encodeURIComponent(a):a}var l="undefined",o="object",m="application/x-shockwave-flash",v=window,i=document,j=navigator,g=function(){var a=typeof i.getElementById!=l&&typeof i.getElementsByTagName!=l&&typeof i.createElement!=l,
+b=j.userAgent.toLowerCase(),d=j.platform.toLowerCase(),g=d?/win/.test(d):/win/.test(b),d=d?/mac/.test(d):/mac/.test(b),b=/webkit/.test(b)?parseFloat(b.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):!1,k=!+"\u000b1",e=[0,0,0],c=null;if(typeof j.plugins!=l&&typeof j.plugins["Shockwave Flash"]==o){if((c=j.plugins["Shockwave Flash"].description)&&!(typeof j.mimeTypes!=l&&j.mimeTypes[m]&&!j.mimeTypes[m].enabledPlugin))k=!1,c=c.replace(/^.*\s+(\S+\s+\S+$)/,"$1"),e[0]=parseInt(c.replace(/^(.*)\..*$/,"$1"),
+10),e[1]=parseInt(c.replace(/^.*\.(.*)\s.*$/,"$1"),10),e[2]=/[a-zA-Z]/.test(c)?parseInt(c.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}else if(typeof v.ActiveXObject!=l)try{var f=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");if(f&&(c=f.GetVariable("$version")))k=!0,c=c.split(" ")[1].split(","),e=[parseInt(c[0],10),parseInt(c[1],10),parseInt(c[2],10)]}catch(h){}return{w3:a,pv:e,wk:b,ie:k,win:g,mac:d}}();return{embedSWF:function(a,b,d,i,k,e,c,f,h){var j={success:!1,id:b};if(g.w3&&!(g.wk&&g.wk<312)&&
+a&&b&&d&&i&&k){d+="";i+="";var p={};if(f&&typeof f===o)for(var m in f)p[m]=f[m];p.data=a;p.width=d;p.height=i;a={};if(c&&typeof c===o)for(var n in c)a[n]=c[n];if(e&&typeof e===o)for(var r in e)typeof a.flashvars!=l?a.flashvars+="&"+r+"="+e[r]:a.flashvars=r+"="+e[r];if(t(k))b=s(p,a,b),j.success=!0,j.ref=b}h&&h(j)},ua:g,getFlashPlayerVersion:function(){return{major:g.pv[0],minor:g.pv[1],release:g.pv[2]}},hasFlashPlayerVersion:t,createSWF:function(a,b,d){if(g.w3)return s(a,b,d)},getQueryParamValue:function(a){var b=
+i.location.search||i.location.hash;if(b){/\?/.test(b)&&(b=b.split("?")[1]);if(a==null)return u(b);for(var b=b.split("&"),d=0;d');
+ (function(){
+ var pinboardLinkroll = document.createElement('script');
+ pinboardLinkroll.type = 'text/javascript';
+ pinboardLinkroll.async = true;
+ pinboardLinkroll.src = url;
+ document.getElementsByTagName('head')[0].appendChild(pinboardLinkroll);
+ })();
+}
+
+function pinboardNS_show_bmarks(r) {
+ var lr = new Pinboard_Linkroll();
+ lr.set_items(r);
+ lr.show_bmarks();
+}
+
+function Pinboard_Linkroll() {
+ var items;
+
+ this.set_items = function(i) {
+ this.items = i;
+ }
+ this.show_bmarks = function() {
+ var lines = [];
+ for (var i = 0; i < this.items.length; i++) {
+ var item = this.items[i];
+ var str = this.format_item(item);
+ lines.push(str);
+ }
+ document.getElementById(linkroll).innerHTML = lines.join("\n");
+ }
+ this.cook = function(v) {
+ return v.replace('<', '<').replace('>', '>>');
+ }
+
+ this.format_item = function(it) {
+ var str = "";
+ if (!it.d) { return; }
+ str += "" + this.cook(it.d) + " ";
+ if (it.n) {
+ str += "" + this.cook(it.n) + " \n";
+ }
+ if (it.t.length > 0) {
+ for (var i = 0; i < it.t.length; i++) {
+ var tag = it.t[i];
+ str += " " + this.cook(tag).replace(/^\s+|\s+$/g, '') + " ";
+ }
+ }
+ str += "
\n";
+ return str;
+ }
+}
+Pinboard_Linkroll.prototype = new Pinboard_Linkroll();
+pinboardNS_fetch_script("https://feeds.pinboard.in/json/v1/u:"+pinboard_user+"/?cb=pinboardNS_show_bmarks\&count="+pinboard_count);
+
diff --git a/.themes/classic/source/javascripts/twitter.js b/.themes/classic/source/javascripts/twitter.js
new file mode 100644
index 0000000..3e2dd0d
--- /dev/null
+++ b/.themes/classic/source/javascripts/twitter.js
@@ -0,0 +1,78 @@
+// JSON-P Twitter fetcher for Octopress
+// (c) Brandon Mathis // MIT License
+
+/* Sky Slavin, Ludopoli. MIT license. * based on JavaScript Pretty Date * Copyright (c) 2008 John Resig (jquery.com) * Licensed under the MIT license. */
+function prettyDate(time) {
+ if (navigator.appName === 'Microsoft Internet Explorer') {
+ return "∞ "; // because IE date parsing isn't fun.
+ }
+ var say = {
+ just_now: " now",
+ minute_ago: "1m",
+ minutes_ago: "m",
+ hour_ago: "1h",
+ hours_ago: "h",
+ yesterday: "1d",
+ days_ago: "d",
+ last_week: "1w",
+ weeks_ago: "w"
+ };
+
+ var current_date = new Date(),
+ current_date_time = current_date.getTime(),
+ current_date_full = current_date_time + (1 * 60000),
+ date = new Date(time),
+ diff = ((current_date_full - date.getTime()) / 1000),
+ day_diff = Math.floor(diff / 86400);
+
+ if (isNaN(day_diff) || day_diff < 0) { return "∞ "; }
+
+ return day_diff === 0 && (
+ diff < 60 && say.just_now ||
+ diff < 120 && say.minute_ago ||
+ diff < 3600 && Math.floor(diff / 60) + say.minutes_ago ||
+ diff < 7200 && say.hour_ago ||
+ diff < 86400 && Math.floor(diff / 3600) + say.hours_ago) ||
+ day_diff === 1 && say.yesterday ||
+ day_diff < 7 && day_diff + say.days_ago ||
+ day_diff === 7 && say.last_week ||
+ day_diff > 7 && Math.ceil(day_diff / 7) + say.weeks_ago;
+}
+
+function linkifyTweet(text, url) {
+ // Linkify urls, usernames, hashtags
+ text = text.replace(/(https?:\/\/)([\w\-:;?&=+.%#\/]+)/gi, '$2 ')
+ .replace(/(^|\W)@(\w+)/g, '$1@$2 ')
+ .replace(/(^|\W)#(\w+)/g, '$1#$2 ');
+
+ // Use twitter's api to replace t.co shortened urls with expanded ones.
+ for (var u in url) {
+ if(url[u].expanded_url != null){
+ var shortUrl = new RegExp(url[u].url, 'g');
+ text = text.replace(shortUrl, url[u].expanded_url);
+ var shortUrl = new RegExp(">"+(url[u].url.replace(/https?:\/\//, '')), 'g');
+ text = text.replace(shortUrl, ">"+url[u].display_url);
+ }
+ }
+ return text
+}
+
+function showTwitterFeed(tweets, twitter_user) {
+ var timeline = document.getElementById('tweets'),
+ content = '';
+
+ for (var t in tweets) {
+ content += ''+''+''+prettyDate(tweets[t].created_at)+' '+linkifyTweet(tweets[t].text.replace(/\n/g, ' '), tweets[t].entities.urls)+'
'+' ';
+ }
+ timeline.innerHTML = content;
+}
+
+function getTwitterFeed(user, count, replies) {
+ count = parseInt(count, 10);
+ $.ajax({
+ url: "https://api.twitter.com/1/statuses/user_timeline/" + user + ".json?trim_user=true&count=" + (count + 20) + "&include_entities=1&exclude_replies=" + (replies ? "0" : "1") + "&callback=?"
+ , type: 'jsonp'
+ , error: function (err) { $('#tweets li.loading').addClass('error').text("Twitter's busted"); }
+ , success: function(data) { showTwitterFeed(data.slice(0, count), user); }
+ })
+}
diff --git a/.themes/classic/source/robots.txt b/.themes/classic/source/robots.txt
new file mode 100644
index 0000000..ee34c72
--- /dev/null
+++ b/.themes/classic/source/robots.txt
@@ -0,0 +1,7 @@
+---
+layout: null
+---
+User-agent: *
+Disallow:
+
+Sitemap: {{ site.url }}/sitemap.xml
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..b202491
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,5 @@
+language: ruby
+rvm:
+ - 2.0.0
+ - 1.9.3
+script: bundle exec rake install; bundle exec rake generate
diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown
new file mode 100644
index 0000000..0da6ecb
--- /dev/null
+++ b/CHANGELOG.markdown
@@ -0,0 +1,29 @@
+# Octopress Changelog
+
+## 2.0
+
+- Now based on [mojombo/jekyll](http://github.com/mojombo/jekyll)
+- Sports a semantic HTML5 template
+- Easy theming with Compass and Sass
+- A Mobile friendly responsive (320 and up) layout
+- Built in 3rd party support for Twitter, Google Plus One, Disqus Comments, Pinboard, Delicious, and Google Analytics
+- Deploy to Github pages or use Rsync
+- Built in support for POW and Rack servers
+- Beautiful [Solarized](http://ethanschoonover.com/solarized) syntax highlighting
+- Super easy setup and configuration
+
+**New Plugins, Filters, & Generators**
+
+- **Gist Tag** for easily embedding gists in your posts
+- **Pygments Cache** makes subsequent compiling much faster
+- **Include Code Tag** lets you embed external code snippets from your file system and adds a download link
+- **Pullquote Tag** Generate beautiful semantic pullquotes (no double data) based on Maykel Loomans's [technique](http://miekd.com/articles/pull-quotes-with-html5-and-css/)
+- **Blockquote Tag** makes it easy to semantically format blockquotes
+- **Category Generator** gives you archive pages for each category
+- **Sitemap.xml Generator** for search engines
+
+## 1.0
+
+- **No longer supported.**
+- Jekyll Matured, but Henrik's Jekyll fork did not.
+- Thanks for all your pull requests, I learned a lot.
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..b02ee4b
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,19 @@
+source "https://rubygems.org"
+
+group :development do
+ gem 'rake', '~> 10.0'
+ gem 'jekyll', '~> 2.0'
+ gem 'octopress-hooks', '~> 2.2'
+ gem 'octopress-date-format', '~> 2.0'
+ gem 'jekyll-sitemap'
+ gem 'rdiscount', '~> 2.0'
+ gem 'RedCloth', '~> 4.2.9'
+ gem 'haml', '~> 4.0'
+ gem 'compass', '~> 0.12.2'
+ gem 'sass-globbing', '~> 1.0.0'
+ gem 'rubypants', '~> 0.2.0'
+ gem 'rb-fsevent', '~> 0.9'
+ gem 'stringex', '~> 1.4.0'
+end
+
+gem 'sinatra', '~> 1.4.2'
diff --git a/README.markdown b/README.markdown
new file mode 100644
index 0000000..d6f1933
--- /dev/null
+++ b/README.markdown
@@ -0,0 +1,41 @@
+## What is Octopress?
+
+Octopress is [Jekyll](https://github.com/mojombo/jekyll) blogging at its finest.
+
+1. **Octopress sports a clean responsive theme** written in semantic HTML5, focused on readability and friendliness toward mobile devices.
+2. **Code blogging is easy and beautiful.** Embed code (with [Solarized](http://ethanschoonover.com/solarized) styling) in your posts from gists, jsFiddle or from your filesystem.
+3. **Third party integration is simple** with built-in support for Pinboard, Delicious, GitHub Repositories, Disqus Comments and Google Analytics.
+4. **It's easy to use.** A collection of rake tasks simplifies development and makes deploying a cinch.
+5. **Ships with great plug-ins** some original and others from the Jekyll community — tested and improved.
+
+**Note**: Octopress requires a minimum Ruby version of `1.9.3-p0`.
+
+## Documentation
+
+Check out [Octopress.org](http://octopress.org/docs) for guides and documentation.
+It should all apply to our current stable version (found in the `master`
+branch). If this is not the case, [please submit a
+fix to our docs repo](https://github.com/octopress/docs).
+
+## Contributing
+
+[![Build Status](https://travis-ci.org/imathis/octopress.png?branch=master)](https://travis-ci.org/imathis/octopress)
+
+We love to see people contributing to Octopress, whether it's a bug report, feature suggestion or a pull request. At the moment, we try to keep the core slick and lean, focusing on basic blogging needs, so some of your suggestions might not find their way into Octopress. For those ideas, we started a [list of 3rd party plug-ins](https://github.com/imathis/octopress/wiki/3rd-party-plugins), where you can link your own Octopress plug-in repositories. For the future, we're thinking about ways to easier add them into our main releases.
+
+
+## License
+(The MIT License)
+
+Copyright © 2009-2013 Brandon Mathis
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+#### If you want to be awesome.
+- Proudly display the 'Powered by Octopress' credit in the footer.
+- Add your site to the Wiki so we can watch the community grow.
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000..02df13b
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,405 @@
+require "rubygems"
+require "bundler/setup"
+require "stringex"
+
+## -- Rsync Deploy config -- ##
+# Be sure your public key is listed in your server's ~/.ssh/authorized_keys file
+ssh_user = "user@domain.com"
+ssh_port = "22"
+document_root = "~/website.com/"
+rsync_delete = false
+rsync_args = "" # Any extra arguments to pass to rsync
+deploy_default = "rsync"
+
+# This will be configured for you when you run config_deploy
+deploy_branch = "gh-pages"
+
+## -- Misc Configs -- ##
+
+public_dir = "public" # compiled site directory
+source_dir = "source" # source file directory
+blog_index_dir = 'source' # directory for your blog's index page (if you put your index in source/blog/index.html, set this to 'source/blog')
+deploy_dir = "_deploy" # deploy directory (for Github pages deployment)
+stash_dir = "_stash" # directory to stash posts for speedy generation
+posts_dir = "_posts" # directory for blog files
+themes_dir = ".themes" # directory for blog files
+new_post_ext = "markdown" # default new post file extension when using the new_post task
+new_page_ext = "markdown" # default new page file extension when using the new_page task
+server_port = "4000" # port for preview server eg. localhost:4000
+
+if (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil
+ puts '## Set the codepage to 65001 for Windows machines'
+ `chcp 65001`
+end
+
+desc "Initial setup for Octopress: copies the default theme into the path of Jekyll's generator. Rake install defaults to rake install[classic] to install a different theme run rake install[some_theme_name]"
+task :install, :theme do |t, args|
+ if File.directory?(source_dir) || File.directory?("sass")
+ abort("rake aborted!") if ask("A theme is already installed, proceeding will overwrite existing files. Are you sure?", ['y', 'n']) == 'n'
+ end
+ # copy theme into working Jekyll directories
+ theme = args.theme || 'classic'
+ puts "## Copying "+theme+" theme into ./#{source_dir} and ./sass"
+ mkdir_p source_dir
+ cp_r "#{themes_dir}/#{theme}/source/.", source_dir
+ mkdir_p "sass"
+ cp_r "#{themes_dir}/#{theme}/sass/.", "sass"
+ mkdir_p "#{source_dir}/#{posts_dir}"
+ mkdir_p public_dir
+end
+
+#######################
+# Working with Jekyll #
+#######################
+
+desc "Generate jekyll site"
+task :generate do
+ raise "### You haven't set anything up yet. First run `rake install` to set up an Octopress theme." unless File.directory?(source_dir)
+ puts "## Generating Site with Jekyll"
+ system "compass compile --css-dir #{source_dir}/stylesheets"
+ system "jekyll build"
+end
+
+desc "Watch the site and regenerate when it changes"
+task :watch do
+ raise "### You haven't set anything up yet. First run `rake install` to set up an Octopress theme." unless File.directory?(source_dir)
+ puts "Starting to watch source with Jekyll and Compass."
+ system "compass compile --css-dir #{source_dir}/stylesheets" unless File.exist?("#{source_dir}/stylesheets/screen.css")
+ jekyllPid = Process.spawn({"OCTOPRESS_ENV"=>"preview"}, "jekyll build --watch")
+ compassPid = Process.spawn("compass watch")
+
+ trap("INT") {
+ [jekyllPid, compassPid].each { |pid| Process.kill(9, pid) rescue Errno::ESRCH }
+ exit 0
+ }
+
+ [jekyllPid, compassPid].each { |pid| Process.wait(pid) }
+end
+
+desc "preview the site in a web browser"
+task :preview do
+ raise "### You haven't set anything up yet. First run `rake install` to set up an Octopress theme." unless File.directory?(source_dir)
+ puts "Starting to watch source with Jekyll and Compass. Starting Rack on port #{server_port}"
+ system "compass compile --css-dir #{source_dir}/stylesheets" unless File.exist?("#{source_dir}/stylesheets/screen.css")
+ jekyllPid = Process.spawn({"OCTOPRESS_ENV"=>"preview"}, "jekyll build --watch")
+ compassPid = Process.spawn("compass watch")
+ rackupPid = Process.spawn("rackup --port #{server_port}")
+
+ trap("INT") {
+ [jekyllPid, compassPid, rackupPid].each { |pid| Process.kill(9, pid) rescue Errno::ESRCH }
+ exit 0
+ }
+
+ [jekyllPid, compassPid, rackupPid].each { |pid| Process.wait(pid) }
+end
+
+# usage rake new_post[my-new-post] or rake new_post['my new post'] or rake new_post (defaults to "new-post")
+desc "Begin a new post in #{source_dir}/#{posts_dir}"
+task :new_post, :title do |t, args|
+ if args.title
+ title = args.title
+ else
+ title = get_stdin("Enter a title for your post: ")
+ end
+ raise "### You haven't set anything up yet. First run `rake install` to set up an Octopress theme." unless File.directory?(source_dir)
+ mkdir_p "#{source_dir}/#{posts_dir}"
+ filename = "#{source_dir}/#{posts_dir}/#{Time.now.strftime('%Y-%m-%d')}-#{title.to_url}.#{new_post_ext}"
+ if File.exist?(filename)
+ abort("rake aborted!") if ask("#{filename} already exists. Do you want to overwrite?", ['y', 'n']) == 'n'
+ end
+ puts "Creating new post: #{filename}"
+ open(filename, 'w') do |post|
+ post.puts "---"
+ post.puts "layout: post"
+ post.puts "title: \"#{title.gsub(/&/,'&')}\""
+ post.puts "date: #{Time.now.strftime('%Y-%m-%d %H:%M:%S %z')}"
+ post.puts "comments: true"
+ post.puts "categories: "
+ post.puts "---"
+ end
+end
+
+# usage rake new_page[my-new-page] or rake new_page[my-new-page.html] or rake new_page (defaults to "new-page.markdown")
+desc "Create a new page in #{source_dir}/(filename)/index.#{new_page_ext}"
+task :new_page, :filename do |t, args|
+ raise "### You haven't set anything up yet. First run `rake install` to set up an Octopress theme." unless File.directory?(source_dir)
+ args.with_defaults(:filename => 'new-page')
+ page_dir = [source_dir]
+ if args.filename.downcase =~ /(^.+\/)?(.+)/
+ filename, dot, extension = $2.rpartition('.').reject(&:empty?) # Get filename and extension
+ title = filename
+ page_dir.concat($1.downcase.sub(/^\//, '').split('/')) unless $1.nil? # Add path to page_dir Array
+ if extension.nil?
+ page_dir << filename
+ filename = "index"
+ end
+ extension ||= new_page_ext
+ page_dir = page_dir.map! { |d| d = d.to_url }.join('/') # Sanitize path
+ filename = filename.downcase.to_url
+
+ mkdir_p page_dir
+ file = "#{page_dir}/#{filename}.#{extension}"
+ if File.exist?(file)
+ abort("rake aborted!") if ask("#{file} already exists. Do you want to overwrite?", ['y', 'n']) == 'n'
+ end
+ puts "Creating new page: #{file}"
+ open(file, 'w') do |page|
+ page.puts "---"
+ page.puts "layout: page"
+ page.puts "title: \"#{title}\""
+ page.puts "date: #{Time.now.strftime('%Y-%m-%d %H:%M')}"
+ page.puts "comments: true"
+ page.puts "sharing: true"
+ page.puts "footer: true"
+ page.puts "---"
+ end
+ else
+ puts "Syntax error: #{args.filename} contains unsupported characters"
+ end
+end
+
+# usage rake isolate[my-post]
+desc "Move all other posts than the one currently being worked on to a temporary stash location (stash) so regenerating the site happens much more quickly."
+task :isolate, :filename do |t, args|
+ stash_dir = "#{source_dir}/#{stash_dir}"
+ FileUtils.mkdir(stash_dir) unless File.exist?(stash_dir)
+ Dir.glob("#{source_dir}/#{posts_dir}/*.*") do |post|
+ FileUtils.mv post, stash_dir unless post.include?(args.filename)
+ end
+end
+
+desc "Move all stashed posts back into the posts directory, ready for site generation."
+task :integrate do
+ FileUtils.mv Dir.glob("#{source_dir}/#{stash_dir}/*.*"), "#{source_dir}/#{posts_dir}/"
+end
+
+desc "Clean out caches: .pygments-cache, .gist-cache, .sass-cache"
+task :clean do
+ rm_rf [Dir.glob(".pygments-cache/**"), Dir.glob(".gist-cache/**"), Dir.glob(".sass-cache/**"), "source/stylesheets/screen.css"]
+end
+
+desc "Move sass to sass.old, install sass theme updates, replace sass/custom with sass.old/custom"
+task :update_style, :theme do |t, args|
+ theme = args.theme || 'classic'
+ if File.directory?("sass.old")
+ puts "removed existing sass.old directory"
+ rm_r "sass.old", :secure=>true
+ end
+ mv "sass", "sass.old"
+ puts "## Moved styles into sass.old/"
+ cp_r "#{themes_dir}/"+theme+"/sass/", "sass", :remove_destination=>true
+ cp_r "sass.old/custom/.", "sass/custom/", :remove_destination=>true
+ puts "## Updated Sass ##"
+end
+
+desc "Move source to source.old, install source theme updates, replace source/_includes/navigation.html with source.old's navigation"
+task :update_source, :theme do |t, args|
+ theme = args.theme || 'classic'
+ if File.directory?("#{source_dir}.old")
+ puts "## Removed existing #{source_dir}.old directory"
+ rm_r "#{source_dir}.old", :secure=>true
+ end
+ mkdir "#{source_dir}.old"
+ cp_r "#{source_dir}/.", "#{source_dir}.old"
+ puts "## Copied #{source_dir} into #{source_dir}.old/"
+ cp_r "#{themes_dir}/"+theme+"/source/.", source_dir, :remove_destination=>true
+ cp_r "#{source_dir}.old/_includes/custom/.", "#{source_dir}/_includes/custom/", :remove_destination=>true
+ cp "#{source_dir}.old/favicon.png", source_dir
+ mv "#{source_dir}/index.html", "#{blog_index_dir}", :force=>true if blog_index_dir != source_dir
+ cp "#{source_dir}.old/index.html", source_dir if blog_index_dir != source_dir && File.exists?("#{source_dir}.old/index.html")
+ puts "## Updated #{source_dir} ##"
+end
+
+##############
+# Deploying #
+##############
+
+desc "Default deploy task"
+task :deploy do
+ # Check if preview posts exist, which should not be published
+ if File.exists?(".preview-mode")
+ puts "## Found posts in preview mode, regenerating files ..."
+ File.delete(".preview-mode")
+ Rake::Task[:generate].execute
+ end
+
+ Rake::Task[:copydot].invoke(source_dir, public_dir)
+ Rake::Task["#{deploy_default}"].execute
+end
+
+desc "Generate website and deploy"
+task :gen_deploy => [:integrate, :generate, :deploy] do
+end
+
+desc "copy dot files for deployment"
+task :copydot, :source, :dest do |t, args|
+ FileList["#{args.source}/**/.*"].exclude("**/.", "**/..", "**/.DS_Store", "**/._*").each do |file|
+ cp_r file, file.gsub(/#{args.source}/, "#{args.dest}") unless File.directory?(file)
+ end
+end
+
+desc "Deploy website via rsync"
+task :rsync do
+ exclude = ""
+ if File.exists?('./rsync-exclude')
+ exclude = "--exclude-from '#{File.expand_path('./rsync-exclude')}'"
+ end
+ puts "## Deploying website via Rsync"
+ ok_failed system("rsync -avze 'ssh -p #{ssh_port}' #{exclude} #{rsync_args} #{"--delete" unless rsync_delete == false} #{public_dir}/ #{ssh_user}:#{document_root}")
+end
+
+desc "deploy public directory to github pages"
+multitask :push do
+ puts "## Deploying branch to Github Pages "
+ puts "## Pulling any updates from Github Pages "
+ cd "#{deploy_dir}" do
+ Bundler.with_clean_env { system "git pull" }
+ end
+ (Dir["#{deploy_dir}/*"]).each { |f| rm_rf(f) }
+ Rake::Task[:copydot].invoke(public_dir, deploy_dir)
+ puts "\n## Copying #{public_dir} to #{deploy_dir}"
+ cp_r "#{public_dir}/.", deploy_dir
+ cd "#{deploy_dir}" do
+ system "git add -A"
+ message = "Site updated at #{Time.now.utc}"
+ puts "\n## Committing: #{message}"
+ system "git commit -m \"#{message}\""
+ puts "\n## Pushing generated #{deploy_dir} website"
+ Bundler.with_clean_env { system "git push origin #{deploy_branch}" }
+ puts "\n## Github Pages deploy complete"
+ end
+end
+
+desc "Update configurations to support publishing to root or sub directory"
+task :set_root_dir, :dir do |t, args|
+ puts ">>> !! Please provide a directory, eg. rake config_dir[publishing/subdirectory]" unless args.dir
+ if args.dir
+ if args.dir == "/"
+ dir = ""
+ else
+ dir = "/" + args.dir.sub(/(\/*)(.+)/, "\\2").sub(/\/$/, '');
+ end
+ rakefile = IO.read(__FILE__)
+ rakefile.sub!(/public_dir(\s*)=(\s*)(["'])[\w\-\/]*["']/, "public_dir\\1=\\2\\3public#{dir}\\3")
+ File.open(__FILE__, 'w') do |f|
+ f.write rakefile
+ end
+ compass_config = IO.read('config.rb')
+ compass_config.sub!(/http_path(\s*)=(\s*)(["'])[\w\-\/]*["']/, "http_path\\1=\\2\\3#{dir}/\\3")
+ compass_config.sub!(/http_images_path(\s*)=(\s*)(["'])[\w\-\/]*["']/, "http_images_path\\1=\\2\\3#{dir}/images\\3")
+ compass_config.sub!(/http_fonts_path(\s*)=(\s*)(["'])[\w\-\/]*["']/, "http_fonts_path\\1=\\2\\3#{dir}/fonts\\3")
+ compass_config.sub!(/css_dir(\s*)=(\s*)(["'])[\w\-\/]*["']/, "css_dir\\1=\\2\\3public#{dir}/stylesheets\\3")
+ File.open('config.rb', 'w') do |f|
+ f.write compass_config
+ end
+ jekyll_config = IO.read('_config.yml')
+ jekyll_config.sub!(/^destination:.+$/, "destination: public#{dir}")
+ jekyll_config.sub!(/^subscribe_rss:\s*\/.+$/, "subscribe_rss: #{dir}/atom.xml")
+ jekyll_config.sub!(/^root:.*$/, "root: /#{dir.sub(/^\//, '')}")
+ File.open('_config.yml', 'w') do |f|
+ f.write jekyll_config
+ end
+ rm_rf public_dir
+ mkdir_p "#{public_dir}#{dir}"
+ puts "## Site's root directory is now '/#{dir.sub(/^\//, '')}' ##"
+ end
+end
+
+desc "Set up _deploy folder and deploy branch for Github Pages deployment"
+task :setup_github_pages, :repo do |t, args|
+ if args.repo
+ repo_url = args.repo
+ else
+ puts "Enter the read/write url for your repository"
+ puts "(For example, 'git@github.com:your_username/your_username.github.io.git)"
+ puts " or 'https://github.com/your_username/your_username.github.io')"
+ repo_url = get_stdin("Repository url: ")
+ end
+ protocol = (repo_url.match(/(^git)@/).nil?) ? 'https' : 'git'
+ if protocol == 'git'
+ user = repo_url.match(/:([^\/]+)/)[1]
+ else
+ user = repo_url.match(/github\.com\/([^\/]+)/)[1]
+ end
+ branch = (repo_url.match(/\/[\w-]+\.github\.(?:io|com)/).nil?) ? 'gh-pages' : 'master'
+ project = (branch == 'gh-pages') ? repo_url.match(/\/([^\.]+)/)[1] : ''
+ unless (`git remote -v` =~ /origin.+?octopress(?:\.git)?/).nil?
+ # If octopress is still the origin remote (from cloning) rename it to octopress
+ system "git remote rename origin octopress"
+ if branch == 'master'
+ # If this is a user/organization pages repository, add the correct origin remote
+ # and checkout the source branch for committing changes to the blog source.
+ system "git remote add origin #{repo_url}"
+ puts "Added remote #{repo_url} as origin"
+ system "git config branch.master.remote origin"
+ puts "Set origin as default remote"
+ system "git branch -m master source"
+ puts "Master branch renamed to 'source' for committing your blog source files"
+ else
+ unless !public_dir.match("#{project}").nil?
+ system "rake set_root_dir[#{project}]"
+ end
+ end
+ end
+ url = blog_url(user, project)
+ jekyll_config = IO.read('_config.yml')
+ jekyll_config.sub!(/^url:.*$/, "url: #{url}")
+ File.open('_config.yml', 'w') do |f|
+ f.write jekyll_config
+ end
+ rm_rf deploy_dir
+ mkdir deploy_dir
+ cd "#{deploy_dir}" do
+ system "git init"
+ system "echo 'My Octopress Page is coming soon …' > index.html"
+ system "git add ."
+ system "git commit -m \"Octopress init\""
+ system "git branch -m gh-pages" unless branch == 'master'
+ system "git remote add origin #{repo_url}"
+ rakefile = IO.read(__FILE__)
+ rakefile.sub!(/deploy_branch(\s*)=(\s*)(["'])[\w-]*["']/, "deploy_branch\\1=\\2\\3#{branch}\\3")
+ rakefile.sub!(/deploy_default(\s*)=(\s*)(["'])[\w-]*["']/, "deploy_default\\1=\\2\\3push\\3")
+ File.open(__FILE__, 'w') do |f|
+ f.write rakefile
+ end
+ end
+ puts "\n---\n## Now you can deploy to #{repo_url} with `rake deploy` ##"
+end
+
+def ok_failed(condition)
+ if (condition)
+ puts "OK"
+ else
+ puts "FAILED"
+ end
+end
+
+def get_stdin(message)
+ print message
+ STDIN.gets.chomp
+end
+
+def ask(message, valid_options)
+ if valid_options
+ answer = get_stdin("#{message} #{valid_options.to_s.gsub(/"/, '').gsub(/, /,'/')} ") while !valid_options.include?(answer)
+ else
+ answer = get_stdin(message)
+ end
+ answer
+end
+
+def blog_url(user, project)
+ url = if File.exists?('source/CNAME')
+ "http://#{IO.read('source/CNAME').strip}"
+ else
+ "http://#{user.downcase}.github.io"
+ end
+ url += "/#{project}" unless project == ''
+ url
+end
+
+desc "list tasks"
+task :list do
+ puts "Tasks: #{(Rake::Task.tasks - [Rake::Task[:list]]).join(', ')}"
+ puts "(type rake -T for more detail)\n\n"
+end
diff --git a/_config.yml b/_config.yml
new file mode 100644
index 0000000..c1d56f4
--- /dev/null
+++ b/_config.yml
@@ -0,0 +1,101 @@
+# ----------------------- #
+# Main Configs #
+# ----------------------- #
+
+url: http://yoursite.com
+title: My Octopress Blog
+subtitle: A blogging framework for hackers.
+author: Your Name
+simple_search: https://www.google.com/search
+description:
+
+# Default date format is "ordinal" (resulting in "July 22nd 2007")
+# You can customize the format as defined in
+# http://www.ruby-doc.org/core-1.9.2/Time.html#method-i-strftime
+# Additionally, %o will give you the ordinal representation of the day
+date_format: "ordinal"
+
+# RSS / Email (optional) subscription links (change if using something like Feedburner)
+subscribe_rss: /atom.xml
+subscribe_email:
+# RSS feeds can list your email address if you like
+email:
+
+# ----------------------- #
+# Jekyll & Plugins #
+# ----------------------- #
+
+# If publishing to a subdirectory as in http://site.com/project set 'root: /project'
+root: /
+permalink: /blog/:year/:month/:day/:title/
+source: source
+destination: public
+plugins: plugins
+code_dir: downloads/code
+category_dir: blog/categories
+markdown: rdiscount
+rdiscount:
+ extensions:
+ - autolink
+ - footnotes
+ - smart
+highlighter: pygments # default python pygments have been replaced by pygments.rb
+
+paginate: 10 # Posts per page on the blog index
+paginate_path: "posts/:num" # Directory base for pagination URLs eg. /posts/2/
+recent_posts: 5 # Posts in the sidebar Recent Posts section
+excerpt_link: "Read on →" # "Continue reading" link text at the bottom of excerpted articles
+excerpt_separator: ""
+
+titlecase: true # Converts page and post titles to titlecase
+
+# list each of the sidebar modules you want to include, in the order you want them to appear.
+# To add custom asides, create files in /source/_includes/custom/asides/ and add them to the list like 'custom/asides/custom_aside_name.html'
+default_asides: [asides/recent_posts.html, asides/github.html, asides/delicious.html, asides/pinboard.html, asides/googleplus.html]
+
+# Each layout uses the default asides, but they can have their own asides instead. Simply uncomment the lines below
+# and add an array with the asides you want to use.
+# blog_index_asides:
+# post_asides:
+# page_asides:
+
+# ----------------------- #
+# 3rd Party Settings #
+# ----------------------- #
+
+# Github repositories
+github_user:
+github_repo_count: 0
+github_show_profile_link: true
+github_skip_forks: true
+
+# Twitter
+twitter_user:
+twitter_tweet_button: true
+
+# Google +1
+google_plus_one: false
+google_plus_one_size: medium
+
+# Google Plus Profile
+# Hidden: No visible button, just add author information to search results
+googleplus_user:
+googleplus_hidden: false
+
+# Pinboard
+pinboard_user:
+pinboard_count: 3
+
+# Delicious
+delicious_user:
+delicious_count: 3
+
+# Disqus Comments
+disqus_short_name:
+disqus_show_comment_count: false
+
+# Google Analytics
+google_analytics_tracking_id:
+
+# Facebook Like
+facebook_like: false
diff --git a/config.rb b/config.rb
new file mode 100644
index 0000000..408aeca
--- /dev/null
+++ b/config.rb
@@ -0,0 +1,19 @@
+require 'sass-globbing'
+
+# Require any additional compass plugins here.
+project_type = :stand_alone
+
+# Publishing paths
+http_path = "/"
+http_images_path = "/images"
+http_generated_images_path = "/images"
+http_fonts_path = "/fonts"
+css_dir = "public/stylesheets"
+
+# Local development paths
+sass_dir = "sass"
+images_dir = "source/images"
+fonts_dir = "source/fonts"
+
+line_comments = false
+output_style = :compressed
diff --git a/config.ru b/config.ru
new file mode 100644
index 0000000..8e3dc08
--- /dev/null
+++ b/config.ru
@@ -0,0 +1,25 @@
+require 'bundler/setup'
+require 'sinatra/base'
+
+# The project root directory
+$root = ::File.dirname(__FILE__)
+
+class SinatraStaticServer < Sinatra::Base
+
+ get(/.+/) do
+ send_sinatra_file(request.path) {404}
+ end
+
+ not_found do
+ send_file(File.join(File.dirname(__FILE__), 'public', '404.html'), {:status => 404})
+ end
+
+ def send_sinatra_file(path, &missing_file_block)
+ file_path = File.join(File.dirname(__FILE__), 'public', path)
+ file_path = File.join(file_path, 'index.html') unless file_path =~ /\.[a-z]+$/i
+ File.exist?(file_path) ? send_file(file_path) : missing_file_block.call
+ end
+
+end
+
+run SinatraStaticServer
diff --git a/images/bg_hr.png b/images/bg_hr.png
new file mode 100644
index 0000000..514aee5
Binary files /dev/null and b/images/bg_hr.png differ
diff --git a/images/blacktocat.png b/images/blacktocat.png
new file mode 100644
index 0000000..e160053
Binary files /dev/null and b/images/blacktocat.png differ
diff --git a/images/icon_download.png b/images/icon_download.png
new file mode 100644
index 0000000..5a793f1
Binary files /dev/null and b/images/icon_download.png differ
diff --git a/images/sprite_download.png b/images/sprite_download.png
new file mode 100644
index 0000000..f9f8de2
Binary files /dev/null and b/images/sprite_download.png differ
diff --git a/index.html b/index.html
index b167352..09dd7d0 100644
--- a/index.html
+++ b/index.html
@@ -1,171 +1,72 @@
-
-
-
- My Octopress Blog
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Skip to main content
-
-
-
-
-
+
+
+
+
+ Welcome to GitHub Pages.
-
-
-
-
-
- Copyright © 2014 - Your Name
-
- Powered by Octopress ,
- customized with octostrap3 .
-
-
+
This automatic page generator is the easiest way to create beautiful pages for all of your projects. Author your page content here using GitHub Flavored Markdown, select a template crafted by a designer, and publish. After your page is generated, you can check out the new branch:
-
-
-
+
$ cd your_repo_root/repo_name
+$ git fetch origin
+$ git checkout gh-pages
+
+
If you're using the GitHub for Mac, simply sync your repository and you'll see the new branch.
+
+ Designer Templates
+
We've crafted some handsome templates for you to use. Go ahead and continue to layouts to browse through them. You can easily go back to edit your page before publishing. After publishing your page, you can revisit the page generator and switch to another theme. Your Page content will be preserved if it remained markdown format.
+
+ Rather Drive Stick?
+
If you prefer to not use the automatic generator, push a branch named gh-pages
to your repository to create a page manually. In addition to supporting regular HTML content, GitHub Pages support Jekyll, a simple, blog aware static site generator written by our own Tom Preston-Werner. Jekyll makes it easy to create site-wide headers and footers without having to copy them across every page. It also offers intelligent blog support and other advanced templating features.
+
+ Authors and Contributors
-
+
You can @mention a GitHub username to generate a link to their profile. The resulting <a>
element will link to the contributor's GitHub Profile. For example: In 2007, Chris Wanstrath (@defunkt ), PJ Hyett (@pjhyett ), and Tom Preston-Werner (@mojombo ) founded GitHub.
+
+ Support or Contact
-
-
+
Having trouble with Pages? Check out the documentation at http://help.github.com/pages or contact support@github.com and we’ll help you sort it out.
+
+
+
+
+
diff --git a/javascripts/main.js b/javascripts/main.js
new file mode 100644
index 0000000..d8135d3
--- /dev/null
+++ b/javascripts/main.js
@@ -0,0 +1 @@
+console.log('This would be the main JS file.');
diff --git a/params.json b/params.json
new file mode 100644
index 0000000..6ffcf2b
--- /dev/null
+++ b/params.json
@@ -0,0 +1 @@
+{"name":"Isuct.github.io","tagline":"","body":"### Welcome to GitHub Pages.\r\nThis automatic page generator is the easiest way to create beautiful pages for all of your projects. Author your page content here using GitHub Flavored Markdown, select a template crafted by a designer, and publish. After your page is generated, you can check out the new branch:\r\n\r\n```\r\n$ cd your_repo_root/repo_name\r\n$ git fetch origin\r\n$ git checkout gh-pages\r\n```\r\n\r\nIf you're using the GitHub for Mac, simply sync your repository and you'll see the new branch.\r\n\r\n### Designer Templates\r\nWe've crafted some handsome templates for you to use. Go ahead and continue to layouts to browse through them. You can easily go back to edit your page before publishing. After publishing your page, you can revisit the page generator and switch to another theme. Your Page content will be preserved if it remained markdown format.\r\n\r\n### Rather Drive Stick?\r\nIf you prefer to not use the automatic generator, push a branch named `gh-pages` to your repository to create a page manually. In addition to supporting regular HTML content, GitHub Pages support Jekyll, a simple, blog aware static site generator written by our own Tom Preston-Werner. Jekyll makes it easy to create site-wide headers and footers without having to copy them across every page. It also offers intelligent blog support and other advanced templating features.\r\n\r\n### Authors and Contributors\r\nYou can @mention a GitHub username to generate a link to their profile. The resulting `` element will link to the contributor's GitHub Profile. For example: In 2007, Chris Wanstrath (@defunkt), PJ Hyett (@pjhyett), and Tom Preston-Werner (@mojombo) founded GitHub.\r\n\r\n### Support or Contact\r\nHaving trouble with Pages? Check out the documentation at http://help.github.com/pages or contact support@github.com and we’ll help you sort it out.\r\n","google":"","note":"Don't delete this file! It's used internally to help with page regeneration."}
\ No newline at end of file
diff --git a/plugins/backtick_code_block.rb b/plugins/backtick_code_block.rb
new file mode 100644
index 0000000..ae4a047
--- /dev/null
+++ b/plugins/backtick_code_block.rb
@@ -0,0 +1,42 @@
+require './plugins/pygments_code'
+
+module BacktickCodeBlock
+ AllOptions = /([^\s]+)\s+(.+?)\s+(https?:\/\/\S+|\/\S+)\s*(.+)?/i
+ LangCaption = /([^\s]+)\s*(.+)?/i
+ def self.render_code_block(input)
+ @options = nil
+ @caption = nil
+ @lang = nil
+ @url = nil
+ @title = nil
+ input.gsub(/^`{3} *([^\n]+)?\n(.+?)\n`{3}/m) do
+ @options = $1 || ''
+ str = $2
+
+ if @options =~ AllOptions
+ @lang = $1
+ @caption = "#{$2} #{$4 || 'link'} "
+ elsif @options =~ LangCaption
+ @lang = $1
+ @caption = "#{$2} "
+ end
+
+ if str.match(/\A( {4}|\t)/)
+ str = str.gsub(/^( {4}|\t)/, '')
+ end
+ if @lang.nil? || @lang == 'plain'
+ code = HighlightCode::tableize_code(str.gsub('<','<').gsub('>','>'))
+ "#{@caption}#{code} "
+ else
+ if @lang.include? "-raw"
+ raw = "``` #{@options.sub('-raw', '')}\n"
+ raw += str
+ raw += "\n```\n"
+ else
+ code = HighlightCode::highlight(str, @lang)
+ "#{@caption}#{code} "
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/blockquote.rb b/plugins/blockquote.rb
new file mode 100644
index 0000000..ebdc0e8
--- /dev/null
+++ b/plugins/blockquote.rb
@@ -0,0 +1,82 @@
+#
+# Author: Brandon Mathis
+# A full rewrite based on the work of: Josediaz Gonzalez - https://github.com/josegonzalez/josediazgonzalez.com/blob/master/_plugins/blockquote.rb
+#
+# Outputs a string with a given attribution as a quote
+#
+# {% blockquote Bobby Willis http://google.com/search?q=pants the search for bobby's pants %}
+# Wheeee!
+# {% endblockquote %}
+# ...
+#
+# Wheeee!
+#
+#
+require './plugins/titlecase.rb'
+
+module Jekyll
+
+ class Blockquote < Liquid::Block
+ FullCiteWithTitle = /(\S.*)\s+(https?:\/\/)(\S+)\s+(.+)/i
+ FullCite = /(\S.*)\s+(https?:\/\/)(\S+)/i
+ AuthorTitle = /([^,]+),([^,]+)/
+ Author = /(.+)/
+
+ def initialize(tag_name, markup, tokens)
+ @by = nil
+ @source = nil
+ @title = nil
+ if markup =~ FullCiteWithTitle
+ @by = $1
+ @source = $2 + $3
+ @title = $4.titlecase.strip
+ elsif markup =~ FullCite
+ @by = $1
+ @source = $2 + $3
+ elsif markup =~ AuthorTitle
+ @by = $1
+ @title = $2.titlecase.strip
+ elsif markup =~ Author
+ @by = $1
+ end
+ super
+ end
+
+ def render(context)
+ quote = paragraphize(super)
+ author = "#{@by.strip} " if @by
+ if @source
+ url = @source.match(/https?:\/\/(.+)/)[1].split('/')
+ parts = []
+ url.each do |part|
+ if (parts + [part]).join('/').length < 32
+ parts << part
+ end
+ end
+ source = parts.join('/')
+ source << '/…' unless source == @source
+ end
+ if !@source.nil?
+ cite = " #{(@title || source)} "
+ elsif !@title.nil?
+ cite = " #{@title} "
+ end
+ blockquote = if @by.nil?
+ quote
+ elsif cite
+ "#{quote}"
+ else
+ "#{quote}"
+ end
+ "#{blockquote} "
+ end
+
+ def paragraphize(input)
+ "#{input.lstrip.rstrip.gsub(/\n\n/, '
').gsub(/\n/, ' ')}
"
+ end
+ end
+end
+
+Liquid::Template.register_tag('blockquote', Jekyll::Blockquote)
diff --git a/plugins/category_generator.rb b/plugins/category_generator.rb
new file mode 100644
index 0000000..c55d62f
--- /dev/null
+++ b/plugins/category_generator.rb
@@ -0,0 +1,193 @@
+# encoding: utf-8
+#
+# Jekyll category page generator.
+# http://recursive-design.com/projects/jekyll-plugins/
+#
+# Version: 0.1.4 (201101061053)
+#
+# Copyright (c) 2010 Dave Perrett, http://recursive-design.com/
+# Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
+#
+# A generator that creates category pages for jekyll sites.
+#
+# Included filters :
+# - category_links: Outputs the list of categories as comma-separated links.
+# - date_to_html_string: Outputs the post.date as formatted html, with hooks for CSS styling.
+#
+# Available _config.yml settings :
+# - category_dir: The subfolder to build category pages in (default is 'categories').
+# - category_title_prefix: The string used before the category name in the page title (default is
+# 'Category: ').
+
+require 'stringex'
+
+module Jekyll
+
+ # The CategoryIndex class creates a single category page for the specified category.
+ class CategoryIndex < Page
+
+ # Initializes a new CategoryIndex.
+ #
+ # +base+ is the String path to the .
+ # +category_dir+ is the String path between and the category folder.
+ # +category+ is the category currently being processed.
+ def initialize(site, base, category_dir, category)
+ @site = site
+ @base = base
+ @dir = category_dir
+ @name = 'index.html'
+ self.process(@name)
+ # Read the YAML data from the layout page.
+ self.read_yaml(File.join(base, '_layouts'), 'category_index.html')
+ self.data['category'] = category
+ # Set the title for this page.
+ title_prefix = site.config['category_title_prefix'] || 'Category: '
+ self.data['title'] = "#{title_prefix}#{category}"
+ # Set the meta-description for this page.
+ meta_description_prefix = site.config['category_meta_description_prefix'] || 'Category: '
+ self.data['description'] = "#{meta_description_prefix}#{category}"
+ end
+
+ end
+
+ # The CategoryFeed class creates an Atom feed for the specified category.
+ class CategoryFeed < Page
+
+ # Initializes a new CategoryFeed.
+ #
+ # +base+ is the String path to the .
+ # +category_dir+ is the String path between and the category folder.
+ # +category+ is the category currently being processed.
+ def initialize(site, base, category_dir, category)
+ @site = site
+ @base = base
+ @dir = category_dir
+ @name = 'atom.xml'
+ self.process(@name)
+ # Read the YAML data from the layout page.
+ self.read_yaml(File.join(base, '_includes/custom'), 'category_feed.xml')
+ self.data['category'] = category
+ # Set the title for this page.
+ title_prefix = site.config['category_title_prefix'] || 'Category: '
+ self.data['title'] = "#{title_prefix}#{category}"
+ # Set the meta-description for this page.
+ meta_description_prefix = site.config['category_meta_description_prefix'] || 'Category: '
+ self.data['description'] = "#{meta_description_prefix}#{category}"
+
+ # Set the correct feed URL.
+ self.data['feed_url'] = "#{category_dir}/#{name}"
+ end
+
+ end
+
+ # The Site class is a built-in Jekyll class with access to global site config information.
+ class Site
+
+ # Creates an instance of CategoryIndex for each category page, renders it, and
+ # writes the output to a file.
+ #
+ # +category_dir+ is the String path to the category folder.
+ # +category+ is the category currently being processed.
+ def write_category_index(category_dir, category)
+ index = CategoryIndex.new(self, self.source, category_dir, category)
+ index.render(self.layouts, site_payload)
+ index.write(self.dest)
+ # Record the fact that this page has been added, otherwise Site::cleanup will remove it.
+ self.pages << index
+
+ # Create an Atom-feed for each index.
+ feed = CategoryFeed.new(self, self.source, category_dir, category)
+ feed.render(self.layouts, site_payload)
+ feed.write(self.dest)
+ # Record the fact that this page has been added, otherwise Site::cleanup will remove it.
+ self.pages << feed
+ end
+
+ # Loops through the list of category pages and processes each one.
+ def write_category_indexes
+ if self.layouts.key? 'category_index'
+ dir = self.config['category_dir'] || 'categories'
+ self.categories.keys.each do |category|
+ self.write_category_index(File.join(dir, category.to_url), category)
+ end
+
+ # Throw an exception if the layout couldn't be found.
+ else
+ raise <<-ERR
+
+
+===============================================
+ Error for category_generator.rb plugin
+-----------------------------------------------
+ No 'category_index.html' in source/_layouts/
+ Perhaps you haven't installed a theme yet.
+===============================================
+
+ERR
+ end
+ end
+
+ end
+
+
+ # Jekyll hook - the generate method is called by jekyll, and generates all of the category pages.
+ class GenerateCategories < Generator
+ safe true
+ priority :low
+
+ def generate(site)
+ site.write_category_indexes
+ end
+
+ end
+
+
+ # Adds some extra filters used during the category creation process.
+ module Filters
+
+ # Outputs a list of categories as comma-separated links. This is used
+ # to output the category list for each post on a category page.
+ #
+ # +categories+ is the list of categories to format.
+ #
+ # Returns string
+ #
+ def category_links(categories)
+ categories = categories.sort!.map { |c| category_link c }
+
+ case categories.length
+ when 0
+ ""
+ when 1
+ categories[0].to_s
+ else
+ "#{categories[0...-1].join(', ')}, #{categories[-1]}"
+ end
+ end
+
+ # Outputs a single category as an link.
+ #
+ # +category+ is a category string to format as an link
+ #
+ # Returns string
+ #
+ def category_link(category)
+ dir = @context.registers[:site].config['category_dir']
+ " #{category} "
+ end
+
+ # Outputs the post.date as formatted html, with hooks for CSS styling.
+ #
+ # +date+ is the date object to format as HTML.
+ #
+ # Returns string
+ def date_to_html_string(date)
+ result = '' + date.strftime('%b').upcase + ' '
+ result += date.strftime('%d ')
+ result += date.strftime('%Y ')
+ result
+ end
+
+ end
+
+end
diff --git a/plugins/code_block.rb b/plugins/code_block.rb
new file mode 100644
index 0000000..539a347
--- /dev/null
+++ b/plugins/code_block.rb
@@ -0,0 +1,92 @@
+# Title: Simple Code Blocks for Jekyll
+# Author: Brandon Mathis http://brandonmathis.com
+# Description: Write codeblocks with semantic HTML5 and elements and optional syntax highlighting — all with a simple, intuitive interface.
+#
+# Syntax:
+# {% codeblock [title] [url] [link text] %}
+# code snippet
+# {% endcodeblock %}
+#
+# For syntax highlighting, put a file extension somewhere in the title. examples:
+# {% codeblock file.sh %}
+# code snippet
+# {% endcodeblock %}
+#
+# {% codeblock Time to be Awesome! (awesome.rb) %}
+# code snippet
+# {% endcodeblock %}
+#
+# Example:
+#
+# {% codeblock Got pain? painreleif.sh http://site.com/painreleief.sh Download it! %}
+# $ rm -rf ~/PAIN
+# {% endcodeblock %}
+#
+# Output:
+#
+#
+# Got pain? painrelief.sh Download it!
+#
+# -- nicely escaped highlighted code --
+#
+#
+#
+# Example 2 (no syntax highlighting):
+#
+# {% codeblock %}
+# Ooooh, sarcasm... How original!
+# {% endcodeblock %}
+#
+#
+# <sarcasm> Ooooh, sarcasm... How original!</sarcasm>
+#
+#
+require './plugins/pygments_code'
+require './plugins/raw'
+
+module Jekyll
+
+ class CodeBlock < Liquid::Block
+ CaptionUrlTitle = /(\S[\S\s]*)\s+(https?:\/\/\S+|\/\S+)\s*(.+)?/i
+ Caption = /(\S[\S\s]*)/
+ def initialize(tag_name, markup, tokens)
+ @title = nil
+ @caption = nil
+ @filetype = nil
+ @highlight = true
+ if markup =~ /\s*lang:(\S+)/i
+ @filetype = $1
+ markup = markup.sub(/\s*lang:(\S+)/i,'')
+ end
+ if markup =~ CaptionUrlTitle
+ @file = $1
+ @caption = "#{$1} #{$3 || 'link'} "
+ elsif markup =~ Caption
+ @file = $1
+ @caption = "#{$1} \n"
+ end
+ if @file =~ /\S[\S\s]*\w+\.(\w+)/ && @filetype.nil?
+ @filetype = $1
+ end
+ super
+ end
+
+ def render(context)
+ output = super
+ code = super
+ source = ""
+ source += @caption if @caption
+ if @filetype
+ source += "#{HighlightCode::highlight(code, @filetype)} "
+ else
+ source += "#{HighlightCode::tableize_code(code.lstrip.rstrip.gsub(/,'<'))} "
+ end
+ source = TemplateWrapper::safe_wrap(source)
+ source = context['pygments_prefix'] + source if context['pygments_prefix']
+ source = source + context['pygments_suffix'] if context['pygments_suffix']
+ source
+ end
+ end
+end
+
+Liquid::Template.register_tag('codeblock', Jekyll::CodeBlock)
diff --git a/plugins/config_tag.rb b/plugins/config_tag.rb
new file mode 100644
index 0000000..92d1f63
--- /dev/null
+++ b/plugins/config_tag.rb
@@ -0,0 +1,44 @@
+require 'json'
+
+class ConfigTag < Liquid::Tag
+ def initialize(tag_name, options, tokens)
+ super
+ options = options.split(' ').map {|i| i.strip }
+ @key = options.slice!(0)
+ @tag = nil
+ @classname = nil
+ options.each do |option|
+ @tag = $1 if option =~ /tag:(\S+)/
+ @classname = $1 if option =~ /classname:(\S+)/
+ end
+ end
+
+ def render(context)
+ config_tag(context.registers[:site].config, @key, @tag, @classname)
+ end
+end
+
+def config_tag(config, key, tag=nil, classname=nil)
+ options = key.split('.').map { |k| config[k] }.last #reference objects with dot notation
+ tag ||= 'div'
+ classname ||= key.sub(/_/, '-').sub(/\./, '-')
+ output = "<#{tag} class='#{classname}'"
+
+ if options.respond_to? 'keys'
+ options.each do |k,v|
+ unless v.nil?
+ v = v.join ',' if v.respond_to? 'join'
+ v = v.to_json if v.respond_to? 'keys'
+ output += " data-#{k.sub'_','-'}='#{v}'"
+ end
+ end
+ elsif options.respond_to? 'join'
+ output += " data-value='#{config[key].join(',')}'"
+ else
+ output += " data-value='#{config[key]}'"
+ end
+ output += ">#{tag}>"
+end
+
+Liquid::Template.register_tag('config_tag', ConfigTag)
+
diff --git a/plugins/gist_tag.rb b/plugins/gist_tag.rb
new file mode 100644
index 0000000..5120115
--- /dev/null
+++ b/plugins/gist_tag.rb
@@ -0,0 +1,130 @@
+# A Liquid tag for Jekyll sites that allows embedding Gists and showing code for non-JavaScript enabled browsers and readers.
+# by: Brandon Tilly
+# Source URL: https://gist.github.com/1027674
+# Post http://brandontilley.com/2011/01/31/gist-tag-for-jekyll.html
+#
+# Example usage: {% gist 1027674 gist_tag.rb %} //embeds a gist for this plugin
+
+require 'cgi'
+require 'digest/md5'
+require 'net/https'
+require 'uri'
+
+module Jekyll
+ class GistTag < Liquid::Tag
+ def initialize(tag_name, text, token)
+ super
+ @text = text
+ @cache_disabled = false
+ @cache_folder = File.expand_path "../.gist-cache", File.dirname(__FILE__)
+ FileUtils.mkdir_p @cache_folder
+ end
+
+ def render(context)
+ if parts = @text.match(/([a-zA-Z\d]*) (.*)/)
+ gist, file = parts[1].strip, parts[2].strip
+ else
+ gist, file = @text.strip, ""
+ end
+ if gist.empty?
+ ""
+ else
+ script_url = script_url_for gist, file
+ code = get_cached_gist(gist, file) || get_gist_from_web(gist, file)
+ html_output_for script_url, code
+ end
+ end
+
+ def html_output_for(script_url, code)
+ code = CGI.escapeHTML code
+ <<-HTML
+
+ HTML
+ end
+
+ def script_url_for(gist_id, filename)
+ url = "https://gist.github.com/#{gist_id}.js"
+ url = "#{url}?file=#{filename}" unless filename.nil? or filename.empty?
+ url
+ end
+
+ def get_gist_url_for(gist, file)
+ "https://gist.githubusercontent.com/raw/#{gist}/#{file}"
+ end
+
+ def cache(gist, file, data)
+ cache_file = get_cache_file_for gist, file
+ File.open(cache_file, "w") do |io|
+ io.write data
+ end
+ end
+
+ def get_cached_gist(gist, file)
+ return nil if @cache_disabled
+ cache_file = get_cache_file_for gist, file
+ File.read cache_file if File.exist? cache_file
+ end
+
+ def get_cache_file_for(gist, file)
+ bad_chars = /[^a-zA-Z0-9\-_.]/
+ gist = gist.gsub bad_chars, ''
+ file = file.gsub bad_chars, ''
+ md5 = Digest::MD5.hexdigest "#{gist}-#{file}"
+ File.join @cache_folder, "#{gist}-#{file}-#{md5}.cache"
+ end
+
+ def get_gist_from_web(gist, file)
+ gist_url = get_gist_url_for(gist, file)
+ data = get_web_content(gist_url)
+
+ locations = Array.new
+ while (data.code.to_i == 301 || data.code.to_i == 302)
+ data = handle_gist_redirecting(data)
+ break if locations.include? data.header['Location']
+ locations << data.header['Location']
+ end
+
+ if data.code.to_i != 200
+ raise RuntimeError, "Gist replied with #{data.code} for #{gist_url}"
+ end
+
+ cache(gist, file, data.body) unless @cache_disabled
+ data.body
+ end
+
+ def handle_gist_redirecting(data)
+ redirected_url = data.header['Location']
+ if redirected_url.nil? || redirected_url.empty?
+ raise ArgumentError, "GitHub replied with a 302 but didn't provide a location in the response headers."
+ end
+
+ get_web_content(redirected_url)
+ end
+
+ def get_web_content(url)
+ raw_uri = URI.parse url
+ proxy = ENV['http_proxy']
+ if proxy
+ proxy_uri = URI.parse(proxy)
+ https = Net::HTTP::Proxy(proxy_uri.host, proxy_uri.port).new raw_uri.host, raw_uri.port
+ else
+ https = Net::HTTP.new raw_uri.host, raw_uri.port
+ end
+ https.use_ssl = true
+ https.verify_mode = OpenSSL::SSL::VERIFY_NONE
+ request = Net::HTTP::Get.new raw_uri.request_uri
+ data = https.request request
+ end
+ end
+
+ class GistTagNoCache < GistTag
+ def initialize(tag_name, text, token)
+ super
+ @cache_disabled = true
+ end
+ end
+end
+
+Liquid::Template.register_tag('gist', Jekyll::GistTag)
+Liquid::Template.register_tag('gistnocache', Jekyll::GistTagNoCache)
diff --git a/plugins/haml.rb b/plugins/haml.rb
new file mode 100644
index 0000000..7e548de
--- /dev/null
+++ b/plugins/haml.rb
@@ -0,0 +1,24 @@
+module Jekyll
+ require 'haml'
+ class HamlConverter < Converter
+ safe true
+ priority :low
+
+ def matches(ext)
+ ext =~ /haml/i
+ end
+
+ def output_ext(ext)
+ ".html"
+ end
+
+ def convert(content)
+ begin
+ engine = Haml::Engine.new(content)
+ engine.render
+ rescue StandardError => e
+ puts "!!! HAML Error: " + e.message
+ end
+ end
+ end
+end
diff --git a/plugins/image_tag.rb b/plugins/image_tag.rb
new file mode 100644
index 0000000..4567000
--- /dev/null
+++ b/plugins/image_tag.rb
@@ -0,0 +1,50 @@
+# Title: Simple Image tag for Jekyll
+# Authors: Brandon Mathis http://brandonmathis.com
+# Felix Schäfer, Frederic Hemberger
+# Description: Easily output images with optional class names, width, height, title and alt attributes
+#
+# Syntax {% img [class name(s)] [http[s]:/]/path/to/image [width [height]] [title text | "title text" ["alt text"]] %}
+#
+# Examples:
+# {% img /images/ninja.png Ninja Attack! %}
+# {% img left half http://site.com/images/ninja.png Ninja Attack! %}
+# {% img left half http://site.com/images/ninja.png 150 150 "Ninja Attack!" "Ninja in attack posture" %}
+#
+# Output:
+#
+#
+#
+#
+
+module Jekyll
+
+ class ImageTag < Liquid::Tag
+ @img = nil
+
+ def initialize(tag_name, markup, tokens)
+ attributes = ['class', 'src', 'width', 'height', 'title']
+
+ if markup =~ /(?\S.*\s+)?(?(?:https?:\/\/|\/|\S+\/)\S+)(?:\s+(?\d+))?(?:\s+(?\d+))?(?\s+.+)?/i
+ @img = attributes.reduce({}) { |img, attr| img[attr] = $~[attr].strip if $~[attr]; img }
+ if /(?:"|')(?[^"']+)?(?:"|')\s+(?:"|')(?[^"']+)?(?:"|')/ =~ @img['title']
+ @img['title'] = title
+ @img['alt'] = alt
+ else
+ @img['alt'] = @img['title'].gsub!(/"/, '"') if @img['title']
+ end
+ @img['class'].gsub!(/"/, '') if @img['class']
+ end
+ super
+ end
+
+ def render(context)
+ if @img
+ " "
+ else
+ "Error processing input, expected syntax: {% img [class name(s)] [http[s]:/]/path/to/image [width [height]] [title text | \"title text\" [\"alt text\"]] %}"
+ end
+ end
+ end
+end
+
+Liquid::Template.register_tag('img', Jekyll::ImageTag)
diff --git a/plugins/include_array.rb b/plugins/include_array.rb
new file mode 100644
index 0000000..000040f
--- /dev/null
+++ b/plugins/include_array.rb
@@ -0,0 +1,58 @@
+# Title: Include Array Tag for Jekyll
+# Author: Jason Woodward http://www.woodwardjd.com
+# Description: Import files on your filesystem as specified in a configuration variable in _config.yml. Mostly cribbed from Jekyll's include tag.
+# Syntax: {% include_array variable_name_from_config.yml %}
+#
+# Example 1:
+# {% include_array asides %}
+#
+# _config.yml snippet:
+# asides: [asides/twitter.html, asides/custom/my_picture.html]
+#
+module Jekyll
+
+ class IncludeArrayTag < Liquid::Tag
+ Syntax = /(#{Liquid::QuotedFragment}+)/
+ def initialize(tag_name, markup, tokens)
+ if markup =~ Syntax
+ @array_name = $1
+ else
+ raise SyntaxError.new("Error in tag 'include_array' - Valid syntax: include_array [array from _config.yml]")
+ end
+
+ super
+ end
+
+ def render(context)
+ includes_dir = File.join(context.registers[:site].source, '_includes')
+
+ if File.symlink?(includes_dir)
+ return "Includes directory '#{includes_dir}' cannot be a symlink"
+ end
+
+ rtn = ''
+ (context.environments.first['site'][@array_name] || []).each do |file|
+ if file !~ /^[a-zA-Z0-9_\/\.-]+$/ || file =~ /\.\// || file =~ /\/\./
+ rtn = rtn + "Include file '#{file}' contains invalid characters or sequences"
+ end
+
+ Dir.chdir(includes_dir) do
+ choices = Dir['**/*'].reject { |x| File.symlink?(x) }
+ if choices.include?(file)
+ source = File.read(file)
+ partial = Liquid::Template.parse(source)
+ context.stack do
+ rtn = rtn + partial.render(context)
+ end
+ else
+ rtn = rtn + "Included file '#{file}' not found in _includes directory"
+ end
+ end
+ end
+ rtn
+ end
+ end
+
+end
+
+Liquid::Template.register_tag('include_array', Jekyll::IncludeArrayTag)
diff --git a/plugins/include_code.rb b/plugins/include_code.rb
new file mode 100644
index 0000000..a61d06c
--- /dev/null
+++ b/plugins/include_code.rb
@@ -0,0 +1,71 @@
+# Title: Include Code Tag for Jekyll
+# Author: Brandon Mathis http://brandonmathis.com
+# Description: Import files on your filesystem into any blog post as embedded code snippets with syntax highlighting and a download link.
+# Configuration: You can set default import path in _config.yml (defaults to code_dir: downloads/code)
+#
+# Syntax {% include_code path/to/file %}
+#
+# Example 1:
+# {% include_code javascripts/test.js %}
+#
+# This will import test.js from source/downloads/code/javascripts/test.js
+# and output the contents in a syntax highlighted code block inside a figure,
+# with a figcaption listing the file name and download link
+#
+# Example 2:
+# You can also include an optional title for the
+#
+# {% include_code Example 2 javascripts/test.js %}
+#
+# will output a figcaption with the title: Example 2 (test.js)
+#
+
+require './plugins/pygments_code'
+require './plugins/raw'
+require 'pathname'
+
+module Jekyll
+
+ class IncludeCodeTag < Liquid::Tag
+ def initialize(tag_name, markup, tokens)
+ @title = nil
+ @file = nil
+ if markup.strip =~ /\s*lang:(\S+)/i
+ @filetype = $1
+ markup = markup.strip.sub(/lang:\S+/i,'')
+ end
+ if markup.strip =~ /(.*)?(\s+|^)(\/*\S+)/i
+ @title = $1 || nil
+ @file = $3
+ end
+ super
+ end
+
+ def render(context)
+ code_dir = (context.registers[:site].config['code_dir'].sub(/^\//,'') || 'downloads/code')
+ code_path = (Pathname.new(context.registers[:site].source) + code_dir).expand_path
+ file = code_path + @file
+
+ if File.symlink?(code_path)
+ return "Code directory '#{code_path}' cannot be a symlink"
+ end
+
+ unless file.file?
+ return "File #{file} could not be found"
+ end
+
+ Dir.chdir(code_path) do
+ code = file.read
+ @filetype = file.extname.sub('.','') if @filetype.nil?
+ title = @title ? "#{@title} (#{file.basename})" : file.basename
+ url = "/#{code_dir}/#{@file}"
+ source = "#{title} download \n"
+ source += "#{HighlightCode::highlight(code, @filetype)} "
+ TemplateWrapper::safe_wrap(source)
+ end
+ end
+ end
+
+end
+
+Liquid::Template.register_tag('include_code', Jekyll::IncludeCodeTag)
diff --git a/plugins/jsfiddle.rb b/plugins/jsfiddle.rb
new file mode 100644
index 0000000..815910e
--- /dev/null
+++ b/plugins/jsfiddle.rb
@@ -0,0 +1,40 @@
+# Title: jsFiddle tag for Jekyll
+# Author: Brian Arnold (@brianarn)
+# Description:
+# Given a jsFiddle shortcode, outputs the jsFiddle iframe code.
+# Using 'default' will preserve defaults as specified by jsFiddle.
+#
+# Syntax: {% jsfiddle shorttag [tabs] [skin] [height] [width] %}
+#
+# Examples:
+#
+# Input: {% jsfiddle ccWP7 %}
+# Output:
+#
+# Input: {% jsfiddle ccWP7 js,html,result %}
+# Output:
+#
+
+module Jekyll
+ class JsFiddle < Liquid::Tag
+ def initialize(tag_name, markup, tokens)
+ if /(?\w+\/?\d?)(?:\s+(?[\w,]+))?(?:\s+(?\w+))?(?:\s+(?\w+))?(?:\s+(?\w+))?/ =~ markup
+ @fiddle = fiddle
+ @sequence = (sequence unless sequence == 'default') || 'js,resources,html,css,result'
+ @skin = (skin unless skin == 'default') || 'light'
+ @width = width || '100%'
+ @height = height || '300px'
+ end
+ end
+
+ def render(context)
+ if @fiddle
+ ""
+ else
+ "Error processing input, expected syntax: {% jsfiddle shorttag [tabs] [skin] [height] [width] %}"
+ end
+ end
+ end
+end
+
+Liquid::Template.register_tag('jsfiddle', Jekyll::JsFiddle)
diff --git a/plugins/octopress_filters.rb b/plugins/octopress_filters.rb
new file mode 100644
index 0000000..9c7fa6c
--- /dev/null
+++ b/plugins/octopress_filters.rb
@@ -0,0 +1,142 @@
+#custom filters for Octopress
+require './plugins/backtick_code_block'
+require 'octopress-hooks'
+require 'jekyll-sitemap'
+require 'octopress-date-format'
+require './plugins/raw'
+require 'rubypants'
+
+module OctopressFilters
+ def self.pre_filter(page)
+ if page.ext.match('html|textile|markdown|md|haml|slim|xml')
+ input = BacktickCodeBlock::render_code_block(page.content)
+ page.content = input.gsub /(.+?<\/figure>)/m do
+ TemplateWrapper::safe_wrap($1)
+ end
+ end
+ end
+ def self.post_filter(page)
+ if page.ext.match('html|textile|markdown|md|haml|slim|xml')
+ page.output = TemplateWrapper::unwrap(page.output)
+ end
+
+ page.output = RubyPants.new(page.output).to_html
+ end
+
+ class PageFilters < Octopress::Hooks::Page
+ def pre_render(page)
+ OctopressFilters::pre_filter(page)
+ end
+
+ def post_render(page)
+ OctopressFilters::post_filter(page)
+ end
+ end
+
+ class PostFilters < Octopress::Hooks::Post
+ def pre_render(post)
+ OctopressFilters::pre_filter(post)
+ end
+
+ def post_render(post)
+ OctopressFilters::post_filter(post)
+ end
+ end
+end
+
+
+module OctopressLiquidFilters
+
+ # Used on the blog index to split posts on the marker
+ def excerpt(input)
+ if input.index(//i)
+ input.split(//i)[0]
+ else
+ input
+ end
+ end
+
+ # Checks for excerpts (helpful for template conditionals)
+ def has_excerpt(input)
+ input =~ //i ? true : false
+ end
+
+ # Summary is used on the Archive pages to return the first block of content from a post.
+ def summary(input)
+ if input.index(/\n\n/)
+ input.split(/\n\n/)[0]
+ else
+ input
+ end
+ end
+
+ # Extracts raw content DIV from template, used for page description as {{ content }}
+ # contains complete sub-template code on main page level
+ def raw_content(input)
+ /(?
[\s\S]*?)<\/div>\s*<(footer|\/article)>/ =~ input
+ return (content.nil?) ? input : content
+ end
+
+ # Escapes CDATA sections in post content
+ def cdata_escape(input)
+ input.gsub(//, ']]>')
+ end
+
+ # Replaces relative urls with full urls
+ def expand_urls(input, url='')
+ url ||= '/'
+ input.gsub /(\s+(href|src)\s*=\s*["|']{1})(\/[^\/>]{1}[^\"'>]*)/ do
+ $1+url+$3
+ end
+ end
+
+ # Improved version of Liquid's truncate:
+ # - Doesn't cut in the middle of a word.
+ # - Uses typographically correct ellipsis (…) insted of '...'
+ def truncate(input, length)
+ if input.length > length && input[0..(length-1)] =~ /(.+)\b.+$/im
+ $1.strip + ' …'
+ else
+ input
+ end
+ end
+
+ # Improved version of Liquid's truncatewords:
+ # - Uses typographically correct ellipsis (…) insted of '...'
+ def truncatewords(input, length)
+ truncate = input.split(' ')
+ if truncate.length > length
+ truncate[0..length-1].join(' ').strip + ' …'
+ else
+ input
+ end
+ end
+
+ # Condenses multiple spaces and tabs into a single space
+ def condense_spaces(input)
+ input.gsub(/\s{2,}/, ' ')
+ end
+
+ # Removes trailing forward slash from a string for easily appending url segments
+ def strip_slash(input)
+ if input =~ /(.+)\/$|^\/$/
+ input = $1
+ end
+ input
+ end
+
+ # Returns a url without the protocol (http://)
+ def shorthand_url(input)
+ input.gsub /(https?:\/\/)(\S+)/ do
+ $2
+ end
+ end
+
+ # Returns a title cased string based on John Gruber's title case http://daringfireball.net/2008/08/title_case_update
+ def titlecase(input)
+ input.titlecase
+ end
+
+end
+Liquid::Template.register_filter OctopressLiquidFilters
+
diff --git a/plugins/pullquote.rb b/plugins/pullquote.rb
new file mode 100644
index 0000000..3c65e66
--- /dev/null
+++ b/plugins/pullquote.rb
@@ -0,0 +1,45 @@
+#
+# Author: Brandon Mathis
+# Based on the semantic pullquote technique by Maykel Loomans at http://miekd.com/articles/pull-quotes-with-html5-and-css/
+#
+# Outputs a span with a data-pullquote attribute set from the marked pullquote. Example:
+#
+# {% pullquote %}
+# When writing longform posts, I find it helpful to include pullquotes, which help those scanning a post discern whether or not a post is helpful.
+# It is important to note, {" pullquotes are merely visual in presentation and should not appear twice in the text. "} That is why it is prefered
+# to use a CSS only technique for styling pullquotes.
+# {% endpullquote %}
+# ...will output...
+#
+#
+# When writing longform posts, I find it helpful to include pullquotes, which help those scanning a post discern whether or not a post is helpful.
+# It is important to note, pullquotes are merely visual in presentation and should not appear twice in the text. This is why a CSS only approach
+# for styling pullquotes is prefered.
+#
+#
+#
+# {% pullquote left %} will create a left-aligned pullquote instead.
+#
+# Note: this plugin now creates pullquotes with the class of pullquote-right by default
+
+module Jekyll
+
+ class PullquoteTag < Liquid::Block
+ def initialize(tag_name, markup, tokens)
+ @align = (markup =~ /left/i) ? "left" : "right"
+ super
+ end
+
+ def render(context)
+ output = super
+ if output =~ /\{"\s*(.+?)\s*"\}/m
+ @quote = RubyPants.new($1).to_html
+ "#{output.gsub(/\{"\s*|\s*"\}/, '')} "
+ else
+ return "Surround your pullquote like this {\" text to be quoted \"}"
+ end
+ end
+ end
+end
+
+Liquid::Template.register_tag('pullquote', Jekyll::PullquoteTag)
diff --git a/plugins/pygments_code.rb b/plugins/pygments_code.rb
new file mode 100644
index 0000000..c0f4de9
--- /dev/null
+++ b/plugins/pygments_code.rb
@@ -0,0 +1,45 @@
+require 'pygments'
+require 'fileutils'
+require 'digest/md5'
+
+PYGMENTS_CACHE_DIR = File.expand_path('../../.pygments-cache', __FILE__)
+FileUtils.mkdir_p(PYGMENTS_CACHE_DIR)
+
+module HighlightCode
+ def self.highlight(str, lang)
+ lang = 'ruby' if lang == 'ru'
+ lang = 'objc' if lang == 'm'
+ lang = 'perl' if lang == 'pl'
+ lang = 'yaml' if lang == 'yml'
+ str = pygments(str, lang).match(/(.+)<\/pre>/m)[1].to_s.gsub(/ *$/, '') #strip out divs
+ tableize_code(str, lang)
+ end
+
+ def self.pygments(code, lang)
+ if defined?(PYGMENTS_CACHE_DIR)
+ path = File.join(PYGMENTS_CACHE_DIR, "#{lang}-#{Digest::MD5.hexdigest(code)}.html")
+ if File.exist?(path)
+ highlighted_code = File.read(path)
+ else
+ begin
+ highlighted_code = Pygments.highlight(code, :lexer => lang, :formatter => 'html', :options => {:encoding => 'utf-8', :startinline => true})
+ rescue MentosError
+ raise "Pygments can't parse unknown language: #{lang}."
+ end
+ File.open(path, 'w') {|f| f.print(highlighted_code) }
+ end
+ else
+ highlighted_code = Pygments.highlight(code, :lexer => lang, :formatter => 'html', :options => {:encoding => 'utf-8', :startinline => true})
+ end
+ highlighted_code
+ end
+ def self.tableize_code (str, lang = '')
+ table = '
'
+ code = ''
+ str.lines.each_with_index do |line,index|
+ table += "#{index+1} \n"
+ code += "#{line} "
+ end
+ table += " #{code}
"
+ end
+end
diff --git a/plugins/raw.rb b/plugins/raw.rb
new file mode 100644
index 0000000..e97c945
--- /dev/null
+++ b/plugins/raw.rb
@@ -0,0 +1,40 @@
+# Author: Brandon Mathis
+# Description: Provides plugins with a method for wrapping and unwrapping input to prevent Markdown and Textile from parsing it.
+# Purpose: This is useful for preventing Markdown and Textile from being too aggressive and incorrectly parsing in-line HTML.
+module TemplateWrapper
+ # Wrap input with a
+ def self.safe_wrap(input)
+ "
#{input}
"
+ end
+ # This must be applied after the
+ def self.unwrap(input)
+ input.gsub /
(.+?)<\/notextile><\/div>/m do
+ $1
+ end
+ end
+end
+
+# Author: phaer, https://github.com/phaer
+# Source: https://gist.github.com/1020852
+# Description: Raw tag for jekyll. Keeps liquid from parsing text betweeen {% raw %} and {% endraw %}
+
+module Jekyll
+ class RawTag < Liquid::Block
+ def parse(tokens)
+ @nodelist ||= []
+ @nodelist.clear
+
+ while token = tokens.shift
+ if token =~ FullToken
+ if block_delimiter == $1
+ end_tag
+ return
+ end
+ end
+ @nodelist << token if not token.empty?
+ end
+ end
+ end
+end
+
+Liquid::Template.register_tag('raw', Jekyll::RawTag)
diff --git a/plugins/render_partial.rb b/plugins/render_partial.rb
new file mode 100644
index 0000000..b6ebfe8
--- /dev/null
+++ b/plugins/render_partial.rb
@@ -0,0 +1,69 @@
+# Title: Render Partial Tag for Jekyll
+# Author: Brandon Mathis http://brandonmathis.com
+# Description: Import files on your filesystem into any blog post and render them inline.
+# Note: Paths are relative to the source directory, if you import a file with yaml front matter, the yaml will be stripped out.
+#
+# Syntax {% render_partial path/to/file %}
+#
+# Example 1:
+# {% render_partial about/_bio.markdown %}
+#
+# This will import source/about/_bio.markdown and render it inline.
+# In this example I used an underscore at the beginning of the filename to prevent Jekyll
+# from generating an about/bio.html (Jekyll doesn't convert files beginning with underscores)
+#
+# Example 2:
+# {% render_partial ../README.markdown %}
+#
+# You can use relative pathnames, to include files outside of the source directory.
+# This might be useful if you want to have a page for a project's README without having
+# to duplicated the contents
+#
+#
+
+require 'pathname'
+require './plugins/octopress_filters'
+
+module Jekyll
+
+ class RenderPartialTag < Liquid::Tag
+ include OctopressFilters
+ def initialize(tag_name, markup, tokens)
+ @file = nil
+ @raw = false
+ if markup =~ /^(\S+)\s?(\w+)?/
+ @file = $1.strip
+ @raw = $2 == 'raw'
+ end
+ super
+ end
+
+ def render(context)
+ file_dir = (context.registers[:site].source || 'source')
+ file_path = Pathname.new(file_dir).expand_path
+ file = file_path + @file
+
+ unless file.file?
+ return "File #{file} could not be found"
+ end
+
+ Dir.chdir(file_path) do
+ contents = file.read
+ if contents =~ /\A-{3}.+[^\A]-{3}\n(.+)/m
+ contents = $1.lstrip
+ end
+ contents = pre_filter(contents)
+ if @raw
+ contents
+ else
+ partial = Liquid::Template.parse(contents)
+ context.stack do
+ partial.render(context)
+ end
+ end
+ end
+ end
+ end
+end
+
+Liquid::Template.register_tag('render_partial', Jekyll::RenderPartialTag)
diff --git a/plugins/rubypants.rb b/plugins/rubypants.rb
new file mode 100644
index 0000000..e4f4502
--- /dev/null
+++ b/plugins/rubypants.rb
@@ -0,0 +1,489 @@
+#
+# = RubyPants -- SmartyPants ported to Ruby
+#
+# Ported by Christian Neukirchen
+# Copyright (C) 2004 Christian Neukirchen
+#
+# Incooporates ideas, comments and documentation by Chad Miller
+# Copyright (C) 2004 Chad Miller
+#
+# Original SmartyPants by John Gruber
+# Copyright (C) 2003 John Gruber
+#
+
+#
+# = RubyPants -- SmartyPants ported to Ruby
+#
+# == Synopsis
+#
+# RubyPants is a Ruby port of the smart-quotes library SmartyPants.
+#
+# The original "SmartyPants" is a free web publishing plug-in for
+# Movable Type, Blosxom, and BBEdit that easily translates plain ASCII
+# punctuation characters into "smart" typographic punctuation HTML
+# entities.
+#
+#
+# == Description
+#
+# RubyPants can perform the following transformations:
+#
+# * Straight quotes (" and ' ) into "curly" quote
+# HTML entities
+# * Backticks-style quotes (``like this'' ) into "curly" quote
+# HTML entities
+# * Dashes (-- and --- ) into en- and em-dash
+# entities
+# * Three consecutive dots (... or . . . ) into an
+# ellipsis entity
+#
+# This means you can write, edit, and save your posts using plain old
+# ASCII straight quotes, plain dashes, and plain dots, but your
+# published posts (and final HTML output) will appear with smart
+# quotes, em-dashes, and proper ellipses.
+#
+# RubyPants does not modify characters within ,
+#
, , or
+# tag blocks. Typically, these tags are used to
+# display text where smart quotes and other "smart punctuation" would
+# not be appropriate, such as source code or example markup.
+#
+#
+# == Backslash Escapes
+#
+# If you need to use literal straight quotes (or plain hyphens and
+# periods), RubyPants accepts the following backslash escape sequences
+# to force non-smart punctuation. It does so by transforming the
+# escape sequence into a decimal-encoded HTML entity:
+#
+# \\ \" \' \. \- \`
+#
+# This is useful, for example, when you want to use straight quotes as
+# foot and inch marks: 6'2" tall; a 17" iMac. (Use 6\'2\"
+# resp. 17\" .)
+#
+#
+# == Algorithmic Shortcomings
+#
+# One situation in which quotes will get curled the wrong way is when
+# apostrophes are used at the start of leading contractions. For
+# example:
+#
+# 'Twas the night before Christmas.
+#
+# In the case above, RubyPants will turn the apostrophe into an
+# opening single-quote, when in fact it should be a closing one. I
+# don't think this problem can be solved in the general case--every
+# word processor I've tried gets this wrong as well. In such cases,
+# it's best to use the proper HTML entity for closing single-quotes
+# ("’ ") by hand.
+#
+#
+# == Bugs
+#
+# To file bug reports or feature requests (except see above) please
+# send email to: mailto:chneukirchen@gmail.com
+#
+# If the bug involves quotes being curled the wrong way, please send
+# example text to illustrate.
+#
+#
+# == Authors
+#
+# John Gruber did all of the hard work of writing this software in
+# Perl for Movable Type and almost all of this useful documentation.
+# Chad Miller ported it to Python to use with Pyblosxom.
+#
+# Christian Neukirchen provided the Ruby port, as a general-purpose
+# library that follows the *Cloth API.
+#
+#
+# == Copyright and License
+#
+# === SmartyPants license:
+#
+# Copyright (c) 2003 John Gruber
+# (http://daringfireball.net)
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# * Neither the name "SmartyPants" nor the names of its contributors
+# may be used to endorse or promote products derived from this
+# software without specific prior written permission.
+#
+# This software is provided by the copyright holders and contributors
+# "as is" and any express or implied warranties, including, but not
+# limited to, the implied warranties of merchantability and fitness
+# for a particular purpose are disclaimed. In no event shall the
+# copyright owner or contributors be liable for any direct, indirect,
+# incidental, special, exemplary, or consequential damages (including,
+# but not limited to, procurement of substitute goods or services;
+# loss of use, data, or profits; or business interruption) however
+# caused and on any theory of liability, whether in contract, strict
+# liability, or tort (including negligence or otherwise) arising in
+# any way out of the use of this software, even if advised of the
+# possibility of such damage.
+#
+# === RubyPants license
+#
+# RubyPants is a derivative work of SmartyPants and smartypants.py.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# This software is provided by the copyright holders and contributors
+# "as is" and any express or implied warranties, including, but not
+# limited to, the implied warranties of merchantability and fitness
+# for a particular purpose are disclaimed. In no event shall the
+# copyright owner or contributors be liable for any direct, indirect,
+# incidental, special, exemplary, or consequential damages (including,
+# but not limited to, procurement of substitute goods or services;
+# loss of use, data, or profits; or business interruption) however
+# caused and on any theory of liability, whether in contract, strict
+# liability, or tort (including negligence or otherwise) arising in
+# any way out of the use of this software, even if advised of the
+# possibility of such damage.
+#
+#
+# == Links
+#
+# John Gruber:: http://daringfireball.net
+# SmartyPants:: http://daringfireball.net/projects/smartypants
+#
+# Chad Miller:: http://web.chad.org
+#
+# Christian Neukirchen:: http://kronavita.de/chris
+#
+
+
+class RubyPants < String
+
+ # Create a new RubyPants instance with the text in +string+.
+ #
+ # Allowed elements in the options array:
+ #
+ # 0 :: do nothing
+ # 1 :: enable all, using only em-dash shortcuts
+ # 2 :: enable all, using old school en- and em-dash shortcuts (*default*)
+ # 3 :: enable all, using inverted old school en and em-dash shortcuts
+ # -1 :: stupefy (translate HTML entities to their ASCII-counterparts)
+ #
+ # If you don't like any of these defaults, you can pass symbols to change
+ # RubyPants' behavior:
+ #
+ # :quotes :: quotes
+ # :backticks :: backtick quotes (``double'' only)
+ # :allbackticks :: backtick quotes (``double'' and `single')
+ # :dashes :: dashes
+ # :oldschool :: old school dashes
+ # :inverted :: inverted old school dashes
+ # :ellipses :: ellipses
+ # :convertquotes :: convert " entities to
+ # " for Dreamweaver users
+ # :stupefy :: translate RubyPants HTML entities
+ # to their ASCII counterparts.
+ #
+ def initialize(string, options=[2])
+ super string
+ @options = [*options]
+ end
+
+ # Apply SmartyPants transformations.
+ def to_html
+ do_quotes = do_backticks = do_dashes = do_ellipses = do_stupify = nil
+ convert_quotes = false
+
+ if @options.include? 0
+ # Do nothing.
+ return self
+ elsif @options.include? 1
+ # Do everything, turn all options on.
+ do_quotes = do_backticks = do_ellipses = true
+ do_dashes = :normal
+ elsif @options.include? 2
+ # Do everything, turn all options on, use old school dash shorthand.
+ do_quotes = do_backticks = do_ellipses = true
+ do_dashes = :oldschool
+ elsif @options.include? 3
+ # Do everything, turn all options on, use inverted old school
+ # dash shorthand.
+ do_quotes = do_backticks = do_ellipses = true
+ do_dashes = :inverted
+ elsif @options.include?(-1)
+ do_stupefy = true
+ else
+ do_quotes = @options.include? :quotes
+ do_backticks = @options.include? :backticks
+ do_backticks = :both if @options.include? :allbackticks
+ do_dashes = :normal if @options.include? :dashes
+ do_dashes = :oldschool if @options.include? :oldschool
+ do_dashes = :inverted if @options.include? :inverted
+ do_ellipses = @options.include? :ellipses
+ convert_quotes = @options.include? :convertquotes
+ do_stupefy = @options.include? :stupefy
+ end
+
+ # Parse the HTML
+ tokens = tokenize
+
+ # Keep track of when we're inside or tags.
+ in_pre = false
+
+ # Here is the result stored in.
+ result = ""
+
+ # This is a cheat, used to get some context for one-character
+ # tokens that consist of just a quote char. What we do is remember
+ # the last character of the previous text token, to use as context
+ # to curl single- character quote tokens correctly.
+ prev_token_last_char = nil
+
+ tokens.each { |token|
+ if token.first == :tag
+ result << token[1]
+ if token[1] =~ %r!<(/?)(?:pre|code|kbd|script|math)[\s>]!
+ in_pre = ($1 != "/") # Opening or closing tag?
+ end
+ else
+ t = token[1]
+
+ # Remember last char of this token before processing.
+ last_char = t[-1].chr
+
+ unless in_pre
+ t = process_escapes t
+
+ t.gsub!(/"/, '"') if convert_quotes
+
+ if do_dashes
+ t = educate_dashes t if do_dashes == :normal
+ t = educate_dashes_oldschool t if do_dashes == :oldschool
+ t = educate_dashes_inverted t if do_dashes == :inverted
+ end
+
+ t = educate_ellipses t if do_ellipses
+
+ # Note: backticks need to be processed before quotes.
+ if do_backticks
+ t = educate_backticks t
+ t = educate_single_backticks t if do_backticks == :both
+ end
+
+ if do_quotes
+ if t == "'"
+ # Special case: single-character ' token
+ if prev_token_last_char =~ /\S/
+ t = "’"
+ else
+ t = "‘"
+ end
+ elsif t == '"'
+ # Special case: single-character " token
+ if prev_token_last_char =~ /\S/
+ t = "”"
+ else
+ t = "“"
+ end
+ else
+ # Normal case:
+ t = educate_quotes t
+ end
+ end
+
+ t = stupefy_entities t if do_stupefy
+ end
+
+ prev_token_last_char = last_char
+ result << t
+ end
+ }
+
+ # Done
+ result
+ end
+
+ protected
+
+ # Return the string, with after processing the following backslash
+ # escape sequences. This is useful if you want to force a "dumb" quote
+ # or other character to appear.
+ #
+ # Escaped are:
+ # \\ \" \' \. \- \`
+ #
+ def process_escapes(str)
+ str.gsub('\\\\', '\').
+ gsub('\"', '"').
+ gsub("\\\'", ''').
+ gsub('\.', '.').
+ gsub('\-', '-').
+ gsub('\`', '`')
+ end
+
+ # The string, with each instance of "-- " translated to an
+ # em-dash HTML entity.
+ #
+ def educate_dashes(str)
+ str.gsub(/--/, '—')
+ end
+
+ # The string, with each instance of "-- " translated to an
+ # en-dash HTML entity, and each "--- " translated to an
+ # em-dash HTML entity.
+ #
+ def educate_dashes_oldschool(str)
+ str.gsub(/---/, '—').gsub(/--/, '–')
+ end
+
+ # Return the string, with each instance of "-- " translated
+ # to an em-dash HTML entity, and each "--- " translated to
+ # an en-dash HTML entity. Two reasons why: First, unlike the en- and
+ # em-dash syntax supported by +educate_dashes_oldschool+, it's
+ # compatible with existing entries written before SmartyPants 1.1,
+ # back when "-- " was only used for em-dashes. Second,
+ # em-dashes are more common than en-dashes, and so it sort of makes
+ # sense that the shortcut should be shorter to type. (Thanks to
+ # Aaron Swartz for the idea.)
+ #
+ def educate_dashes_inverted(str)
+ str.gsub(/---/, '–').gsub(/--/, '—')
+ end
+
+ # Return the string, with each instance of "... " translated
+ # to an ellipsis HTML entity. Also converts the case where there are
+ # spaces between the dots.
+ #
+ def educate_ellipses(str)
+ str.gsub('...', '…').gsub('. . .', '…')
+ end
+
+ # Return the string, with "``backticks'' "-style single quotes
+ # translated into HTML curly quote entities.
+ #
+ def educate_backticks(str)
+ str.gsub("``", '“').gsub("''", '”')
+ end
+
+ # Return the string, with "`backticks' "-style single quotes
+ # translated into HTML curly quote entities.
+ #
+ def educate_single_backticks(str)
+ str.gsub("`", '‘').gsub("'", '’')
+ end
+
+ # Return the string, with "educated" curly quote HTML entities.
+ #
+ def educate_quotes(str)
+ punct_class = '[!"#\$\%\'()*+,\-.\/:;<=>?\@\[\\\\\]\^_`{|}~]'
+
+ str = str.dup
+
+ # Special case if the very first character is a quote followed by
+ # punctuation at a non-word-break. Close the quotes by brute
+ # force:
+ str.gsub!(/^'(?=#{punct_class}\B)/, '’')
+ str.gsub!(/^"(?=#{punct_class}\B)/, '”')
+
+ # Special case for double sets of quotes, e.g.:
+ # He said, "'Quoted' words in a larger quote."
+ str.gsub!(/"'(?=\w)/, '“‘')
+ str.gsub!(/'"(?=\w)/, '‘“')
+
+ # Special case for decade abbreviations (the '80s):
+ str.gsub!(/'(?=\d\ds)/, '’')
+
+ close_class = %![^\ \t\r\n\\[\{\(\-]!
+ dec_dashes = '–|—'
+
+ # Get most opening single quotes:
+ str.gsub!(/(\s| |--|&[mn]dash;|#{dec_dashes}|ȁ[34];)'(?=\w)/,
+ '\1‘')
+ # Single closing quotes:
+ str.gsub!(/(#{close_class})'/, '\1’')
+ str.gsub!(/'(\s|s\b|$)/, '’\1')
+ # Any remaining single quotes should be opening ones:
+ str.gsub!(/'/, '‘')
+
+ # Get most opening double quotes:
+ str.gsub!(/(\s| |--|&[mn]dash;|#{dec_dashes}|ȁ[34];)"(?=\w)/,
+ '\1“')
+ # Double closing quotes:
+ str.gsub!(/(#{close_class})"/, '\1”')
+ str.gsub!(/"(\s|s\b|$)/, '”\1')
+ # Any remaining quotes should be opening ones:
+ str.gsub!(/"/, '“')
+
+ str
+ end
+
+ # Return the string, with each RubyPants HTML entity translated to
+ # its ASCII counterpart.
+ #
+ # Note: This is not reversible (but exactly the same as in SmartyPants)
+ #
+ def stupefy_entities(str)
+ str.
+ gsub(/–/, '-'). # en-dash
+ gsub(/—/, '--'). # em-dash
+
+ gsub(/‘/, "'"). # open single quote
+ gsub(/’/, "'"). # close single quote
+
+ gsub(/“/, '"'). # open double quote
+ gsub(/”/, '"'). # close double quote
+
+ gsub(/…/, '...') # ellipsis
+ end
+
+ # Return an array of the tokens comprising the string. Each token is
+ # either a tag (possibly with nested, tags contained therein, such
+ # as , or a run of text between
+ # tags. Each element of the array is a two-element array; the first
+ # is either :tag or :text; the second is the actual value.
+ #
+ # Based on the _tokenize() subroutine from Brad Choate's
+ # MTRegex plugin.
+ #
+ # This is actually the easier variant using tag_soup, as used by
+ # Chad Miller in the Python port of SmartyPants.
+ #
+ def tokenize
+ tag_soup = /([^<]*)(<[^>]*>)/
+
+ tokens = []
+
+ prev_end = 0
+ scan(tag_soup) {
+ tokens << [:text, $1] if $1 != ""
+ tokens << [:tag, $2]
+
+ prev_end = $~.end(0)
+ }
+
+ if prev_end < size
+ tokens << [:text, self[prev_end..-1]]
+ end
+
+ tokens
+ end
+end
diff --git a/plugins/titlecase.rb b/plugins/titlecase.rb
new file mode 100644
index 0000000..7648932
--- /dev/null
+++ b/plugins/titlecase.rb
@@ -0,0 +1,36 @@
+class String
+ def titlecase
+ small_words = %w(a an and as at but by en for if in of on or the to v v. via vs vs.)
+
+ x = split(" ").map do |word|
+ # note: word could contain non-word characters!
+ # downcase all small_words, capitalize the rest
+ small_words.include?(word.gsub(/\W/, "").downcase) ? word.downcase! : word.smart_capitalize!
+ word
+ end
+ # capitalize first and last words
+ x.first.to_s.smart_capitalize!
+ x.last.to_s.smart_capitalize!
+ # small words are capitalized after colon, period, exclamation mark, question mark
+ x.join(" ").gsub(/(:|\.|!|\?)\s?(\W*#{small_words.join("|")}\W*)\s/) { "#{$1} #{$2.smart_capitalize} " }
+ end
+
+ def titlecase!
+ replace(titlecase)
+ end
+
+ def smart_capitalize
+ # ignore any leading crazy characters and capitalize the first real character
+ if self =~ /^['"\(\[']*([a-z])/
+ i = index($1)
+ x = self[i,self.length]
+ # word with capitals and periods mid-word are left alone
+ self[i,1] = self[i,1].upcase unless x =~ /[A-Z]/ or x =~ /\.\w+/
+ end
+ self
+ end
+
+ def smart_capitalize!
+ replace(smart_capitalize)
+ end
+end
diff --git a/plugins/video_tag.rb b/plugins/video_tag.rb
new file mode 100644
index 0000000..c6e67b7
--- /dev/null
+++ b/plugins/video_tag.rb
@@ -0,0 +1,56 @@
+# Title: Simple Video tag for Jekyll
+# Author: Brandon Mathis http://brandonmathis.com
+# Description: Easily output MPEG4 HTML5 video with a flash backup.
+#
+# Syntax {% video url/to/video [width height] [url/to/poster] %}
+#
+# Example:
+# {% video http://site.com/video.mp4 720 480 http://site.com/poster-frame.jpg %}
+#
+# Output:
+#
+#
+#
+#
+
+module Jekyll
+
+ class VideoTag < Liquid::Tag
+ @video = nil
+ @poster = ''
+ @height = ''
+ @width = ''
+
+ def initialize(tag_name, markup, tokens)
+ if markup =~ /(https?:\S+)(\s+(https?:\S+))?(\s+(https?:\S+))?(\s+(\d+)\s(\d+))?(\s+(https?:\S+))?/i
+ @video = [$1, $3, $5].compact
+ @width = $7
+ @height = $8
+ @poster = $10
+ end
+ super
+ end
+
+ def render(context)
+ output = super
+ type = {
+ 'mp4' => "type='video/mp4; codecs=\"avc1.42E01E, mp4a.40.2\"'",
+ 'ogv' => "type='video/ogg; codecs=theora, vorbis'",
+ 'webm' => "type='video/webm; codecs=vp8, vorbis'"
+ }
+ if @video.size > 0
+ video = ""
+ @video.each do |v|
+ t = v.match(/([^\.]+)$/)[1]
+ video += ""
+ end
+ video += " "
+ else
+ "Error processing input, expected syntax: {% video url/to/video [url/to/video] [url/to/video] [width height] [url/to/poster] %}"
+ end
+ end
+ end
+end
+
+Liquid::Template.register_tag('video', Jekyll::VideoTag)
+
diff --git a/stylesheets/pygment_trac.css b/stylesheets/pygment_trac.css
new file mode 100644
index 0000000..e65cedf
--- /dev/null
+++ b/stylesheets/pygment_trac.css
@@ -0,0 +1,70 @@
+.highlight .hll { background-color: #ffffcc }
+.highlight { background: #f0f3f3; }
+.highlight .c { color: #0099FF; font-style: italic } /* Comment */
+.highlight .err { color: #AA0000; background-color: #FFAAAA } /* Error */
+.highlight .k { color: #006699; font-weight: bold } /* Keyword */
+.highlight .o { color: #555555 } /* Operator */
+.highlight .cm { color: #0099FF; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #009999 } /* Comment.Preproc */
+.highlight .c1 { color: #0099FF; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #0099FF; font-weight: bold; font-style: italic } /* Comment.Special */
+.highlight .gd { background-color: #FFCCCC; border: 1px solid #CC0000 } /* Generic.Deleted */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #FF0000 } /* Generic.Error */
+.highlight .gh { color: #003300; font-weight: bold } /* Generic.Heading */
+.highlight .gi { background-color: #CCFFCC; border: 1px solid #00CC00 } /* Generic.Inserted */
+.highlight .go { color: #AAAAAA } /* Generic.Output */
+.highlight .gp { color: #000099; font-weight: bold } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #003300; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #99CC66 } /* Generic.Traceback */
+.highlight .kc { color: #006699; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #006699; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #006699; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #006699 } /* Keyword.Pseudo */
+.highlight .kr { color: #006699; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #007788; font-weight: bold } /* Keyword.Type */
+.highlight .m { color: #FF6600 } /* Literal.Number */
+.highlight .s { color: #CC3300 } /* Literal.String */
+.highlight .na { color: #330099 } /* Name.Attribute */
+.highlight .nb { color: #336666 } /* Name.Builtin */
+.highlight .nc { color: #00AA88; font-weight: bold } /* Name.Class */
+.highlight .no { color: #336600 } /* Name.Constant */
+.highlight .nd { color: #9999FF } /* Name.Decorator */
+.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
+.highlight .ne { color: #CC0000; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #CC00FF } /* Name.Function */
+.highlight .nl { color: #9999FF } /* Name.Label */
+.highlight .nn { color: #00CCFF; font-weight: bold } /* Name.Namespace */
+.highlight .nt { color: #330099; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #003333 } /* Name.Variable */
+.highlight .ow { color: #000000; font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mf { color: #FF6600 } /* Literal.Number.Float */
+.highlight .mh { color: #FF6600 } /* Literal.Number.Hex */
+.highlight .mi { color: #FF6600 } /* Literal.Number.Integer */
+.highlight .mo { color: #FF6600 } /* Literal.Number.Oct */
+.highlight .sb { color: #CC3300 } /* Literal.String.Backtick */
+.highlight .sc { color: #CC3300 } /* Literal.String.Char */
+.highlight .sd { color: #CC3300; font-style: italic } /* Literal.String.Doc */
+.highlight .s2 { color: #CC3300 } /* Literal.String.Double */
+.highlight .se { color: #CC3300; font-weight: bold } /* Literal.String.Escape */
+.highlight .sh { color: #CC3300 } /* Literal.String.Heredoc */
+.highlight .si { color: #AA0000 } /* Literal.String.Interpol */
+.highlight .sx { color: #CC3300 } /* Literal.String.Other */
+.highlight .sr { color: #33AAAA } /* Literal.String.Regex */
+.highlight .s1 { color: #CC3300 } /* Literal.String.Single */
+.highlight .ss { color: #FFCC33 } /* Literal.String.Symbol */
+.highlight .bp { color: #336666 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #003333 } /* Name.Variable.Class */
+.highlight .vg { color: #003333 } /* Name.Variable.Global */
+.highlight .vi { color: #003333 } /* Name.Variable.Instance */
+.highlight .il { color: #FF6600 } /* 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/stylesheet.css b/stylesheets/stylesheet.css
new file mode 100644
index 0000000..7a08b01
--- /dev/null
+++ b/stylesheets/stylesheet.css
@@ -0,0 +1,423 @@
+/*******************************************************************************
+Slate Theme for GitHub Pages
+by Jason Costello, @jsncostello
+*******************************************************************************/
+
+@import url(pygment_trac.css);
+
+/*******************************************************************************
+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;
+}
+
+/* HTML5 display-role reset for older browsers */
+article, aside, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section {
+ display: block;
+}
+
+ol, ul {
+ list-style: none;
+}
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+/*******************************************************************************
+Theme Styles
+*******************************************************************************/
+
+body {
+ box-sizing: border-box;
+ color:#373737;
+ background: #212121;
+ font-size: 16px;
+ font-family: 'Myriad Pro', Calibri, Helvetica, Arial, sans-serif;
+ line-height: 1.5;
+ -webkit-font-smoothing: antialiased;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ margin: 10px 0;
+ font-weight: 700;
+ color:#222222;
+ font-family: 'Lucida Grande', 'Calibri', Helvetica, Arial, sans-serif;
+ letter-spacing: -1px;
+}
+
+h1 {
+ font-size: 36px;
+ font-weight: 700;
+}
+
+h2 {
+ padding-bottom: 10px;
+ font-size: 32px;
+ background: url('../images/bg_hr.png') repeat-x bottom;
+}
+
+h3 {
+ font-size: 24px;
+}
+
+h4 {
+ font-size: 21px;
+}
+
+h5 {
+ font-size: 18px;
+}
+
+h6 {
+ font-size: 16px;
+}
+
+p {
+ margin: 10px 0 15px 0;
+}
+
+footer p {
+ color: #f2f2f2;
+}
+
+a {
+ text-decoration: none;
+ color: #007edf;
+ text-shadow: none;
+
+ transition: color 0.5s ease;
+ transition: text-shadow 0.5s ease;
+ -webkit-transition: color 0.5s ease;
+ -webkit-transition: text-shadow 0.5s ease;
+ -moz-transition: color 0.5s ease;
+ -moz-transition: text-shadow 0.5s ease;
+ -o-transition: color 0.5s ease;
+ -o-transition: text-shadow 0.5s ease;
+ -ms-transition: color 0.5s ease;
+ -ms-transition: text-shadow 0.5s ease;
+}
+
+a:hover, a:focus {text-decoration: underline;}
+
+footer a {
+ color: #F2F2F2;
+ text-decoration: underline;
+}
+
+em {
+ font-style: italic;
+}
+
+strong {
+ font-weight: bold;
+}
+
+img {
+ position: relative;
+ margin: 0 auto;
+ max-width: 739px;
+ padding: 5px;
+ margin: 10px 0 10px 0;
+ border: 1px solid #ebebeb;
+
+ box-shadow: 0 0 5px #ebebeb;
+ -webkit-box-shadow: 0 0 5px #ebebeb;
+ -moz-box-shadow: 0 0 5px #ebebeb;
+ -o-box-shadow: 0 0 5px #ebebeb;
+ -ms-box-shadow: 0 0 5px #ebebeb;
+}
+
+p img {
+ display: inline;
+ margin: 0;
+ padding: 0;
+ vertical-align: middle;
+ text-align: center;
+ border: none;
+}
+
+pre, code {
+ width: 100%;
+ color: #222;
+ background-color: #fff;
+
+ font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
+ font-size: 14px;
+
+ border-radius: 2px;
+ -moz-border-radius: 2px;
+ -webkit-border-radius: 2px;
+}
+
+pre {
+ width: 100%;
+ padding: 10px;
+ box-shadow: 0 0 10px rgba(0,0,0,.1);
+ overflow: auto;
+}
+
+code {
+ padding: 3px;
+ margin: 0 3px;
+ box-shadow: 0 0 10px rgba(0,0,0,.1);
+}
+
+pre code {
+ display: block;
+ box-shadow: none;
+}
+
+blockquote {
+ color: #666;
+ margin-bottom: 20px;
+ padding: 0 0 0 20px;
+ border-left: 3px solid #bbb;
+}
+
+
+ul, ol, dl {
+ margin-bottom: 15px
+}
+
+ul {
+ list-style: inside;
+ padding-left: 20px;
+}
+
+ol {
+ list-style: decimal inside;
+ padding-left: 20px;
+}
+
+dl dt {
+ font-weight: bold;
+}
+
+dl dd {
+ padding-left: 20px;
+ font-style: italic;
+}
+
+dl p {
+ padding-left: 20px;
+ font-style: italic;
+}
+
+hr {
+ height: 1px;
+ margin-bottom: 5px;
+ border: none;
+ background: url('../images/bg_hr.png') repeat-x center;
+}
+
+table {
+ border: 1px solid #373737;
+ margin-bottom: 20px;
+ text-align: left;
+ }
+
+th {
+ font-family: 'Lucida Grande', 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ padding: 10px;
+ background: #373737;
+ color: #fff;
+ }
+
+td {
+ padding: 10px;
+ border: 1px solid #373737;
+ }
+
+form {
+ background: #f2f2f2;
+ padding: 20px;
+}
+
+/*******************************************************************************
+Full-Width Styles
+*******************************************************************************/
+
+.outer {
+ width: 100%;
+}
+
+.inner {
+ position: relative;
+ max-width: 640px;
+ padding: 20px 10px;
+ margin: 0 auto;
+}
+
+#forkme_banner {
+ display: block;
+ position: absolute;
+ top:0;
+ right: 10px;
+ z-index: 10;
+ padding: 10px 50px 10px 10px;
+ color: #fff;
+ background: url('../images/blacktocat.png') #0090ff no-repeat 95% 50%;
+ font-weight: 700;
+ box-shadow: 0 0 10px rgba(0,0,0,.5);
+ border-bottom-left-radius: 2px;
+ border-bottom-right-radius: 2px;
+}
+
+#header_wrap {
+ background: #212121;
+ background: -moz-linear-gradient(top, #373737, #212121);
+ background: -webkit-linear-gradient(top, #373737, #212121);
+ background: -ms-linear-gradient(top, #373737, #212121);
+ background: -o-linear-gradient(top, #373737, #212121);
+ background: linear-gradient(top, #373737, #212121);
+}
+
+#header_wrap .inner {
+ padding: 50px 10px 30px 10px;
+}
+
+#project_title {
+ margin: 0;
+ color: #fff;
+ font-size: 42px;
+ font-weight: 700;
+ text-shadow: #111 0px 0px 10px;
+}
+
+#project_tagline {
+ color: #fff;
+ font-size: 24px;
+ font-weight: 300;
+ background: none;
+ text-shadow: #111 0px 0px 10px;
+}
+
+#downloads {
+ position: absolute;
+ width: 210px;
+ z-index: 10;
+ bottom: -40px;
+ right: 0;
+ height: 70px;
+ background: url('../images/icon_download.png') no-repeat 0% 90%;
+}
+
+.zip_download_link {
+ display: block;
+ float: right;
+ width: 90px;
+ height:70px;
+ text-indent: -5000px;
+ overflow: hidden;
+ background: url(../images/sprite_download.png) no-repeat bottom left;
+}
+
+.tar_download_link {
+ display: block;
+ float: right;
+ width: 90px;
+ height:70px;
+ text-indent: -5000px;
+ overflow: hidden;
+ background: url(../images/sprite_download.png) no-repeat bottom right;
+ margin-left: 10px;
+}
+
+.zip_download_link:hover {
+ background: url(../images/sprite_download.png) no-repeat top left;
+}
+
+.tar_download_link:hover {
+ background: url(../images/sprite_download.png) no-repeat top right;
+}
+
+#main_content_wrap {
+ background: #f2f2f2;
+ border-top: 1px solid #111;
+ border-bottom: 1px solid #111;
+}
+
+#main_content {
+ padding-top: 40px;
+}
+
+#footer_wrap {
+ background: #212121;
+}
+
+
+
+/*******************************************************************************
+Small Device Styles
+*******************************************************************************/
+
+@media screen and (max-width: 480px) {
+ body {
+ font-size:14px;
+ }
+
+ #downloads {
+ display: none;
+ }
+
+ .inner {
+ min-width: 320px;
+ max-width: 480px;
+ }
+
+ #project_title {
+ font-size: 32px;
+ }
+
+ h1 {
+ font-size: 28px;
+ }
+
+ h2 {
+ font-size: 24px;
+ }
+
+ h3 {
+ font-size: 21px;
+ }
+
+ h4 {
+ font-size: 18px;
+ }
+
+ h5 {
+ font-size: 14px;
+ }
+
+ h6 {
+ font-size: 12px;
+ }
+
+ code, pre {
+ min-width: 320px;
+ max-width: 480px;
+ font-size: 11px;
+ }
+
+}