diff --git a/.gitignore b/.gitignore index f40099f..4ba527e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ data/ tmp/ cache/ pagecache/ +.project diff --git a/inc/highlight.js/LICENSE b/inc/highlight.js/LICENSE new file mode 100644 index 0000000..422deb7 --- /dev/null +++ b/inc/highlight.js/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2006, Ivan Sagalaev +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 of highlight.js 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 REGENTS 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 REGENTS AND 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. diff --git a/inc/highlight.js/README.md b/inc/highlight.js/README.md new file mode 100644 index 0000000..3f0b749 --- /dev/null +++ b/inc/highlight.js/README.md @@ -0,0 +1,143 @@ +# Highlight.js + +Highlight.js highlights syntax in code examples on blogs, forums and, +in fact, on any web page. It's very easy to use because it works +automatically: finds blocks of code, detects a language, highlights it. + +Autodetection can be fine tuned when it fails by itself (see "Heuristics"). + + +## Basic usage + +Link the library and a stylesheet from your page and hook highlighting to +the page load event: + +```html + + + +``` + +This will highlight all code on the page marked up as `
 .. 
`. +If you use different markup or need to apply highlighting dynamically, read +"Custom initialization" below. + +- You can download your own customized version of "highlight.pack.js" or + use the hosted one as described on the download page: + + +- Style themes are available in the download package or as hosted files. + To create a custom style for your site see the class reference in the file + [classref.txt][cr] from the downloaded package. + +[cr]: http://github.com/isagalaev/highlight.js/blob/master/classref.txt + + +## node.js + +Highlight.js can be used under node.js. The package with all supported languages is +installable from NPM: + + npm install highlight.js + +Alternatively, you can build it from the source with only languages you need: + + python tools/build.py -tnode lang1 lang2 .. + +Using the library: + +```javascript +var hljs = require('highlight.js'); + +// If you know the language +hljs.highlight(lang, code).value; + +// Automatic language detection +hljs.highlightAuto(code).value; +``` + +## Tab replacement + +You can replace TAB ('\x09') characters used for indentation in your code +with some fixed number of spaces or with a `` to give them special +styling: + +```html + +``` + +## Custom initialization + +If you use different markup for code blocks you can initialize them manually +with `highlightBlock(code, tabReplace, useBR)` function. It takes a DOM element +containing the code to highlight and optionally a string with which to replace +TAB characters. + +Initialization using, for example, jQuery might look like this: + +```javascript +$(document).ready(function() { + $('pre code').each(function(i, e) {hljs.highlightBlock(e)}); +}); +``` + +You can use `highlightBlock` to highlight blocks dynamically inserted into +the page. Just make sure you don't do it twice for already highlighted +blocks. + +If your code container relies on `
` tags instead of line breaks (i.e. if +it's not `
`) pass `true` into the third parameter of `highlightBlock`
+to make highlight.js use `
` in the output: + +```javascript +$('div.code').each(function(i, e) {hljs.highlightBlock(e, null, true)}); +``` + + +## Heuristics + +Autodetection of a code's language is done using a simple heuristic: +the program tries to highlight a fragment with all available languages and +counts all syntactic structures that it finds along the way. The language +with greatest count wins. + +This means that in short fragments the probability of an error is high +(and it really happens sometimes). In this cases you can set the fragment's +language explicitly by assigning a class to the `` element: + +```html +
...
+``` + +You can use class names recommended in HTML5: "language-html", +"language-php". Classes also can be assigned to the `
` element.
+
+To disable highlighting of a fragment altogether use "no-highlight" class:
+
+```html
+
...
+``` + + +## Export + +File export.html contains a little program that allows you to paste in a code +snippet and then copy and paste the resulting HTML code generated by the +highlighter. This is useful in situations when you can't use the script itself +on a site. + + +## Meta + +- Version: 7.3 +- URL: http://softwaremaniacs.org/soft/highlight/en/ +- Author: Ivan Sagalaev () + +For the license terms see LICENSE files. +For the list of contributors see AUTHORS.en.txt file. diff --git a/inc/highlight.js/README.ru.md b/inc/highlight.js/README.ru.md new file mode 100644 index 0000000..65e419f --- /dev/null +++ b/inc/highlight.js/README.ru.md @@ -0,0 +1,149 @@ +# Highlight.js + +Highlight.js нужен для подсветки синтаксиса в примерах кода в блогах, +форумах и вообще на любых веб-страницах. Пользоваться им очень просто, +потому что работает он автоматически: сам находит блоки кода, сам +определяет язык, сам подсвечивает. + +Автоопределением языка можно управлять, когда оно не справляется само (см. +дальше "Эвристика"). + + +## Простое использование + +Подключите библиотеку и стиль на страницу и повесть вызов подсветки на +загрузку страницы: + +```html + + + +``` + +Весь код на странице, обрамлённый в теги `
 .. 
` +будет автоматически подсвечен. Если вы используете другие теги или хотите +подсвечивать блоки кода динамически, читайте "Инициализацию вручную" ниже. + +- Вы можете скачать собственную версию "highlight.pack.js" или сослаться + на захостенный файл, как описано на странице загрузки: + + +- Стилевые темы можно найти в загруженном архиве или также использовать + захостенные. Чтобы сделать собственный стиль для своего сайта, вам + будет полезен справочник классов в файле [classref.txt][cr], который тоже + есть в архиве. + +[cr]: http://github.com/isagalaev/highlight.js/blob/master/classref.txt + + +## node.js + +Highlight.js можно использовать в node.js. Библиотеку со всеми возможными языками можно +установить с NPM: + + npm install highlight.js + +Также её можно собрать из исходников с только теми языками, которые нужны: + + python tools/build.py -tnode lang1 lang2 .. + +Использование библиотеки: + +```javascript +var hljs = require('highlight.js'); + +// Если вы знаете язык +hljs.highlight(lang, code).value; + +// Автоопределение языка +hljs.highlightAuto(code).value; +``` + + +## Замена TABов + +Также вы можете заменить символы TAB ('\x09'), используемые для отступов, на +фиксированное количество пробелов или на отдельный ``, чтобы задать ему +какой-нибудь специальный стиль: + +```html + +``` + + +## Инициализация вручную + +Если вы используете другие теги для блоков кода, вы можете инициализировать их +явно с помощью функции `highlightBlock(code, tabReplace, useBR)`. Она принимает +DOM-элемент с текстом расцвечиваемого кода и опционально - строчку для замены +символов TAB. + +Например с использованием jQuery код инициализации может выглядеть так: + +```javascript +$(document).ready(function() { + $('pre code').each(function(i, e) {hljs.highlightBlock(e)}); +}); +``` + +`highlightBlock` можно также использовать, чтобы подсветить блоки кода, +добавленные на страницу динамически. Только убедитесь, что вы не делаете этого +повторно для уже раскрашенных блоков. + +Если ваш блок кода использует `
` вместо переводов строки (т.е. если это не +`
`), передайте `true` третьим параметром в `highlightBlock`:
+
+```javascript
+$('div.code').each(function(i, e) {hljs.highlightBlock(e, null, true)});
+```
+
+
+## Эвристика
+
+Определение языка, на котором написан фрагмент, делается с помощью
+довольно простой эвристики: программа пытается расцветить фрагмент всеми
+языками подряд, и для каждого языка считает количество подошедших
+синтаксически конструкций и ключевых слов. Для какого языка нашлось больше,
+тот и выбирается.
+
+Это означает, что в коротких фрагментах высока вероятность ошибки, что
+периодически и случается. Чтобы указать язык фрагмента явно, надо написать
+его название в виде класса к элементу ``:
+
+```html
+
...
+``` + +Можно использовать рекомендованные в HTML5 названия классов: +"language-html", "language-php". Также можно назначать классы на элемент +`
`.
+
+Чтобы запретить расцветку фрагмента вообще, используется класс "no-highlight":
+
+```html
+
...
+``` + + +## Экспорт + +В файле export.html находится небольшая программка, которая показывает и дает +скопировать непосредственно HTML-код подсветки для любого заданного фрагмента кода. +Это может понадобится например на сайте, на котором нельзя подключить сам скрипт +highlight.js. + + +## Координаты + +- Версия: 7.3 +- URL: http://softwaremaniacs.org/soft/highlight/ +- Автор: Иван Сагалаев () + +Лицензионное соглашение читайте в файле LICENSE. +Список соавторов читайте в файле AUTHORS.ru.txt diff --git a/inc/highlight.js/classref.txt b/inc/highlight.js/classref.txt new file mode 100644 index 0000000..b22bdad --- /dev/null +++ b/inc/highlight.js/classref.txt @@ -0,0 +1,568 @@ +This is a full list of available classes corresponding to languages' +syntactic structures. The parentheses after language name contain identifiers +used as class names in `` element. + +Python ("python"): + + keyword keyword + built_in built-in objects (None, False, True and Ellipsis) + number number + string string (of any type) + comment comment + decorator @-decorator for functions + function function header "def some_name(...):" + class class header "class SomeName(...):" + title name of a function or a class inside a header + params everything inside parentheses in a function's or class' header + +Python profiler results ("profile"): + + number number + string string + builtin builtin function entry + filename filename in an entry + summary profiling summary + header header of table of results + keyword column header + function function name in an entry (including parentheses) + title actual name of a function in an entry (excluding parentheses) + prompt interpreter prompt (>>> or ...) + +Ruby ("ruby"): + + keyword keyword + string string + subst in-string substitution (#{...}) + comment comment + yardoctag YARD tag + function function header "def some_name(...):" + class class header "class SomeName(...):" + title name of a function or a class inside a header + parent name of a parent class + symbol symbol + +Perl ("perl"): + + keyword keyword + comment comment + number number + string string + regexp regular expression + sub subroutine header (from "sub" till "{") + variable variable starting with "$", "%", "@" + operator operator + pod plain old doc + +PHP ("php"): + + keyword keyword + number number + string string (of any type) + comment comment + phpdoc phpdoc params in comments + variable variable starting with "$" + preprocessor preprocessor marks: "" + +Scala ("scala"): + + keyword keyword + number number + string string + comment comment + annotation annotation + javadoc javadoc comment + javadoctag @-tag in javadoc + class class header + title class name inside a header + params everything in parentheses inside a class header + inheritance keywords "extends" and "with" inside class header + +Go language ("go"): + comment comment + string string constant + number number + keyword language keywords + constant true false nil iota + typename built-in plain types (int, string etc.) + built_in built-in functions + +HTML, XML ("xml"): + + tag any tag from "<" till ">" + attribute tag's attribute with or without value + value attribute's value + comment comment + pi processing instruction () + doctype declaration + cdata CDATA section + +CSS ("css"): + + tag tag in selectors + id #some_name in selectors + class .some_name in selectors + at_rule @-rule till first "{" or ";" + attr_selector attribute selector (square brackets in a[href^=http://]) + pseudo pseudo classes and elemens (:after, ::after etc.) + comment comment + rules everything from "{" till "}" + attribute property name inside a rule + value property value inside a rule, from ":" till ";" or + till the end of rule block + number number within a value + string string within a value + hexcolor hex color (#FFFFFF) within a value + function CSS function within a value + important "!important" symbol + +Markdown ("markdown"): + + header header + bullet list bullet + emphasis emphasis + strong strong emphasis + blockquote blockquote + code code + horizontal_rule horizontal rule + link_label link label + link_url link url + +Django ("django"): + + keyword HTML tag in HTML, default tags and default filters in templates + tag any tag from "<" till ">" + comment comment + doctype declaration + attribute tag's attribute with or withou value + value attribute's value + template_tag template tag {% .. %} + variable template variable {{ .. }} + template_comment template comment, both {# .. #} and {% comment %} + filter filter from "|" till the next filter or the end of tag + argument filter argument + +JSON ("json"): + + number number + literal "true", "false" and "null" + string string value + attribute name of an object property + value value of an object property + +JavaScript ("javascript"): + + keyword keyword + comment comment + number number + literal special literal: "true", "false" and "null" + string string + regexp regular expression + function header of a function + title name of a function inside a header + params parentheses and everything inside them in a function's header + +CoffeeScript ("coffeescript"): + + keyword keyword + comment comment + number number + literal special literal: "true", "false" and "null" + string string + regexp regular expression + function header of a function + class header of a class + title name of a function variable inside a header + params parentheses and everything inside them in a function's header + property @-property within class and functions + +ActionScript ("actionscript"): + + comment comment + string string + number number + keyword keywords + literal literal + reserved reserved keyword + title name of declaration (package, class or function) + preprocessor preprocessor directive (import, include) + type type of returned value (for functions) + package package (named or not) + class class/interface + function function + param params of function + rest_arg rest argument of function + +VBScript ("vbscript"): + + keyword keyword + number number + string string + comment comment + built_in built-in function + +HTTP ("http"): + + request first line of a request + status first line of a response + attribute header name + string header value or query string in a request line + number status code + +Lua ("lua"): + + keyword keyword + number number + string string + comment comment + built_in built-in operator + function header of a function + title name of a function inside a header + params everything inside parentheses in a function's header + long_brackets multiline string in [=[ .. ]=] + +Delphi ("delphi"): + + keyword keyword + comment comment (of any type) + number number + string string + function header of a function, procedure, constructor and destructor + title name of a function, procedure, constructor or destructor + inside a header + params everything inside parentheses in a function's header + class class' body from "= class" till "end;" + +Java ("java"): + + keyword keyword + number number + string string + comment commment + annotaion annotation + javadoc javadoc comment + class class header from "class" till "{" + title class name inside a header + params everything in parentheses inside a class header + inheritance keywords "extends" and "implements" inside class header + +C++ ("cpp"): + + keyword keyword + number number + string string and character + comment comment + preprocessor preprocessor directive + stl_container instantiation of STL containers ("vector<...>") + +Objective C ("objectivec"): + keyword keyword + built_in Cocoa/Cocoa Touch constants and classes + number number + string string + comment comment + preprocessor preprocessor directive + class interface/implementation, protocol and forward class declaration + variable properties and struct accesors + +Vala ("vala"): + + keyword keyword + number number + string string + comment comment + class class definitions + title in class definition + constant ALL_UPPER_CASE + +C# ("cs"): + + keyword keyword + number number + string string + comment commment + xmlDocTag xmldoc tag ("///", "", "<..>") + +D language ("d"): + + comment comment + string string constant + number number + keyword language keywords (including @attributes) + constant true false null + built_in built-in plain types (int, string etc.) + +RenderMan RSL ("rsl"): + + keyword keyword + number number + string string (including @"..") + comment comment + preprocessor preprocessor directive + shader sahder keywords + shading shading keywords + built_in built-in function + +RenderMan RIB ("rib"): + + keyword keyword + number number + string string + comment comment + commands command + +Maya Embedded Language ("mel"): + + keyword keyword + number number + string string + comment comment + variable variable + +SQL ("sql"): + + keyword keyword (mostly SQL'92 and SQL'99) + number number + string string (of any type: "..", '..', `..`) + comment comment + aggregate aggregate function + +Smalltalk ("smalltalk"): + + keyword keyword + number number + string string + comment commment + symbol symbol + array array + class name of a class + char char + localvars block of local variables + +Lisp ("lisp"): + + keyword keyword + number number + string string + comment commment + variable variable + literal b, t and nil + list non-quoted list + title first symbol in a non-quoted list + body remainder of the non-quoted list + quoted quoted list, both "(quote .. )" and "'(..)" + +Clojure ("clojure"): + + comment comments and hints + string string + number number + collection collections + attribute :keyword + title function name (built-in or user defined) + built_in built-in function name + +Ini ("ini"): + + title title of a section + value value of a setting of any type + string string + number number + keyword boolean value keyword + +Apache ("apache"): + + keyword keyword + number number + comment commment + literal On and Off + sqbracket variables in rewrites "%{..}" + cbracket options in rewrites "[..]" + tag begin and end of a configuration section + +Nginx ("nginx"): + + title directive title + string string + number number + comment comment + built_in built-in constant + variable $-variable + regexp regexp + +Diff ("diff"): + + header file header + chunk chunk header within a file + addition added lines + deletion deleted lines + change changed lines + +DOS ("dos"): + + keyword keyword + flow batch control keyword + stream DOS special files ("con", "prn", ...) + winutils some commands (see dos.js specifically) + envvar environment variables + +Bash ("bash"): + + keyword keyword + string string + number number + comment comment + literal special literal: "true" и "false" + variable variable + shebang script interpreter header + +CMake ("cmake") + + keyword keyword + number number + string string + comment commment + envvar $-variable + +Axapta ("axapta"): + + keyword keyword + number number + string string + comment commment + class class header from "class" till "{" + title class name inside a header + params everything in parentheses inside a class header + inheritance keywords "extends" and "implements" inside class header + preprocessor preprocessor directive + +1C ("1c"): + + keyword keyword + number number + date date + string string + comment commment + function header of function or procudure + title function name inside a header + params everything in parentheses inside a function header + preprocessor preprocessor directive + +AVR assembler ("avrasm"): + + keyword keyword + built_in pre-defined register + number number + string string + comment commment + label label + preprocessor preprocessor directive + localvars substitution in .macro + +VHDL ("vhdl") + + keyword keyword + number number + string string + comment commment + literal signal logical value + typename typename + attribute signal attribute + +Parser3 ("parser3"): + + keyword keyword + number number + comment commment + variable variable starting with "$" + preprocessor preprocessor directive + title user-defined name starting with "@" + +TeX ("tex"): + + comment comment + number number + command command + parameter parameter + formula formula + special special symbol + +Haskell ("haskell"): + + keyword keyword + number number + string string + comment comment + class type classes and other data types + title function name + type type class name + typedef definition of types (type, newtype, data) + +Erlang ("erlang"): + + comment comment + string string + number number + keyword keyword + record_name record access (#record_name) + title name of declaration function + variable variable (starts with capital letter or with _) + pp.keywords module's attribute (-attribute) + function_name atom or atom:atom in case of function call + +Rust ("rust"): + + comment comment + string string + number number + keyword keyword + title name of declaration + preprocessor preprocessor directive + +Matlab ("matlab"): + + comment comment + string string + number number + keyword keyword + title function name + function function + param params of function + matrix matrix in [ .. ] + cell cell in { .. } + +R ("r"): + + comment comment + string string constant + number number + keyword language keywords (function, if) plus "structural" + functions (attach, require, setClass) + literal special literal: TRUE, FALSE, NULL, NA, etc. + +OpenGL Shading Language ("glsl"): + + comment comment + number number + preprocessor preprocessor directive + keyword keyword + built_in GLSL built-in functions and variables + literal true false + +AppleScript ("applescript"): + + keyword keyword + command core AppleScript command + constant AppleScript built in constant + type AppleScript variable type (integer, etc.) + property Applescript built in property (length, etc.) + number number + string string + comment comment + title name of a handler + +Brainfuck ("brainfuck"): + + title Brainfuck while loop command + literal Brainfuck inc and dec commands + comment comment + string Brainfuck input and output commands diff --git a/inc/highlight.js/highlight.pack.js b/inc/highlight.js/highlight.pack.js new file mode 100644 index 0000000..e2ab63b --- /dev/null +++ b/inc/highlight.js/highlight.pack.js @@ -0,0 +1 @@ +var hljs=new function(){function l(o){return o.replace(/&/gm,"&").replace(//gm,">")}function b(p){for(var o=p.firstChild;o;o=o.nextSibling){if(o.nodeName=="CODE"){return o}if(!(o.nodeType==3&&o.nodeValue.match(/\s+/))){break}}}function h(p,o){return Array.prototype.map.call(p.childNodes,function(q){if(q.nodeType==3){return o?q.nodeValue.replace(/\n/g,""):q.nodeValue}if(q.nodeName=="BR"){return"\n"}return h(q,o)}).join("")}function a(q){var p=(q.className+" "+q.parentNode.className).split(/\s+/);p=p.map(function(r){return r.replace(/^language-/,"")});for(var o=0;o"}while(x.length||v.length){var u=t().splice(0,1)[0];y+=l(w.substr(p,u.offset-p));p=u.offset;if(u.event=="start"){y+=s(u.node);r.push(u.node)}else{if(u.event=="stop"){var o,q=r.length;do{q--;o=r[q];y+=("")}while(o!=u.node);r.splice(q,1);while(q'+L[0]+""}else{r+=L[0]}N=A.lR.lastIndex;L=A.lR.exec(K)}return r+K.substr(N)}function z(){if(A.sL&&!e[A.sL]){return l(w)}var r=A.sL?d(A.sL,w):g(w);if(A.r>0){v+=r.keyword_count;B+=r.r}return''+r.value+""}function J(){return A.sL!==undefined?z():G()}function I(L,r){var K=L.cN?'':"";if(L.rB){x+=K;w=""}else{if(L.eB){x+=l(r)+K;w=""}else{x+=K;w=r}}A=Object.create(L,{parent:{value:A}});B+=L.r}function C(K,r){w+=K;if(r===undefined){x+=J();return 0}var L=o(r,A);if(L){x+=J();I(L,r);return L.rB?0:r.length}var M=s(A,r);if(M){if(!(M.rE||M.eE)){w+=r}x+=J();do{if(A.cN){x+=""}A=A.parent}while(A!=M.parent);if(M.eE){x+=l(r)}w="";if(M.starts){I(M.starts,"")}return M.rE?0:r.length}if(t(r,A)){throw"Illegal"}w+=r;return r.length||1}var F=e[D];f(F);var A=F;var w="";var B=0;var v=0;var x="";try{var u,q,p=0;while(true){A.t.lastIndex=p;u=A.t.exec(E);if(!u){break}q=C(E.substr(p,u.index-p),u[0]);p=u.index+q}C(E.substr(p));return{r:B,keyword_count:v,value:x,language:D}}catch(H){if(H=="Illegal"){return{r:0,keyword_count:0,value:l(E)}}else{throw H}}}function g(s){var o={keyword_count:0,r:0,value:l(s)};var q=o;for(var p in e){if(!e.hasOwnProperty(p)){continue}var r=d(p,s);r.language=p;if(r.keyword_count+r.r>q.keyword_count+q.r){q=r}if(r.keyword_count+r.r>o.keyword_count+o.r){q=o;o=r}}if(q.language){o.second_best=q}return o}function i(q,p,o){if(p){q=q.replace(/^((<[^>]+>|\t)+)/gm,function(r,v,u,t){return v.replace(/\t/g,p)})}if(o){q=q.replace(/\n/g,"
")}return q}function m(r,u,p){var v=h(r,p);var t=a(r);if(t=="no-highlight"){return}var w=t?d(t,v):g(v);t=w.language;var o=c(r);if(o.length){var q=document.createElement("pre");q.innerHTML=w.value;w.value=j(o,c(q),v)}w.value=i(w.value,u,p);var s=r.className;if(!s.match("(\\s|^)(language-)?"+t+"(\\s|$)")){s=s?(s+" "+t):t}r.innerHTML=w.value;r.className=s;r.result={language:t,kw:w.keyword_count,re:w.r};if(w.second_best){r.second_best={language:w.second_best.language,kw:w.second_best.keyword_count,re:w.second_best.r}}}function n(){if(n.called){return}n.called=true;Array.prototype.map.call(document.getElementsByTagName("pre"),b).filter(Boolean).forEach(function(o){m(o,hljs.tabReplace)})}function k(){window.addEventListener("DOMContentLoaded",n,false);window.addEventListener("load",n,false)}var e={};this.LANGUAGES=e;this.highlight=d;this.highlightAuto=g;this.fixMarkup=i;this.highlightBlock=m;this.initHighlighting=n;this.initHighlightingOnLoad=k;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|\\.|-|-=|/|/=|:|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE],r:0};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE],r:0};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.inherit=function(q,r){var o={};for(var p in q){o[p]=q[p]}if(r){for(var p in r){o[p]=r[p]}}return o}}();hljs.LANGUAGES.bash=function(a){var g="true false";var e="if then else elif fi for break continue while in do done echo exit return set declare";var c={cN:"variable",b:"\\$[a-zA-Z0-9_#]+"};var b={cN:"variable",b:"\\${([^}]|\\\\})+}"};var h={cN:"string",b:'"',e:'"',i:"\\n",c:[a.BE,c,b],r:0};var d={cN:"string",b:"'",e:"'",c:[{b:"''"}],r:0};var f={cN:"test_condition",b:"",e:"",c:[h,d,c,b],k:{literal:g},r:0};return{k:{keyword:e,literal:g},c:[{cN:"shebang",b:"(#!\\/bin\\/bash)|(#!\\/bin\\/sh)",r:10},c,b,a.HCM,h,d,a.inherit(f,{b:"\\[ ",e:" \\]",r:0}),a.inherit(f,{b:"\\[\\[ ",e:" \\]\\]"})]}}(hljs);hljs.LANGUAGES.cs=function(a){return{k:"abstract as base bool break byte case catch char checked class const continue decimal default delegate do double else enum event explicit extern false finally fixed float for foreach goto if implicit in int interface internal is lock long namespace new null object operator out override params private protected public readonly ref return sbyte sealed short sizeof stackalloc static string struct switch this throw true try typeof uint ulong unchecked unsafe ushort using virtual volatile void while ascending descending from get group into join let orderby partial select set value var where yield",c:[{cN:"comment",b:"///",e:"$",rB:true,c:[{cN:"xmlDocTag",b:"///|"},{cN:"xmlDocTag",b:""}]},a.CLCM,a.CBLCLM,{cN:"preprocessor",b:"#",e:"$",k:"if else elif endif define undef warning error line region endregion pragma checksum"},{cN:"string",b:'@"',e:'"',c:[{b:'""'}]},a.ASM,a.QSM,a.CNM]}}(hljs);hljs.LANGUAGES.ruby=function(e){var a="[a-zA-Z_][a-zA-Z0-9_]*(\\!|\\?)?";var j="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?";var g={keyword:"and false then defined module in return redo if BEGIN retry end for true self when next until do begin unless END rescue nil else break undef not super class case require yield alias while ensure elsif or include"};var c={cN:"yardoctag",b:"@[A-Za-z]+"};var k=[{cN:"comment",b:"#",e:"$",c:[c]},{cN:"comment",b:"^\\=begin",e:"^\\=end",c:[c],r:10},{cN:"comment",b:"^__END__",e:"\\n$"}];var d={cN:"subst",b:"#\\{",e:"}",l:a,k:g};var i=[e.BE,d];var b=[{cN:"string",b:"'",e:"'",c:i,r:0},{cN:"string",b:'"',e:'"',c:i,r:0},{cN:"string",b:"%[qw]?\\(",e:"\\)",c:i},{cN:"string",b:"%[qw]?\\[",e:"\\]",c:i},{cN:"string",b:"%[qw]?{",e:"}",c:i},{cN:"string",b:"%[qw]?<",e:">",c:i,r:10},{cN:"string",b:"%[qw]?/",e:"/",c:i,r:10},{cN:"string",b:"%[qw]?%",e:"%",c:i,r:10},{cN:"string",b:"%[qw]?-",e:"-",c:i,r:10},{cN:"string",b:"%[qw]?\\|",e:"\\|",c:i,r:10}];var h={cN:"function",bWK:true,e:" |$|;",k:"def",c:[{cN:"title",b:j,l:a,k:g},{cN:"params",b:"\\(",e:"\\)",l:a,k:g}].concat(k)};var f=k.concat(b.concat([{cN:"class",bWK:true,e:"$|;",k:"class module",c:[{cN:"title",b:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?",r:0},{cN:"inheritance",b:"<\\s*",c:[{cN:"parent",b:"("+e.IR+"::)?"+e.IR}]}].concat(k)},h,{cN:"constant",b:"(::)?(\\b[A-Z]\\w*(::)?)+",r:0},{cN:"symbol",b:":",c:b.concat([{b:j}]),r:0},{cN:"symbol",b:a+":",r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{cN:"number",b:"\\?\\w"},{cN:"variable",b:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{b:"("+e.RSR+")\\s*",c:k.concat([{cN:"regexp",b:"/",e:"/[a-z]*",i:"\\n",c:[e.BE,d]}]),r:0}]));d.c=f;h.c[1].c=f;return{l:a,k:g,c:f}}(hljs);hljs.LANGUAGES.diff=function(a){return{c:[{cN:"chunk",b:"^\\@\\@ +\\-\\d+,\\d+ +\\+\\d+,\\d+ +\\@\\@$",r:10},{cN:"chunk",b:"^\\*\\*\\* +\\d+,\\d+ +\\*\\*\\*\\*$",r:10},{cN:"chunk",b:"^\\-\\-\\- +\\d+,\\d+ +\\-\\-\\-\\-$",r:10},{cN:"header",b:"Index: ",e:"$"},{cN:"header",b:"=====",e:"=====$"},{cN:"header",b:"^\\-\\-\\-",e:"$"},{cN:"header",b:"^\\*{3} ",e:"$"},{cN:"header",b:"^\\+\\+\\+",e:"$"},{cN:"header",b:"\\*{5}",e:"\\*{5}$"},{cN:"addition",b:"^\\+",e:"$"},{cN:"deletion",b:"^\\-",e:"$"},{cN:"change",b:"^\\!",e:"$"}]}}(hljs);hljs.LANGUAGES.javascript=function(a){return{k:{keyword:"in if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const",literal:"true false null undefined NaN Infinity"},c:[a.ASM,a.QSM,a.CLCM,a.CBLCLM,a.CNM,{b:"("+a.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[a.CLCM,a.CBLCLM,{cN:"regexp",b:"/",e:"/[gim]*",i:"\\n",c:[{b:"\\\\/"}]},{b:"<",e:">;",sL:"xml"}],r:0},{cN:"function",bWK:true,e:"{",k:"function",c:[{cN:"title",b:"[A-Za-z$_][0-9A-Za-z$_]*"},{cN:"params",b:"\\(",e:"\\)",c:[a.CLCM,a.CBLCLM],i:"[\"'\\(]"}],i:"\\[|%"}]}}(hljs);hljs.LANGUAGES.css=function(a){var b={cN:"function",b:a.IR+"\\(",e:"\\)",c:[a.NM,a.ASM,a.QSM]};return{cI:true,i:"[=/|']",c:[a.CBLCLM,{cN:"id",b:"\\#[A-Za-z0-9_-]+"},{cN:"class",b:"\\.[A-Za-z0-9_-]+",r:0},{cN:"attr_selector",b:"\\[",e:"\\]",i:"$"},{cN:"pseudo",b:":(:)?[a-zA-Z0-9\\_\\-\\+\\(\\)\\\"\\']+"},{cN:"at_rule",b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{cN:"at_rule",b:"@",e:"[{;]",eE:true,k:"import page media charset",c:[b,a.ASM,a.QSM,a.NM]},{cN:"tag",b:a.IR,r:0},{cN:"rules",b:"{",e:"}",i:"[^\\s]",r:0,c:[a.CBLCLM,{cN:"rule",b:"[^\\s]",rB:true,e:";",eW:true,c:[{cN:"attribute",b:"[A-Z\\_\\.\\-]+",e:":",eE:true,i:"[^\\s]",starts:{cN:"value",eW:true,eE:true,c:[b,a.NM,a.QSM,a.ASM,a.CBLCLM,{cN:"hexcolor",b:"\\#[0-9A-F]+"},{cN:"important",b:"!important"}]}}]}]}]}}(hljs);hljs.LANGUAGES.xml=function(a){var c="[A-Za-z0-9\\._:-]+";var b={eW:true,c:[{cN:"attribute",b:c,r:0},{b:'="',rB:true,e:'"',c:[{cN:"value",b:'"',eW:true}]},{b:"='",rB:true,e:"'",c:[{cN:"value",b:"'",eW:true}]},{b:"=",c:[{cN:"value",b:"[^\\s/>]+"}]}]};return{cI:true,c:[{cN:"pi",b:"<\\?",e:"\\?>",r:10},{cN:"doctype",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},{cN:"comment",b:"",r:10},{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"|$)",e:">",k:{title:"style"},c:[b],starts:{e:"",rE:true,sL:"css"}},{cN:"tag",b:"|$)",e:">",k:{title:"script"},c:[b],starts:{e:"<\/script>",rE:true,sL:"javascript"}},{b:"<%",e:"%>",sL:"vbscript"},{cN:"tag",b:"",c:[{cN:"title",b:"[^ />]+"},b]}]}}(hljs);hljs.LANGUAGES.http=function(a){return{i:"\\S",c:[{cN:"status",b:"^HTTP/[0-9\\.]+",e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{cN:"request",b:"^[A-Z]+ (.*?) HTTP/[0-9\\.]+$",rB:true,e:"$",c:[{cN:"string",b:" ",e:" ",eB:true,eE:true}]},{cN:"attribute",b:"^\\w",e:": ",eE:true,i:"\\n|\\s|=",starts:{cN:"string",e:"$"}},{b:"\\n\\n",starts:{sL:"",eW:true}}]}}(hljs);hljs.LANGUAGES.java=function(a){return{k:"false synchronized int abstract float private char boolean static null if const for true while long throw strictfp finally protected import native final return void enum else break transient new catch instanceof byte super volatile case assert short package default double public try this switch continue throws",c:[{cN:"javadoc",b:"/\\*\\*",e:"\\*/",c:[{cN:"javadoctag",b:"@[A-Za-z]+"}],r:10},a.CLCM,a.CBLCLM,a.ASM,a.QSM,{cN:"class",bWK:true,e:"{",k:"class interface",i:":",c:[{bWK:true,k:"extends implements",r:10},{cN:"title",b:a.UIR}]},a.CNM,{cN:"annotation",b:"@[A-Za-z]+"}]}}(hljs);hljs.LANGUAGES.php=function(a){var e={cN:"variable",b:"\\$+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*"};var b=[a.inherit(a.ASM,{i:null}),a.inherit(a.QSM,{i:null}),{cN:"string",b:'b"',e:'"',c:[a.BE]},{cN:"string",b:"b'",e:"'",c:[a.BE]}];var c=[a.BNM,a.CNM];var d={cN:"title",b:a.UIR};return{cI:true,k:"and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return implements parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception php_user_filter default die require __FUNCTION__ enddeclare final try this switch continue endfor endif declare unset true false namespace trait goto instanceof insteadof __DIR__ __NAMESPACE__ __halt_compiler",c:[a.CLCM,a.HCM,{cN:"comment",b:"/\\*",e:"\\*/",c:[{cN:"phpdoc",b:"\\s@[A-Za-z]+"}]},{cN:"comment",eB:true,b:"__halt_compiler.+?;",eW:true},{cN:"string",b:"<<<['\"]?\\w+['\"]?$",e:"^\\w+;",c:[a.BE]},{cN:"preprocessor",b:"<\\?php",r:10},{cN:"preprocessor",b:"\\?>"},e,{cN:"function",bWK:true,e:"{",k:"function",i:"\\$|\\[|%",c:[d,{cN:"params",b:"\\(",e:"\\)",c:["self",e,a.CBLCLM].concat(b).concat(c)}]},{cN:"class",bWK:true,e:"{",k:"class",i:"[:\\(\\$]",c:[{bWK:true,eW:true,k:"extends",c:[d]},d]},{b:"=>"}].concat(b).concat(c)}}(hljs);hljs.LANGUAGES.python=function(a){var f={cN:"prompt",b:"^(>>>|\\.\\.\\.) "};var c=[{cN:"string",b:"(u|b)?r?'''",e:"'''",c:[f],r:10},{cN:"string",b:'(u|b)?r?"""',e:'"""',c:[f],r:10},{cN:"string",b:"(u|r|ur)'",e:"'",c:[a.BE],r:10},{cN:"string",b:'(u|r|ur)"',e:'"',c:[a.BE],r:10},{cN:"string",b:"(b|br)'",e:"'",c:[a.BE]},{cN:"string",b:'(b|br)"',e:'"',c:[a.BE]}].concat([a.ASM,a.QSM]);var e={cN:"title",b:a.UIR};var d={cN:"params",b:"\\(",e:"\\)",c:["self",a.CNM,f].concat(c)};var b={bWK:true,e:":",i:"[${=;\\n]",c:[e,d],r:10};return{k:{keyword:"and elif is global as in if from raise for except finally print import pass return exec else break not with class assert yield try while continue del or def lambda nonlocal|10",built_in:"None True False Ellipsis NotImplemented"},i:"(|\\?)",c:c.concat([f,a.HCM,a.inherit(b,{cN:"function",k:"def"}),a.inherit(b,{cN:"class",k:"class"}),a.CNM,{cN:"decorator",b:"@",e:"$"},{b:"\\b(print|exec)\\("}])}}(hljs);hljs.LANGUAGES.sql=function(a){return{cI:true,c:[{cN:"operator",b:"(begin|start|commit|rollback|savepoint|lock|alter|create|drop|rename|call|delete|do|handler|insert|load|replace|select|truncate|update|set|show|pragma|grant)\\b(?!:)",e:";",eW:true,k:{keyword:"all partial global month current_timestamp using go revoke smallint indicator end-exec disconnect zone with character assertion to add current_user usage input local alter match collate real then rollback get read timestamp session_user not integer bit unique day minute desc insert execute like ilike|2 level decimal drop continue isolation found where constraints domain right national some module transaction relative second connect escape close system_user for deferred section cast current sqlstate allocate intersect deallocate numeric public preserve full goto initially asc no key output collation group by union session both last language constraint column of space foreign deferrable prior connection unknown action commit view or first into float year primary cascaded except restrict set references names table outer open select size are rows from prepare distinct leading create only next inner authorization schema corresponding option declare precision immediate else timezone_minute external varying translation true case exception join hour default double scroll value cursor descriptor values dec fetch procedure delete and false int is describe char as at in varchar null trailing any absolute current_time end grant privileges when cross check write current_date pad begin temporary exec time update catalog user sql date on identity timezone_hour natural whenever interval work order cascade diagnostics nchar having left call do handler load replace truncate start lock show pragma exists number",aggregate:"count sum min max avg"},c:[{cN:"string",b:"'",e:"'",c:[a.BE,{b:"''"}],r:0},{cN:"string",b:'"',e:'"',c:[a.BE,{b:'""'}],r:0},{cN:"string",b:"`",e:"`",c:[a.BE]},a.CNM]},a.CBLCLM,{cN:"comment",b:"--",e:"$"}]}}(hljs);hljs.LANGUAGES.ini=function(a){return{cI:true,i:"[^\\s]",c:[{cN:"comment",b:";",e:"$"},{cN:"title",b:"^\\[",e:"\\]"},{cN:"setting",b:"^[a-z0-9\\[\\]_-]+[ \\t]*=[ \\t]*",e:"$",c:[{cN:"value",eW:true,k:"on off true false yes no",c:[a.QSM,a.NM]}]}]}}(hljs);hljs.LANGUAGES.perl=function(e){var a="getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qqfileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmgetsub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedirioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when";var d={cN:"subst",b:"[$@]\\{",e:"\\}",k:a,r:10};var b={cN:"variable",b:"\\$\\d"};var i={cN:"variable",b:"[\\$\\%\\@\\*](\\^\\w\\b|#\\w+(\\:\\:\\w+)*|[^\\s\\w{]|{\\w+}|\\w+(\\:\\:\\w*)*)"};var f=[e.BE,d,b,i];var h={b:"->",c:[{b:e.IR},{b:"{",e:"}"}]};var g={cN:"comment",b:"^(__END__|__DATA__)",e:"\\n$",r:5};var c=[b,i,e.HCM,g,{cN:"comment",b:"^\\=\\w",e:"\\=cut",eW:true},h,{cN:"string",b:"q[qwxr]?\\s*\\(",e:"\\)",c:f,r:5},{cN:"string",b:"q[qwxr]?\\s*\\[",e:"\\]",c:f,r:5},{cN:"string",b:"q[qwxr]?\\s*\\{",e:"\\}",c:f,r:5},{cN:"string",b:"q[qwxr]?\\s*\\|",e:"\\|",c:f,r:5},{cN:"string",b:"q[qwxr]?\\s*\\<",e:"\\>",c:f,r:5},{cN:"string",b:"qw\\s+q",e:"q",c:f,r:5},{cN:"string",b:"'",e:"'",c:[e.BE],r:0},{cN:"string",b:'"',e:'"',c:f,r:0},{cN:"string",b:"`",e:"`",c:[e.BE]},{cN:"string",b:"{\\w+}",r:0},{cN:"string",b:"-?\\w+\\s*\\=\\>",r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{b:"("+e.RSR+"|\\b(split|return|print|reverse|grep)\\b)\\s*",k:"split return print reverse grep",r:0,c:[e.HCM,g,{cN:"regexp",b:"(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*",r:10},{cN:"regexp",b:"(m|qr)?/",e:"/[a-z]*",c:[e.BE],r:0}]},{cN:"sub",bWK:true,e:"(\\s*\\(.*?\\))?[;{]",k:"sub",r:5},{cN:"operator",b:"-\\w\\b",r:0}];d.c=c;h.c[1].c=c;return{k:a,c:c}}(hljs);hljs.LANGUAGES.json=function(a){var e={literal:"true false null"};var d=[a.QSM,a.CNM];var c={cN:"value",e:",",eW:true,eE:true,c:d,k:e};var b={b:"{",e:"}",c:[{cN:"attribute",b:'\\s*"',e:'"\\s*:\\s*',eB:true,eE:true,c:[a.BE],i:"\\n",starts:c}],i:"\\S"};var f={b:"\\[",e:"\\]",c:[a.inherit(c,{cN:null})],i:"\\S"};d.splice(d.length,0,b,f);return{c:d,k:e,i:"\\S"}}(hljs);hljs.LANGUAGES.apache=function(a){var b={cN:"number",b:"[\\$%]\\d+"};return{cI:true,k:{keyword:"acceptfilter acceptmutex acceptpathinfo accessfilename action addalt addaltbyencoding addaltbytype addcharset adddefaultcharset adddescription addencoding addhandler addicon addiconbyencoding addiconbytype addinputfilter addlanguage addmoduleinfo addoutputfilter addoutputfilterbytype addtype alias aliasmatch allow allowconnect allowencodedslashes allowoverride anonymous anonymous_logemail anonymous_mustgiveemail anonymous_nouserid anonymous_verifyemail authbasicauthoritative authbasicprovider authdbduserpwquery authdbduserrealmquery authdbmgroupfile authdbmtype authdbmuserfile authdefaultauthoritative authdigestalgorithm authdigestdomain authdigestnccheck authdigestnonceformat authdigestnoncelifetime authdigestprovider authdigestqop authdigestshmemsize authgroupfile authldapbinddn authldapbindpassword authldapcharsetconfig authldapcomparednonserver authldapdereferencealiases authldapgroupattribute authldapgroupattributeisdn authldapremoteuserattribute authldapremoteuserisdn authldapurl authname authnprovideralias authtype authuserfile authzdbmauthoritative authzdbmtype authzdefaultauthoritative authzgroupfileauthoritative authzldapauthoritative authzownerauthoritative authzuserauthoritative balancermember browsermatch browsermatchnocase bufferedlogs cachedefaultexpire cachedirlength cachedirlevels cachedisable cacheenable cachefile cacheignorecachecontrol cacheignoreheaders cacheignorenolastmod cacheignorequerystring cachelastmodifiedfactor cachemaxexpire cachemaxfilesize cacheminfilesize cachenegotiateddocs cacheroot cachestorenostore cachestoreprivate cgimapextension charsetdefault charsetoptions charsetsourceenc checkcaseonly checkspelling chrootdir contentdigest cookiedomain cookieexpires cookielog cookiename cookiestyle cookietracking coredumpdirectory customlog dav davdepthinfinity davgenericlockdb davlockdb davmintimeout dbdexptime dbdkeep dbdmax dbdmin dbdparams dbdpersist dbdpreparesql dbdriver defaulticon defaultlanguage defaulttype deflatebuffersize deflatecompressionlevel deflatefilternote deflatememlevel deflatewindowsize deny directoryindex directorymatch directoryslash documentroot dumpioinput dumpiologlevel dumpiooutput enableexceptionhook enablemmap enablesendfile errordocument errorlog example expiresactive expiresbytype expiresdefault extendedstatus extfilterdefine extfilteroptions fileetag filterchain filterdeclare filterprotocol filterprovider filtertrace forcelanguagepriority forcetype forensiclog gracefulshutdowntimeout group header headername hostnamelookups identitycheck identitychecktimeout imapbase imapdefault imapmenu include indexheadinsert indexignore indexoptions indexorderdefault indexstylesheet isapiappendlogtoerrors isapiappendlogtoquery isapicachefile isapifakeasync isapilognotsupported isapireadaheadbuffer keepalive keepalivetimeout languagepriority ldapcacheentries ldapcachettl ldapconnectiontimeout ldapopcacheentries ldapopcachettl ldapsharedcachefile ldapsharedcachesize ldaptrustedclientcert ldaptrustedglobalcert ldaptrustedmode ldapverifyservercert limitinternalrecursion limitrequestbody limitrequestfields limitrequestfieldsize limitrequestline limitxmlrequestbody listen listenbacklog loadfile loadmodule lockfile logformat loglevel maxclients maxkeepaliverequests maxmemfree maxrequestsperchild maxrequestsperthread maxspareservers maxsparethreads maxthreads mcachemaxobjectcount mcachemaxobjectsize mcachemaxstreamingbuffer mcacheminobjectsize mcacheremovalalgorithm mcachesize metadir metafiles metasuffix mimemagicfile minspareservers minsparethreads mmapfile mod_gzip_on mod_gzip_add_header_count mod_gzip_keep_workfiles mod_gzip_dechunk mod_gzip_min_http mod_gzip_minimum_file_size mod_gzip_maximum_file_size mod_gzip_maximum_inmem_size mod_gzip_temp_dir mod_gzip_item_include mod_gzip_item_exclude mod_gzip_command_version mod_gzip_can_negotiate mod_gzip_handle_methods mod_gzip_static_suffix mod_gzip_send_vary mod_gzip_update_static modmimeusepathinfo multiviewsmatch namevirtualhost noproxy nwssltrustedcerts nwsslupgradeable options order passenv pidfile protocolecho proxybadheader proxyblock proxydomain proxyerroroverride proxyftpdircharset proxyiobuffersize proxymaxforwards proxypass proxypassinterpolateenv proxypassmatch proxypassreverse proxypassreversecookiedomain proxypassreversecookiepath proxypreservehost proxyreceivebuffersize proxyremote proxyremotematch proxyrequests proxyset proxystatus proxytimeout proxyvia readmename receivebuffersize redirect redirectmatch redirectpermanent redirecttemp removecharset removeencoding removehandler removeinputfilter removelanguage removeoutputfilter removetype requestheader require rewritebase rewritecond rewriteengine rewritelock rewritelog rewriteloglevel rewritemap rewriteoptions rewriterule rlimitcpu rlimitmem rlimitnproc satisfy scoreboardfile script scriptalias scriptaliasmatch scriptinterpretersource scriptlog scriptlogbuffer scriptloglength scriptsock securelisten seerequesttail sendbuffersize serveradmin serveralias serverlimit servername serverpath serverroot serversignature servertokens setenv setenvif setenvifnocase sethandler setinputfilter setoutputfilter ssienableaccess ssiendtag ssierrormsg ssistarttag ssitimeformat ssiundefinedecho sslcacertificatefile sslcacertificatepath sslcadnrequestfile sslcadnrequestpath sslcarevocationfile sslcarevocationpath sslcertificatechainfile sslcertificatefile sslcertificatekeyfile sslciphersuite sslcryptodevice sslengine sslhonorciperorder sslmutex ssloptions sslpassphrasedialog sslprotocol sslproxycacertificatefile sslproxycacertificatepath sslproxycarevocationfile sslproxycarevocationpath sslproxyciphersuite sslproxyengine sslproxymachinecertificatefile sslproxymachinecertificatepath sslproxyprotocol sslproxyverify sslproxyverifydepth sslrandomseed sslrequire sslrequiressl sslsessioncache sslsessioncachetimeout sslusername sslverifyclient sslverifydepth startservers startthreads substitute suexecusergroup threadlimit threadsperchild threadstacksize timeout traceenable transferlog typesconfig unsetenv usecanonicalname usecanonicalphysicalport user userdir virtualdocumentroot virtualdocumentrootip virtualscriptalias virtualscriptaliasip win32disableacceptex xbithack",literal:"on off"},c:[a.HCM,{cN:"sqbracket",b:"\\s\\[",e:"\\]$"},{cN:"cbracket",b:"[\\$%]\\{",e:"\\}",c:["self",b]},b,{cN:"tag",b:""},a.QSM]}}(hljs);hljs.LANGUAGES.cpp=function(a){var b={keyword:"false int float while private char catch export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const struct for static_cast|10 union namespace unsigned long throw volatile static protected bool template mutable if public friend do return goto auto void enum else break new extern using true class asm case typeid short reinterpret_cast|10 default double register explicit signed typename try this switch continue wchar_t inline delete alignof char16_t char32_t constexpr decltype noexcept nullptr static_assert thread_local restrict _Bool complex",built_in:"std string cin cout cerr clog stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap array shared_ptr"};return{k:b,i:"",k:b,r:10,c:["self"]}]}}(hljs); \ No newline at end of file diff --git a/inc/highlight.js/styles/arta.css b/inc/highlight.js/styles/arta.css new file mode 100644 index 0000000..b7257da --- /dev/null +++ b/inc/highlight.js/styles/arta.css @@ -0,0 +1,158 @@ +/* +Date: 17.V.2011 +Author: pumbur +*/ + +pre code +{ + display: block; padding: 0.5em; + background: #222; +} + +pre .profile .header *, +pre .ini .title, +pre .nginx .title +{ + color: #fff; +} + +pre .comment, +pre .javadoc, +pre .preprocessor, +pre .preprocessor .title, +pre .shebang, +pre .profile .summary, +pre .diff, +pre .pi, +pre .doctype, +pre .tag, +pre .template_comment, +pre .css .rules, +pre .tex .special +{ + color: #444; +} + +pre .string, +pre .symbol, +pre .diff .change, +pre .regexp, +pre .xml .attribute, +pre .smalltalk .char, +pre .xml .value, +pre .ini .value, +pre .clojure .attribute +{ + color: #ffcc33; +} + +pre .number, +pre .addition +{ + color: #00cc66; +} + +pre .built_in, +pre .literal, +pre .vhdl .typename, +pre .go .constant, +pre .go .typename, +pre .ini .keyword, +pre .lua .title, +pre .perl .variable, +pre .php .variable, +pre .mel .variable, +pre .django .variable, +pre .css .funtion, +pre .smalltalk .method, +pre .hexcolor, +pre .important, +pre .flow, +pre .inheritance, +pre .parser3 .variable +{ + color: #32AAEE; +} + +pre .keyword, +pre .tag .title, +pre .css .tag, +pre .css .class, +pre .css .id, +pre .css .pseudo, +pre .css .attr_selector, +pre .lisp .title, +pre .clojure .built_in, +pre .winutils, +pre .tex .command, +pre .request, +pre .status +{ + color: #6644aa; +} + +pre .title, +pre .ruby .constant, +pre .vala .constant, +pre .parent, +pre .deletion, +pre .template_tag, +pre .css .keyword, +pre .objectivec .class .id, +pre .smalltalk .class, +pre .lisp .keyword, +pre .apache .tag, +pre .nginx .variable, +pre .envvar, +pre .bash .variable, +pre .go .built_in, +pre .vbscript .built_in, +pre .lua .built_in, +pre .rsl .built_in, +pre .tail, +pre .avrasm .label, +pre .tex .formula, +pre .tex .formula * +{ + color: #bb1166; +} + +pre .yardoctag, +pre .phpdoc, +pre .profile .header, +pre .ini .title, +pre .apache .tag, +pre .parser3 .title +{ + font-weight: bold; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata +{ + opacity: 0.6; +} + +pre code, +pre .javascript, +pre .css, +pre .xml, +pre .subst, +pre .diff .chunk, +pre .css .value, +pre .css .attribute, +pre .lisp .string, +pre .lisp .number, +pre .tail .params, +pre .container, +pre .haskell *, +pre .erlang *, +pre .erlang_repl * +{ + color: #aaa; +} diff --git a/inc/highlight.js/styles/ascetic.css b/inc/highlight.js/styles/ascetic.css new file mode 100644 index 0000000..63349b7 --- /dev/null +++ b/inc/highlight.js/styles/ascetic.css @@ -0,0 +1,50 @@ +/* + +Original style from softwaremaniacs.org (c) Ivan Sagalaev + +*/ + +pre code { + display: block; padding: 0.5em; + background: white; color: black; +} + +pre .string, +pre .tag .value, +pre .filter .argument, +pre .addition, +pre .change, +pre .apache .tag, +pre .apache .cbracket, +pre .nginx .built_in, +pre .tex .formula { + color: #888; +} + +pre .comment, +pre .template_comment, +pre .shebang, +pre .doctype, +pre .pi, +pre .javadoc, +pre .deletion, +pre .apache .sqbracket { + color: #CCC; +} + +pre .keyword, +pre .tag .title, +pre .ini .title, +pre .lisp .title, +pre .clojure .title, +pre .http .title, +pre .nginx .title, +pre .css .tag, +pre .winutils, +pre .flow, +pre .apache .tag, +pre .tex .command, +pre .request, +pre .status { + font-weight: bold; +} diff --git a/inc/highlight.js/styles/brown_paper.css b/inc/highlight.js/styles/brown_paper.css new file mode 100644 index 0000000..23476da --- /dev/null +++ b/inc/highlight.js/styles/brown_paper.css @@ -0,0 +1,104 @@ +/* + +Brown Paper style from goldblog.com.ua (c) Zaripov Yura + +*/ + +pre code { + display: block; padding: 0.5em; + background:#b7a68e url(./brown_papersq.png); +} + +pre .keyword, +pre .literal, +pre .change, +pre .winutils, +pre .flow, +pre .lisp .title, +pre .clojure .built_in, +pre .nginx .title, +pre .tex .special, +pre .request, +pre .status { + color:#005599; + font-weight:bold; +} + +pre code, +pre .subst, +pre .tag .keyword { + color: #363C69; +} + +pre .string, +pre .title, +pre .haskell .type, +pre .tag .value, +pre .css .rules .value, +pre .preprocessor, +pre .ruby .symbol, +pre .ruby .symbol .string, +pre .ruby .class .parent, +pre .built_in, +pre .sql .aggregate, +pre .django .template_tag, +pre .django .variable, +pre .smalltalk .class, +pre .javadoc, +pre .ruby .string, +pre .django .filter .argument, +pre .smalltalk .localvars, +pre .smalltalk .array, +pre .attr_selector, +pre .pseudo, +pre .addition, +pre .stream, +pre .envvar, +pre .apache .tag, +pre .apache .cbracket, +pre .tex .number { + color: #2C009F; +} + +pre .comment, +pre .java .annotation, +pre .python .decorator, +pre .template_comment, +pre .pi, +pre .doctype, +pre .deletion, +pre .shebang, +pre .apache .sqbracket, +pre .nginx .built_in, +pre .tex .formula { + color: #802022; +} + +pre .keyword, +pre .literal, +pre .css .id, +pre .phpdoc, +pre .title, +pre .haskell .type, +pre .vbscript .built_in, +pre .sql .aggregate, +pre .rsl .built_in, +pre .smalltalk .class, +pre .diff .header, +pre .chunk, +pre .winutils, +pre .bash .variable, +pre .apache .tag, +pre .tex .command { + font-weight: bold; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.8; +} diff --git a/inc/highlight.js/styles/brown_papersq.png b/inc/highlight.js/styles/brown_papersq.png new file mode 100644 index 0000000..3813903 Binary files /dev/null and b/inc/highlight.js/styles/brown_papersq.png differ diff --git a/inc/highlight.js/styles/dark.css b/inc/highlight.js/styles/dark.css new file mode 100644 index 0000000..102a389 --- /dev/null +++ b/inc/highlight.js/styles/dark.css @@ -0,0 +1,103 @@ +/* + +Dark style from softwaremaniacs.org (c) Ivan Sagalaev + +*/ + +pre code { + display: block; padding: 0.5em; + background: #444; +} + +pre .keyword, +pre .literal, +pre .change, +pre .winutils, +pre .flow, +pre .lisp .title, +pre .clojure .built_in, +pre .nginx .title, +pre .tex .special { + color: white; +} + +pre code, +pre .subst { + color: #DDD; +} + +pre .string, +pre .title, +pre .haskell .type, +pre .ini .title, +pre .tag .value, +pre .css .rules .value, +pre .preprocessor, +pre .ruby .symbol, +pre .ruby .symbol .string, +pre .ruby .class .parent, +pre .built_in, +pre .sql .aggregate, +pre .django .template_tag, +pre .django .variable, +pre .smalltalk .class, +pre .javadoc, +pre .ruby .string, +pre .django .filter .argument, +pre .smalltalk .localvars, +pre .smalltalk .array, +pre .attr_selector, +pre .pseudo, +pre .addition, +pre .stream, +pre .envvar, +pre .apache .tag, +pre .apache .cbracket, +pre .tex .command, +pre .prompt { + color: #D88; +} + +pre .comment, +pre .java .annotation, +pre .python .decorator, +pre .template_comment, +pre .pi, +pre .doctype, +pre .deletion, +pre .shebang, +pre .apache .sqbracket, +pre .tex .formula { + color: #777; +} + +pre .keyword, +pre .literal, +pre .title, +pre .css .id, +pre .phpdoc, +pre .haskell .type, +pre .vbscript .built_in, +pre .sql .aggregate, +pre .rsl .built_in, +pre .smalltalk .class, +pre .diff .header, +pre .chunk, +pre .winutils, +pre .bash .variable, +pre .apache .tag, +pre .tex .special, +pre .request, +pre .status { + font-weight: bold; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} diff --git a/inc/highlight.js/styles/default.css b/inc/highlight.js/styles/default.css new file mode 100644 index 0000000..e417fc1 --- /dev/null +++ b/inc/highlight.js/styles/default.css @@ -0,0 +1,135 @@ +/* + +Original style from softwaremaniacs.org (c) Ivan Sagalaev + +*/ + +pre code { + display: block; padding: 0.5em; + background: #F0F0F0; +} + +pre code, +pre .subst, +pre .tag .title, +pre .lisp .title, +pre .clojure .built_in, +pre .nginx .title { + color: black; +} + +pre .string, +pre .title, +pre .constant, +pre .parent, +pre .tag .value, +pre .rules .value, +pre .rules .value .number, +pre .preprocessor, +pre .ruby .symbol, +pre .ruby .symbol .string, +pre .aggregate, +pre .template_tag, +pre .django .variable, +pre .smalltalk .class, +pre .addition, +pre .flow, +pre .stream, +pre .bash .variable, +pre .apache .tag, +pre .apache .cbracket, +pre .tex .command, +pre .tex .special, +pre .erlang_repl .function_or_atom, +pre .markdown .header { + color: #800; +} + +pre .comment, +pre .annotation, +pre .template_comment, +pre .diff .header, +pre .chunk, +pre .markdown .blockquote { + color: #888; +} + +pre .number, +pre .date, +pre .regexp, +pre .literal, +pre .smalltalk .symbol, +pre .smalltalk .char, +pre .go .constant, +pre .change, +pre .markdown .bullet, +pre .markdown .link_url { + color: #080; +} + +pre .label, +pre .javadoc, +pre .ruby .string, +pre .decorator, +pre .filter .argument, +pre .localvars, +pre .array, +pre .attr_selector, +pre .important, +pre .pseudo, +pre .pi, +pre .doctype, +pre .deletion, +pre .envvar, +pre .shebang, +pre .apache .sqbracket, +pre .nginx .built_in, +pre .tex .formula, +pre .erlang_repl .reserved, +pre .prompt, +pre .markdown .link_label, +pre .vhdl .attribute, +pre .clojure .attribute, +pre .coffeescript .property { + color: #88F +} + +pre .keyword, +pre .id, +pre .phpdoc, +pre .title, +pre .built_in, +pre .aggregate, +pre .css .tag, +pre .javadoctag, +pre .phpdoc, +pre .yardoctag, +pre .smalltalk .class, +pre .winutils, +pre .bash .variable, +pre .apache .tag, +pre .go .typename, +pre .tex .command, +pre .markdown .strong, +pre .request, +pre .status { + font-weight: bold; +} + +pre .markdown .emphasis { + font-style: italic; +} + +pre .nginx .built_in { + font-weight: normal; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} diff --git a/inc/highlight.js/styles/far.css b/inc/highlight.js/styles/far.css new file mode 100644 index 0000000..54859ca --- /dev/null +++ b/inc/highlight.js/styles/far.css @@ -0,0 +1,111 @@ +/* + +FAR Style (c) MajestiC + +*/ + +pre code { + display: block; padding: 0.5em; + background: #000080; +} + +pre code, +pre .subst { + color: #0FF; +} + +pre .string, +pre .ruby .string, +pre .haskell .type, +pre .tag .value, +pre .css .rules .value, +pre .css .rules .value .number, +pre .preprocessor, +pre .ruby .symbol, +pre .ruby .symbol .string, +pre .built_in, +pre .sql .aggregate, +pre .django .template_tag, +pre .django .variable, +pre .smalltalk .class, +pre .addition, +pre .apache .tag, +pre .apache .cbracket, +pre .tex .command, +pre .clojure .title { + color: #FF0; +} + +pre .keyword, +pre .css .id, +pre .title, +pre .haskell .type, +pre .vbscript .built_in, +pre .sql .aggregate, +pre .rsl .built_in, +pre .smalltalk .class, +pre .xml .tag .title, +pre .winutils, +pre .flow, +pre .change, +pre .envvar, +pre .bash .variable, +pre .tex .special, +pre .clojure .built_in { + color: #FFF; +} + +pre .comment, +pre .phpdoc, +pre .javadoc, +pre .java .annotation, +pre .template_comment, +pre .deletion, +pre .apache .sqbracket, +pre .tex .formula { + color: #888; +} + +pre .number, +pre .date, +pre .regexp, +pre .literal, +pre .smalltalk .symbol, +pre .smalltalk .char, +pre .clojure .attribute { + color: #0F0; +} + +pre .python .decorator, +pre .django .filter .argument, +pre .smalltalk .localvars, +pre .smalltalk .array, +pre .attr_selector, +pre .pseudo, +pre .xml .pi, +pre .diff .header, +pre .chunk, +pre .shebang, +pre .nginx .built_in, +pre .prompt { + color: #008080; +} + +pre .keyword, +pre .css .id, +pre .title, +pre .haskell .type, +pre .vbscript .built_in, +pre .sql .aggregate, +pre .rsl .built_in, +pre .smalltalk .class, +pre .winutils, +pre .flow, +pre .apache .tag, +pre .nginx .built_in, +pre .tex .command, +pre .tex .special, +pre .request, +pre .status { + font-weight: bold; +} diff --git a/inc/highlight.js/styles/github.css b/inc/highlight.js/styles/github.css new file mode 100644 index 0000000..89b02a6 --- /dev/null +++ b/inc/highlight.js/styles/github.css @@ -0,0 +1,127 @@ +/* + +github.com style (c) Vasily Polovnyov + +*/ + +pre code { + display: block; padding: 0.5em; + color: #333; + background: #f8f8ff +} + +pre .comment, +pre .template_comment, +pre .diff .header, +pre .javadoc { + color: #998; + font-style: italic +} + +pre .keyword, +pre .css .rule .keyword, +pre .winutils, +pre .javascript .title, +pre .nginx .title, +pre .subst, +pre .request, +pre .status { + color: #333; + font-weight: bold +} + +pre .number, +pre .hexcolor, +pre .ruby .constant { + color: #099; +} + +pre .string, +pre .tag .value, +pre .phpdoc, +pre .tex .formula { + color: #d14 +} + +pre .title, +pre .id { + color: #900; + font-weight: bold +} + +pre .javascript .title, +pre .lisp .title, +pre .clojure .title, +pre .subst { + font-weight: normal +} + +pre .class .title, +pre .haskell .type, +pre .vhdl .literal, +pre .tex .command { + color: #458; + font-weight: bold +} + +pre .tag, +pre .tag .title, +pre .rules .property, +pre .django .tag .keyword { + color: #000080; + font-weight: normal +} + +pre .attribute, +pre .variable, +pre .lisp .body { + color: #008080 +} + +pre .regexp { + color: #009926 +} + +pre .class { + color: #458; + font-weight: bold +} + +pre .symbol, +pre .ruby .symbol .string, +pre .lisp .keyword, +pre .tex .special, +pre .prompt { + color: #990073 +} + +pre .built_in, +pre .lisp .title, +pre .clojure .built_in { + color: #0086b3 +} + +pre .preprocessor, +pre .pi, +pre .doctype, +pre .shebang, +pre .cdata { + color: #999; + font-weight: bold +} + +pre .deletion { + background: #fdd +} + +pre .addition { + background: #dfd +} + +pre .diff .change { + background: #0086b3 +} + +pre .chunk { + color: #aaa +} diff --git a/inc/highlight.js/styles/googlecode.css b/inc/highlight.js/styles/googlecode.css new file mode 100644 index 0000000..a7b7592 --- /dev/null +++ b/inc/highlight.js/styles/googlecode.css @@ -0,0 +1,144 @@ +/* + +Google Code style (c) Aahan Krish + +*/ + +pre code { + display: block; padding: 0.5em; + background: white; color: black; +} + +pre .comment, +pre .template_comment, +pre .javadoc, +pre .comment * { + color: #800; +} + +pre .keyword, +pre .method, +pre .list .title, +pre .clojure .built_in, +pre .nginx .title, +pre .tag .title, +pre .setting .value, +pre .winutils, +pre .tex .command, +pre .http .title, +pre .request, +pre .status { + color: #008; +} + +pre .envvar, +pre .tex .special { + color: #660; +} + +pre .string, +pre .tag .value, +pre .cdata, +pre .filter .argument, +pre .attr_selector, +pre .apache .cbracket, +pre .date, +pre .regexp { + color: #080; +} + +pre .sub .identifier, +pre .pi, +pre .tag, +pre .tag .keyword, +pre .decorator, +pre .ini .title, +pre .shebang, +pre .prompt, +pre .hexcolor, +pre .rules .value, +pre .css .value .number, +pre .literal, +pre .symbol, +pre .ruby .symbol .string, +pre .number, +pre .css .function, +pre .clojure .attribute { + color: #066; +} + +pre .class .title, +pre .haskell .type, +pre .smalltalk .class, +pre .javadoctag, +pre .yardoctag, +pre .phpdoc, +pre .typename, +pre .tag .attribute, +pre .doctype, +pre .class .id, +pre .built_in, +pre .setting, +pre .params, +pre .variable, +pre .clojure .title { + color: #606; +} + +pre .css .tag, +pre .rules .property, +pre .pseudo, +pre .subst { + color: #000; +} + +pre .css .class, pre .css .id { + color: #9B703F; +} + +pre .value .important { + color: #ff7700; + font-weight: bold; +} + +pre .rules .keyword { + color: #C5AF75; +} + +pre .annotation, +pre .apache .sqbracket, +pre .nginx .built_in { + color: #9B859D; +} + +pre .preprocessor, +pre .preprocessor * { + color: #444; +} + +pre .tex .formula { + background-color: #EEE; + font-style: italic; +} + +pre .diff .header, +pre .chunk { + color: #808080; + font-weight: bold; +} + +pre .diff .change { + background-color: #BCCFF9; +} + +pre .addition { + background-color: #BAEEBA; +} + +pre .deletion { + background-color: #FFC8BD; +} + +pre .comment .yardoctag { + font-weight: bold; +} diff --git a/inc/highlight.js/styles/idea.css b/inc/highlight.js/styles/idea.css new file mode 100644 index 0000000..94515c2 --- /dev/null +++ b/inc/highlight.js/styles/idea.css @@ -0,0 +1,121 @@ +/* + +Intellij Idea-like styling (c) Vasily Polovnyov + +*/ + +pre code { + display: block; padding: 0.5em; + color: #000; + background: #fff; +} + +pre .subst, +pre .title { + font-weight: normal; + color: #000; +} + +pre .comment, +pre .template_comment, +pre .javadoc, +pre .diff .header { + color: #808080; + font-style: italic; +} + +pre .annotation, +pre .decorator, +pre .preprocessor, +pre .doctype, +pre .pi, +pre .chunk, +pre .shebang, +pre .apache .cbracket, +pre .prompt, +pre .http .title { + color: #808000; +} + +pre .tag, +pre .pi { + background: #efefef; +} + +pre .tag .title, +pre .id, +pre .attr_selector, +pre .pseudo, +pre .literal, +pre .keyword, +pre .hexcolor, +pre .css .function, +pre .ini .title, +pre .css .class, +pre .list .title, +pre .clojure .title, +pre .nginx .title, +pre .tex .command, +pre .request, +pre .status { + font-weight: bold; + color: #000080; +} + +pre .attribute, +pre .rules .keyword, +pre .number, +pre .date, +pre .regexp, +pre .tex .special { + font-weight: bold; + color: #0000ff; +} + +pre .number, +pre .regexp { + font-weight: normal; +} + +pre .string, +pre .value, +pre .filter .argument, +pre .css .function .params, +pre .apache .tag { + color: #008000; + font-weight: bold; +} + +pre .symbol, +pre .ruby .symbol .string, +pre .char, +pre .tex .formula { + color: #000; + background: #d0eded; + font-style: italic; +} + +pre .phpdoc, +pre .yardoctag, +pre .javadoctag { + text-decoration: underline; +} + +pre .variable, +pre .envvar, +pre .apache .sqbracket, +pre .nginx .built_in { + color: #660e7a; +} + +pre .addition { + background: #baeeba; +} + +pre .deletion { + background: #ffc8bd; +} + +pre .diff .change { + background: #bccff9; +} diff --git a/inc/highlight.js/styles/ir_black.css b/inc/highlight.js/styles/ir_black.css new file mode 100644 index 0000000..c4c09b5 --- /dev/null +++ b/inc/highlight.js/styles/ir_black.css @@ -0,0 +1,104 @@ +/* + IR_Black style (c) Vasily Mikhailitchenko +*/ + +pre code { + display: block; padding: 0.5em; + background: #000; color: #f8f8f8; +} + +pre .shebang, +pre .comment, +pre .template_comment, +pre .javadoc { + color: #7c7c7c; +} + +pre .keyword, +pre .tag, +pre .tex .command, +pre .request, +pre .status, +pre .clojure .attribute { + color: #96CBFE; +} + +pre .sub .keyword, +pre .method, +pre .list .title, +pre .nginx .title { + color: #FFFFB6; +} + +pre .string, +pre .tag .value, +pre .cdata, +pre .filter .argument, +pre .attr_selector, +pre .apache .cbracket, +pre .date { + color: #A8FF60; +} + +pre .subst { + color: #DAEFA3; +} + +pre .regexp { + color: #E9C062; +} + +pre .title, +pre .sub .identifier, +pre .pi, +pre .decorator, +pre .tex .special, +pre .haskell .type, +pre .constant, +pre .smalltalk .class, +pre .javadoctag, +pre .yardoctag, +pre .phpdoc, +pre .nginx .built_in { + color: #FFFFB6; +} + +pre .symbol, +pre .ruby .symbol .string, +pre .number, +pre .variable, +pre .vbscript, +pre .literal { + color: #C6C5FE; +} + +pre .css .tag { + color: #96CBFE; +} + +pre .css .rules .property, +pre .css .id { + color: #FFFFB6; +} + +pre .css .class { + color: #FFF; +} + +pre .hexcolor { + color: #C6C5FE; +} + +pre .number { + color:#FF73FD; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.7; +} diff --git a/inc/highlight.js/styles/magula.css b/inc/highlight.js/styles/magula.css new file mode 100644 index 0000000..8766344 --- /dev/null +++ b/inc/highlight.js/styles/magula.css @@ -0,0 +1,121 @@ +/* +Description: Magula style for highligh.js +Author: Ruslan Keba +Website: http://rukeba.com/ +Version: 1.0 +Date: 2009-01-03 +Music: Aphex Twin / Xtal +*/ + +pre code { + display: block; padding: 0.5em; + background-color: #f4f4f4; +} + +pre code, +pre .subst, +pre .lisp .title, +pre .clojure .built_in { + color: black; +} + +pre .string, +pre .title, +pre .parent, +pre .tag .value, +pre .rules .value, +pre .rules .value .number, +pre .preprocessor, +pre .ruby .symbol, +pre .ruby .symbol .string, +pre .aggregate, +pre .template_tag, +pre .django .variable, +pre .smalltalk .class, +pre .addition, +pre .flow, +pre .stream, +pre .bash .variable, +pre .apache .cbracket { + color: #050; +} + +pre .comment, +pre .annotation, +pre .template_comment, +pre .diff .header, +pre .chunk { + color: #777; +} + +pre .number, +pre .date, +pre .regexp, +pre .literal, +pre .smalltalk .symbol, +pre .smalltalk .char, +pre .change, +pre .tex .special { + color: #800; +} + +pre .label, +pre .javadoc, +pre .ruby .string, +pre .decorator, +pre .filter .argument, +pre .localvars, +pre .array, +pre .attr_selector, +pre .pseudo, +pre .pi, +pre .doctype, +pre .deletion, +pre .envvar, +pre .shebang, +pre .apache .sqbracket, +pre .nginx .built_in, +pre .tex .formula, +pre .prompt, +pre .clojure .attribute { + color: #00e; +} + +pre .keyword, +pre .id, +pre .phpdoc, +pre .title, +pre .built_in, +pre .aggregate, +pre .smalltalk .class, +pre .winutils, +pre .bash .variable, +pre .apache .tag, +pre .xml .tag, +pre .tex .command, +pre .request, +pre .status { + font-weight: bold; + color: navy; +} + +pre .nginx .built_in { + font-weight: normal; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} + +/* --- */ +pre .apache .tag { + font-weight: bold; + color: blue; +} + diff --git a/inc/highlight.js/styles/monokai.css b/inc/highlight.js/styles/monokai.css new file mode 100644 index 0000000..79c4f6f --- /dev/null +++ b/inc/highlight.js/styles/monokai.css @@ -0,0 +1,114 @@ +/* +Monokai style - ported by Luigi Maselli - http://grigio.org +*/ + +pre code { + display: block; padding: 0.5em; + background: #272822; +} + +pre .tag, +pre .tag .title, +pre .keyword, +pre .literal, +pre .change, +pre .winutils, +pre .flow, +pre .lisp .title, +pre .clojure .built_in, +pre .nginx .title, +pre .tex .special { + color: #F92672; +} + +pre code { + color: #DDD; +} + +pre code .constant { + color: #66D9EF; +} + +pre .class .title { + color: white; +} + +pre .attribute, +pre .symbol, +pre .symbol .string, +pre .value, +pre .regexp { + color: #BF79DB; +} + +pre .tag .value, +pre .string, +pre .subst, +pre .title, +pre .haskell .type, +pre .preprocessor, +pre .ruby .class .parent, +pre .built_in, +pre .sql .aggregate, +pre .django .template_tag, +pre .django .variable, +pre .smalltalk .class, +pre .javadoc, +pre .django .filter .argument, +pre .smalltalk .localvars, +pre .smalltalk .array, +pre .attr_selector, +pre .pseudo, +pre .addition, +pre .stream, +pre .envvar, +pre .apache .tag, +pre .apache .cbracket, +pre .tex .command, +pre .prompt { + color: #A6E22E; +} + +pre .comment, +pre .java .annotation, +pre .python .decorator, +pre .template_comment, +pre .pi, +pre .doctype, +pre .deletion, +pre .shebang, +pre .apache .sqbracket, +pre .tex .formula { + color: #75715E; +} + +pre .keyword, +pre .literal, +pre .css .id, +pre .phpdoc, +pre .title, +pre .haskell .type, +pre .vbscript .built_in, +pre .sql .aggregate, +pre .rsl .built_in, +pre .smalltalk .class, +pre .diff .header, +pre .chunk, +pre .winutils, +pre .bash .variable, +pre .apache .tag, +pre .tex .special, +pre .request, +pre .status { + font-weight: bold; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} diff --git a/inc/highlight.js/styles/pojoaque.css b/inc/highlight.js/styles/pojoaque.css new file mode 100644 index 0000000..b9d20c2 --- /dev/null +++ b/inc/highlight.js/styles/pojoaque.css @@ -0,0 +1,104 @@ +/* + +Pojoaque Style by Jason Tate +http://web-cms-designs.com/ftopict-10-pojoaque-style-for-highlight-js-code-highlighter.html +Based on Solarized Style from http://ethanschoonover.com/solarized + +*/ + +pre code { + display: block; padding: 0.5em; + color: #DCCF8F; + background: url(./pojoaque.jpg) repeat scroll left top #181914; +} + +pre .comment, +pre .template_comment, +pre .diff .header, +pre .doctype, +pre .lisp .string, +pre .javadoc { + color: #586e75; + font-style: italic; +} + +pre .keyword, +pre .css .rule .keyword, +pre .winutils, +pre .javascript .title, +pre .method, +pre .addition, +pre .css .tag, +pre .clojure .title, +pre .nginx .title { + color: #B64926; +} + +pre .number, +pre .command, +pre .string, +pre .tag .value, +pre .phpdoc, +pre .tex .formula, +pre .regexp, +pre .hexcolor { + color: #468966; +} + +pre .title, +pre .localvars, +pre .function .title, +pre .chunk, +pre .decorator, +pre .built_in, +pre .lisp .title, +pre .clojure .built_in, +pre .identifier, +pre .id { + color: #FFB03B; +} + +pre .attribute, +pre .variable, +pre .lisp .body, +pre .smalltalk .number, +pre .constant, +pre .class .title, +pre .parent, +pre .haskell .type { + color: #b58900; +} + +pre .css .attribute { + color: #b89859; +} + +pre .css .number,pre .css .hexcolor{ + color: #DCCF8F; +} + +pre .css .class { + color: #d3a60c; +} + +pre .preprocessor, +pre .pi, +pre .shebang, +pre .symbol, +pre .symbol .string, +pre .diff .change, +pre .special, +pre .attr_selector, +pre .important, +pre .subst, +pre .cdata { + color: #cb4b16; +} + +pre .deletion { + color: #dc322f; +} + +pre .tex .formula { + background: #073642; +} diff --git a/inc/highlight.js/styles/pojoaque.jpg b/inc/highlight.js/styles/pojoaque.jpg new file mode 100644 index 0000000..9c07d4a Binary files /dev/null and b/inc/highlight.js/styles/pojoaque.jpg differ diff --git a/inc/highlight.js/styles/rainbow.css b/inc/highlight.js/styles/rainbow.css new file mode 100644 index 0000000..e8e098f --- /dev/null +++ b/inc/highlight.js/styles/rainbow.css @@ -0,0 +1,114 @@ +/* + +Style with support for rainbow parens + +*/ + +pre ::-moz-selection{ background: #FF5E99; color:#fff; text-shadow: none; } +pre ::selection { background:#FF5E99; color:#fff; text-shadow: none; } + +pre code { + display: block; padding: 0.5em; + background: #474949; color: #D1D9E1; +} + + +pre .body, +pre .collection { + color: #D1D9E1; +} + +pre .comment, +pre .template_comment, +pre .diff .header, +pre .doctype, +pre .lisp .string, +pre .javadoc { + color: #969896; + font-style: italic; +} + +pre .keyword, +pre .clojure .attribute, +pre .winutils, +pre .javascript .title, +pre .addition, +pre .css .tag { + color: #cc99cc; +} + +pre .number { color: #f99157; } + +pre .command, +pre .string, +pre .tag .value, +pre .phpdoc, +pre .tex .formula, +pre .regexp, +pre .hexcolor { + color: #8abeb7; +} + +pre .title, +pre .localvars, +pre .function .title, +pre .chunk, +pre .decorator, +pre .built_in, +pre .lisp .title, +pre .identifier +{ + color: #b5bd68; +} + +pre .class .keyword +{ + color: #f2777a; +} + +pre .variable, +pre .lisp .body, +pre .smalltalk .number, +pre .constant, +pre .class .title, +pre .parent, +pre .haskell .label, +pre .id, +pre .lisp .title, +pre .clojure .title .built_in { + color: #ffcc66; +} + +pre .tag .title, +pre .rules .property, +pre .django .tag .keyword, +pre .clojure .title .built_in { + font-weight: bold; +} + +pre .attribute, +pre .clojure .title { + color: #81a2be; +} + +pre .preprocessor, +pre .pi, +pre .shebang, +pre .symbol, +pre .symbol .string, +pre .diff .change, +pre .special, +pre .attr_selector, +pre .important, +pre .subst, +pre .cdata { + color: #f99157; +} + +pre .deletion { + color: #dc322f; +} + +pre .tex .formula { + background: #eee8d5; +} diff --git a/inc/highlight.js/styles/school_book.css b/inc/highlight.js/styles/school_book.css new file mode 100644 index 0000000..dd07ed2 --- /dev/null +++ b/inc/highlight.js/styles/school_book.css @@ -0,0 +1,111 @@ +/* + +School Book style from goldblog.com.ua (c) Zaripov Yura + +*/ + +pre code { + display: block; padding: 15px 0.5em 0.5em 30px; + font-size: 11px !important; + line-height:16px !important; +} + +pre{ + background:#f6f6ae url(./school_book.png); + border-top: solid 2px #d2e8b9; + border-bottom: solid 1px #d2e8b9; +} + +pre .keyword, +pre .literal, +pre .change, +pre .winutils, +pre .flow, +pre .lisp .title, +pre .clojure .built_in, +pre .nginx .title, +pre .tex .special { + color:#005599; + font-weight:bold; +} + +pre code, +pre .subst, +pre .tag .keyword { + color: #3E5915; +} + +pre .string, +pre .title, +pre .haskell .type, +pre .tag .value, +pre .css .rules .value, +pre .preprocessor, +pre .ruby .symbol, +pre .ruby .symbol .string, +pre .ruby .class .parent, +pre .built_in, +pre .sql .aggregate, +pre .django .template_tag, +pre .django .variable, +pre .smalltalk .class, +pre .javadoc, +pre .ruby .string, +pre .django .filter .argument, +pre .smalltalk .localvars, +pre .smalltalk .array, +pre .attr_selector, +pre .pseudo, +pre .addition, +pre .stream, +pre .envvar, +pre .apache .tag, +pre .apache .cbracket, +pre .nginx .built_in, +pre .tex .command { + color: #2C009F; +} + +pre .comment, +pre .java .annotation, +pre .python .decorator, +pre .template_comment, +pre .pi, +pre .doctype, +pre .deletion, +pre .shebang, +pre .apache .sqbracket { + color: #E60415; +} + +pre .keyword, +pre .literal, +pre .css .id, +pre .phpdoc, +pre .title, +pre .haskell .type, +pre .vbscript .built_in, +pre .sql .aggregate, +pre .rsl .built_in, +pre .smalltalk .class, +pre .xml .tag .title, +pre .diff .header, +pre .chunk, +pre .winutils, +pre .bash .variable, +pre .apache .tag, +pre .tex .command, +pre .request, +pre .status { + font-weight: bold; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} diff --git a/inc/highlight.js/styles/school_book.png b/inc/highlight.js/styles/school_book.png new file mode 100644 index 0000000..956e979 Binary files /dev/null and b/inc/highlight.js/styles/school_book.png differ diff --git a/inc/highlight.js/styles/solarized_dark.css b/inc/highlight.js/styles/solarized_dark.css new file mode 100644 index 0000000..8d3a238 --- /dev/null +++ b/inc/highlight.js/styles/solarized_dark.css @@ -0,0 +1,88 @@ +/* + +Orginal Style from ethanschoonover.com/solarized (c) Jeremy Hull + +*/ + +pre code { + display: block; padding: 0.5em; + background: #002b36; color: #839496; +} + +pre .comment, +pre .template_comment, +pre .diff .header, +pre .doctype, +pre .pi, +pre .lisp .string, +pre .javadoc { + color: #586e75; + font-style: italic; +} + +pre .keyword, +pre .winutils, +pre .method, +pre .addition, +pre .css .tag, +pre .request, +pre .status, +pre .nginx .title { + color: #859900; +} + +pre .number, +pre .command, +pre .string, +pre .tag .value, +pre .phpdoc, +pre .tex .formula, +pre .regexp, +pre .hexcolor { + color: #2aa198; +} + +pre .title, +pre .localvars, +pre .chunk, +pre .decorator, +pre .built_in, +pre .identifier, +pre .vhdl .literal, +pre .id { + color: #268bd2; +} + +pre .attribute, +pre .variable, +pre .lisp .body, +pre .smalltalk .number, +pre .constant, +pre .class .title, +pre .parent, +pre .haskell .type { + color: #b58900; +} + +pre .preprocessor, +pre .preprocessor .keyword, +pre .shebang, +pre .symbol, +pre .symbol .string, +pre .diff .change, +pre .special, +pre .attr_selector, +pre .important, +pre .subst, +pre .cdata, +pre .clojure .title { + color: #cb4b16; +} + +pre .deletion { + color: #dc322f; +} + +pre .tex .formula { + background: #073642; +} diff --git a/inc/highlight.js/styles/solarized_light.css b/inc/highlight.js/styles/solarized_light.css new file mode 100644 index 0000000..a92ecac --- /dev/null +++ b/inc/highlight.js/styles/solarized_light.css @@ -0,0 +1,88 @@ +/* + +Orginal Style from ethanschoonover.com/solarized (c) Jeremy Hull + +*/ + +pre code { + display: block; padding: 0.5em; + background: #fdf6e3; color: #657b83; +} + +pre .comment, +pre .template_comment, +pre .diff .header, +pre .doctype, +pre .pi, +pre .lisp .string, +pre .javadoc { + color: #93a1a1; + font-style: italic; +} + +pre .keyword, +pre .winutils, +pre .method, +pre .addition, +pre .css .tag, +pre .request, +pre .status, +pre .nginx .title { + color: #859900; +} + +pre .number, +pre .command, +pre .string, +pre .tag .value, +pre .phpdoc, +pre .tex .formula, +pre .regexp, +pre .hexcolor { + color: #2aa198; +} + +pre .title, +pre .localvars, +pre .chunk, +pre .decorator, +pre .built_in, +pre .identifier, +pre .vhdl .literal, +pre .id { + color: #268bd2; +} + +pre .attribute, +pre .variable, +pre .lisp .body, +pre .smalltalk .number, +pre .constant, +pre .class .title, +pre .parent, +pre .haskell .type { + color: #b58900; +} + +pre .preprocessor, +pre .preprocessor .keyword, +pre .shebang, +pre .symbol, +pre .symbol .string, +pre .diff .change, +pre .special, +pre .attr_selector, +pre .important, +pre .subst, +pre .cdata, +pre .clojure .title { + color: #cb4b16; +} + +pre .deletion { + color: #dc322f; +} + +pre .tex .formula { + background: #eee8d5; +} diff --git a/inc/highlight.js/styles/sunburst.css b/inc/highlight.js/styles/sunburst.css new file mode 100644 index 0000000..28c4ffc --- /dev/null +++ b/inc/highlight.js/styles/sunburst.css @@ -0,0 +1,158 @@ +/* + +Sunburst-like style (c) Vasily Polovnyov + +*/ + +pre code { + display: block; padding: 0.5em; + background: #000; color: #f8f8f8; +} + +pre .comment, +pre .template_comment, +pre .javadoc { + color: #aeaeae; + font-style: italic; +} + +pre .keyword, +pre .ruby .function .keyword, +pre .request, +pre .status, +pre .nginx .title { + color: #E28964; +} + +pre .function .keyword, +pre .sub .keyword, +pre .method, +pre .list .title { + color: #99CF50; +} + +pre .string, +pre .tag .value, +pre .cdata, +pre .filter .argument, +pre .attr_selector, +pre .apache .cbracket, +pre .date, +pre .tex .command { + color: #65B042; +} + +pre .subst { + color: #DAEFA3; +} + +pre .regexp { + color: #E9C062; +} + +pre .title, +pre .sub .identifier, +pre .pi, +pre .tag, +pre .tag .keyword, +pre .decorator, +pre .shebang, +pre .prompt { + color: #89BDFF; +} + +pre .class .title, +pre .haskell .type, +pre .smalltalk .class, +pre .javadoctag, +pre .yardoctag, +pre .phpdoc { + text-decoration: underline; +} + +pre .symbol, +pre .ruby .symbol .string, +pre .number { + color: #3387CC; +} + +pre .params, +pre .variable, +pre .clojure .attribute { + color: #3E87E3; +} + +pre .css .tag, +pre .rules .property, +pre .pseudo, +pre .tex .special { + color: #CDA869; +} + +pre .css .class { + color: #9B703F; +} + +pre .rules .keyword { + color: #C5AF75; +} + +pre .rules .value { + color: #CF6A4C; +} + +pre .css .id { + color: #8B98AB; +} + +pre .annotation, +pre .apache .sqbracket, +pre .nginx .built_in { + color: #9B859D; +} + +pre .preprocessor { + color: #8996A8; +} + +pre .hexcolor, +pre .css .value .number { + color: #DD7B3B; +} + +pre .css .function { + color: #DAD085; +} + +pre .diff .header, +pre .chunk, +pre .tex .formula { + background-color: #0E2231; + color: #F8F8F8; + font-style: italic; +} + +pre .diff .change { + background-color: #4A410D; + color: #F8F8F8; +} + +pre .addition { + background-color: #253B22; + color: #F8F8F8; +} + +pre .deletion { + background-color: #420E09; + color: #F8F8F8; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} diff --git a/inc/highlight.js/styles/tomorrow-night-blue.css b/inc/highlight.js/styles/tomorrow-night-blue.css new file mode 100644 index 0000000..7d2700c --- /dev/null +++ b/inc/highlight.js/styles/tomorrow-night-blue.css @@ -0,0 +1,52 @@ +/* Tomorrow Night Blue Theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ +.tomorrow-comment, pre .comment, pre .title { + color: #7285b7; +} + +.tomorrow-red, pre .variable, pre .attribute, pre .tag, pre .regexp, pre .ruby .constant, pre .xml .tag .title, pre .xml .pi, pre .xml .doctype, pre .html .doctype, pre .css .id, pre .css .class, pre .css .pseudo { + color: #ff9da4; +} + +.tomorrow-orange, pre .number, pre .preprocessor, pre .built_in, pre .literal, pre .params, pre .constant { + color: #ffc58f; +} + +.tomorrow-yellow, pre .class, pre .ruby .class .title, pre .css .rules .attribute { + color: #ffeead; +} + +.tomorrow-green, pre .string, pre .value, pre .inheritance, pre .header, pre .ruby .symbol, pre .xml .cdata { + color: #d1f1a9; +} + +.tomorrow-aqua, pre .css .hexcolor { + color: #99ffff; +} + +.tomorrow-blue, pre .function, pre .python .decorator, pre .python .title, pre .ruby .function .title, pre .ruby .title .keyword, pre .perl .sub, pre .javascript .title, pre .coffeescript .title { + color: #bbdaff; +} + +.tomorrow-purple, pre .keyword, pre .javascript .function { + color: #ebbbff; +} + +pre code { + display: block; + background: #002451; + color: white; + padding: 0.5em; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} diff --git a/inc/highlight.js/styles/tomorrow-night-bright.css b/inc/highlight.js/styles/tomorrow-night-bright.css new file mode 100644 index 0000000..6dd88e1 --- /dev/null +++ b/inc/highlight.js/styles/tomorrow-night-bright.css @@ -0,0 +1,51 @@ +/* Tomorrow Night Bright Theme */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ +.tomorrow-comment, pre .comment, pre .title { + color: #969896; +} + +.tomorrow-red, pre .variable, pre .attribute, pre .tag, pre .regexp, pre .ruby .constant, pre .xml .tag .title, pre .xml .pi, pre .xml .doctype, pre .html .doctype, pre .css .id, pre .css .class, pre .css .pseudo { + color: #d54e53; +} + +.tomorrow-orange, pre .number, pre .preprocessor, pre .built_in, pre .literal, pre .params, pre .constant { + color: #e78c45; +} + +.tomorrow-yellow, pre .class, pre .ruby .class .title, pre .css .rules .attribute { + color: #e7c547; +} + +.tomorrow-green, pre .string, pre .value, pre .inheritance, pre .header, pre .ruby .symbol, pre .xml .cdata { + color: #b9ca4a; +} + +.tomorrow-aqua, pre .css .hexcolor { + color: #70c0b1; +} + +.tomorrow-blue, pre .function, pre .python .decorator, pre .python .title, pre .ruby .function .title, pre .ruby .title .keyword, pre .perl .sub, pre .javascript .title, pre .coffeescript .title { + color: #7aa6da; +} + +.tomorrow-purple, pre .keyword, pre .javascript .function { + color: #c397d8; +} + +pre code { + display: block; + background: black; + color: #eaeaea; + padding: 0.5em; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} diff --git a/inc/highlight.js/styles/tomorrow-night-eighties.css b/inc/highlight.js/styles/tomorrow-night-eighties.css new file mode 100644 index 0000000..48011eb --- /dev/null +++ b/inc/highlight.js/styles/tomorrow-night-eighties.css @@ -0,0 +1,51 @@ +/* Tomorrow Night Eighties Theme */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ +.tomorrow-comment, pre .comment, pre .title { + color: #999999; +} + +.tomorrow-red, pre .variable, pre .attribute, pre .tag, pre .regexp, pre .ruby .constant, pre .xml .tag .title, pre .xml .pi, pre .xml .doctype, pre .html .doctype, pre .css .id, pre .css .class, pre .css .pseudo { + color: #f2777a; +} + +.tomorrow-orange, pre .number, pre .preprocessor, pre .built_in, pre .literal, pre .params, pre .constant { + color: #f99157; +} + +.tomorrow-yellow, pre .class, pre .ruby .class .title, pre .css .rules .attribute { + color: #ffcc66; +} + +.tomorrow-green, pre .string, pre .value, pre .inheritance, pre .header, pre .ruby .symbol, pre .xml .cdata { + color: #99cc99; +} + +.tomorrow-aqua, pre .css .hexcolor { + color: #66cccc; +} + +.tomorrow-blue, pre .function, pre .python .decorator, pre .python .title, pre .ruby .function .title, pre .ruby .title .keyword, pre .perl .sub, pre .javascript .title, pre .coffeescript .title { + color: #6699cc; +} + +.tomorrow-purple, pre .keyword, pre .javascript .function { + color: #cc99cc; +} + +pre code { + display: block; + background: #2d2d2d; + color: #cccccc; + padding: 0.5em; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} diff --git a/inc/highlight.js/styles/tomorrow-night.css b/inc/highlight.js/styles/tomorrow-night.css new file mode 100644 index 0000000..cf2c44d --- /dev/null +++ b/inc/highlight.js/styles/tomorrow-night.css @@ -0,0 +1,52 @@ +/* Tomorrow Night Theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ +.tomorrow-comment, pre .comment, pre .title { + color: #969896; +} + +.tomorrow-red, pre .variable, pre .attribute, pre .tag, pre .regexp, pre .ruby .constant, pre .xml .tag .title, pre .xml .pi, pre .xml .doctype, pre .html .doctype, pre .css .id, pre .css .class, pre .css .pseudo { + color: #cc6666; +} + +.tomorrow-orange, pre .number, pre .preprocessor, pre .built_in, pre .literal, pre .params, pre .constant { + color: #de935f; +} + +.tomorrow-yellow, pre .class, pre .ruby .class .title, pre .css .rules .attribute { + color: #f0c674; +} + +.tomorrow-green, pre .string, pre .value, pre .inheritance, pre .header, pre .ruby .symbol, pre .xml .cdata { + color: #b5bd68; +} + +.tomorrow-aqua, pre .css .hexcolor { + color: #8abeb7; +} + +.tomorrow-blue, pre .function, pre .python .decorator, pre .python .title, pre .ruby .function .title, pre .ruby .title .keyword, pre .perl .sub, pre .javascript .title, pre .coffeescript .title { + color: #81a2be; +} + +.tomorrow-purple, pre .keyword, pre .javascript .function { + color: #b294bb; +} + +pre code { + display: block; + background: #1d1f21; + color: #c5c8c6; + padding: 0.5em; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} diff --git a/inc/highlight.js/styles/tomorrow.css b/inc/highlight.js/styles/tomorrow.css new file mode 100644 index 0000000..a2240f2 --- /dev/null +++ b/inc/highlight.js/styles/tomorrow.css @@ -0,0 +1,49 @@ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ +.tomorrow-comment, pre .comment, pre .title { + color: #8e908c; +} + +.tomorrow-red, pre .variable, pre .attribute, pre .tag, pre .regexp, pre .ruby .constant, pre .xml .tag .title, pre .xml .pi, pre .xml .doctype, pre .html .doctype, pre .css .id, pre .css .class, pre .css .pseudo { + color: #c82829; +} + +.tomorrow-orange, pre .number, pre .preprocessor, pre .built_in, pre .literal, pre .params, pre .constant { + color: #f5871f; +} + +.tomorrow-yellow, pre .class, pre .ruby .class .title, pre .css .rules .attribute { + color: #eab700; +} + +.tomorrow-green, pre .string, pre .value, pre .inheritance, pre .header, pre .ruby .symbol, pre .xml .cdata { + color: #718c00; +} + +.tomorrow-aqua, pre .css .hexcolor { + color: #3e999f; +} + +.tomorrow-blue, pre .function, pre .python .decorator, pre .python .title, pre .ruby .function .title, pre .ruby .title .keyword, pre .perl .sub, pre .javascript .title, pre .coffeescript .title { + color: #4271ae; +} + +.tomorrow-purple, pre .keyword, pre .javascript .function { + color: #8959a8; +} + +pre code { + display: block; + background: white; + color: #4d4d4c; + padding: 0.5em; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} diff --git a/inc/highlight.js/styles/vs.css b/inc/highlight.js/styles/vs.css new file mode 100644 index 0000000..503d698 --- /dev/null +++ b/inc/highlight.js/styles/vs.css @@ -0,0 +1,86 @@ +/* + +Visual Studio-like style based on original C# coloring by Jason Diamond + +*/ +pre code { + display: block; padding: 0.5em; +} + +pre .comment, +pre .annotation, +pre .template_comment, +pre .diff .header, +pre .chunk, +pre .apache .cbracket { + color: rgb(0, 128, 0); +} + +pre .keyword, +pre .id, +pre .built_in, +pre .smalltalk .class, +pre .winutils, +pre .bash .variable, +pre .tex .command, +pre .request, +pre .status, +pre .nginx .title, +pre .xml .tag, +pre .xml .tag .value { + color: rgb(0, 0, 255); +} + +pre .string, +pre .title, +pre .parent, +pre .tag .value, +pre .rules .value, +pre .rules .value .number, +pre .ruby .symbol, +pre .ruby .symbol .string, +pre .aggregate, +pre .template_tag, +pre .django .variable, +pre .addition, +pre .flow, +pre .stream, +pre .apache .tag, +pre .date, +pre .tex .formula { + color: rgb(163, 21, 21); +} + +pre .ruby .string, +pre .decorator, +pre .filter .argument, +pre .localvars, +pre .array, +pre .attr_selector, +pre .pseudo, +pre .pi, +pre .doctype, +pre .deletion, +pre .envvar, +pre .shebang, +pre .preprocessor, +pre .userType, +pre .apache .sqbracket, +pre .nginx .built_in, +pre .tex .special, +pre .prompt { + color: rgb(43, 145, 175); +} + +pre .phpdoc, +pre .javadoc, +pre .xmlDocTag { + color: rgb(128, 128, 128); +} + +pre .vhdl .typename { font-weight: bold; } +pre .vhdl .string { color: #666666; } +pre .vhdl .literal { color: rgb(163, 21, 21); } +pre .vhdl .attribute { color: #00B0E8; } + +pre .xml .attribute { color: rgb(255, 0, 0); } diff --git a/inc/highlight.js/styles/xcode.css b/inc/highlight.js/styles/xcode.css new file mode 100644 index 0000000..04f7bf9 --- /dev/null +++ b/inc/highlight.js/styles/xcode.css @@ -0,0 +1,154 @@ +/* + +XCode style (c) Angel Garcia + +*/ + +pre code { + display: block; padding: 0.5em; + background: #fff; color: black; +} + +pre .comment, +pre .template_comment, +pre .javadoc, +pre .comment * { + color: rgb(0,106,0); +} + +pre .keyword, +pre .literal, +pre .nginx .title { + color: rgb(170,13,145); +} +pre .method, +pre .list .title, +pre .tag .title, +pre .setting .value, +pre .winutils, +pre .tex .command, +pre .http .title, +pre .request, +pre .status { + color: #008; +} + +pre .envvar, +pre .tex .special { + color: #660; +} + +pre .string { + color: rgb(196,26,22); +} +pre .tag .value, +pre .cdata, +pre .filter .argument, +pre .attr_selector, +pre .apache .cbracket, +pre .date, +pre .regexp { + color: #080; +} + +pre .sub .identifier, +pre .pi, +pre .tag, +pre .tag .keyword, +pre .decorator, +pre .ini .title, +pre .shebang, +pre .prompt, +pre .hexcolor, +pre .rules .value, +pre .css .value .number, +pre .symbol, +pre .symbol .string, +pre .number, +pre .css .function, +pre .clojure .title, +pre .clojure .built_in { + color: rgb(28,0,207); +} + +pre .class .title, +pre .haskell .type, +pre .smalltalk .class, +pre .javadoctag, +pre .yardoctag, +pre .phpdoc, +pre .typename, +pre .tag .attribute, +pre .doctype, +pre .class .id, +pre .built_in, +pre .setting, +pre .params, +pre .clojure .attribute { + color: rgb(92,38,153); +} + +pre .variable { + color: rgb(63,110,116); +} +pre .css .tag, +pre .rules .property, +pre .pseudo, +pre .subst { + color: #000; +} + +pre .css .class, pre .css .id { + color: #9B703F; +} + +pre .value .important { + color: #ff7700; + font-weight: bold; +} + +pre .rules .keyword { + color: #C5AF75; +} + +pre .annotation, +pre .apache .sqbracket, +pre .nginx .built_in { + color: #9B859D; +} + +pre .preprocessor, +pre .preprocessor * { + color: rgb(100,56,32); +} + +pre .tex .formula { + background-color: #EEE; + font-style: italic; +} + +pre .diff .header, +pre .chunk { + color: #808080; + font-weight: bold; +} + +pre .diff .change { + background-color: #BCCFF9; +} + +pre .addition { + background-color: #BAEEBA; +} + +pre .deletion { + background-color: #FFC8BD; +} + +pre .comment .yardoctag { + font-weight: bold; +} + +pre .method .id { + color: #000; +} diff --git a/inc/highlight.js/styles/zenburn.css b/inc/highlight.js/styles/zenburn.css new file mode 100644 index 0000000..501d6c7 --- /dev/null +++ b/inc/highlight.js/styles/zenburn.css @@ -0,0 +1,115 @@ +/* + +Zenburn style from voldmar.ru (c) Vladimir Epifanov +based on dark.css by Ivan Sagalaev + +*/ + +pre code { + display: block; padding: 0.5em; + background: #3F3F3F; + color: #DCDCDC; +} + +pre .keyword, +pre .tag, +pre .css .class, +pre .css .id, +pre .lisp .title, +pre .nginx .title, +pre .request, +pre .status, +pre .clojure .attribute { + color: #E3CEAB; +} + +pre .django .template_tag, +pre .django .variable, +pre .django .filter .argument { + color: #DCDCDC; +} + +pre .number, +pre .date { + color: #8CD0D3; +} + +pre .dos .envvar, +pre .dos .stream, +pre .variable, +pre .apache .sqbracket { + color: #EFDCBC; +} + +pre .dos .flow, +pre .diff .change, +pre .python .exception, +pre .python .built_in, +pre .literal, +pre .tex .special { + color: #EFEFAF; +} + +pre .diff .chunk, +pre .subst { + color: #8F8F8F; +} + +pre .dos .keyword, +pre .python .decorator, +pre .title, +pre .haskell .type, +pre .diff .header, +pre .ruby .class .parent, +pre .apache .tag, +pre .nginx .built_in, +pre .tex .command, +pre .prompt { + color: #efef8f; +} + +pre .dos .winutils, +pre .ruby .symbol, +pre .ruby .symbol .string, +pre .ruby .string { + color: #DCA3A3; +} + +pre .diff .deletion, +pre .string, +pre .tag .value, +pre .preprocessor, +pre .built_in, +pre .sql .aggregate, +pre .javadoc, +pre .smalltalk .class, +pre .smalltalk .localvars, +pre .smalltalk .array, +pre .css .rules .value, +pre .attr_selector, +pre .pseudo, +pre .apache .cbracket, +pre .tex .formula { + color: #CC9393; +} + +pre .shebang, +pre .diff .addition, +pre .comment, +pre .java .annotation, +pre .template_comment, +pre .pi, +pre .doctype { + color: #7F9F7F; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} + diff --git a/inc/shaarli.css b/inc/shaarli.css index b4d0414..4f713b6 100644 --- a/inc/shaarli.css +++ b/inc/shaarli.css @@ -445,5 +445,4 @@ div.dailyDate { font-size: 11pt;padding:0px; display:block; } div.dailyEntryTitle { font-size:16pt; font-weight:bold;} div.dailyEntryDescription { font-size:10pt; } -} - +} \ No newline at end of file diff --git a/inc/user.css b/inc/user.css new file mode 100644 index 0000000..210c84a --- /dev/null +++ b/inc/user.css @@ -0,0 +1,73 @@ +a { + -moz-transition: all 100ms ease-in-out; + -ms-transition: all 100ms ease-in-out; + -o-transition: all 100ms ease-in-out; + -webkit-transition: all 100ms ease-in-out; + transition: all 100ms ease-in-out; + color: #E28E3F; +} + +a:hover { + color: #F57900 +} + +pre code { + border-radius: 3px; + overflow-x: auto; + white-space: normal; +} + +.linkInfo { + float: left; + width: 17%; + margin-right: 1%; +} + +.linkcontainer { + margin-left: 17%; +} + +.linktaglist { + padding-top: 0px; +} + +.linktag { + display: inline-block; + height: auto; + margin: 4px 0; +} + +#linklist li.private { + background: inherit; + padding: 4px 10px 15px 20px; +} + +.private .linktitle a { + color: #80AD48; +} + +.private .linktitle a:hover { + color: #AAD378; +} + +#findSnippet { + background-color: #111111; + padding: 2px; +} + +#findSnippet li { + display: inline-block; + padding: 1px; + color: #EEEEEE; +} + +#findSnippet li a { + display: block; + color: #80AD48; + font-size: 105%; + text-decoration: none; +} + +#findSnippet li a:hover { + color: #AAD378; +} \ No newline at end of file diff --git a/index.php b/index.php index 3349ff7..98804f4 100644 --- a/index.php +++ b/index.php @@ -9,16 +9,16 @@ $GLOBALS['config']['DATADIR'] = 'data'; // Data subdirectory $GLOBALS['config']['CONFIG_FILE'] = $GLOBALS['config']['DATADIR'].'/config.php'; // Configuration file (user login/password) $GLOBALS['config']['DATASTORE'] = $GLOBALS['config']['DATADIR'].'/datastore.php'; // Data storage file. -$GLOBALS['config']['LINKS_PER_PAGE'] = 20; // Default links per page. +$GLOBALS['config']['LINKS_PER_PAGE'] = 30; // Default links per page. $GLOBALS['config']['IPBANS_FILENAME'] = $GLOBALS['config']['DATADIR'].'/ipbans.php'; // File storage for failures and bans. $GLOBALS['config']['BAN_AFTER'] = 4; // Ban IP after this many failures. $GLOBALS['config']['BAN_DURATION'] = 1800; // Ban duration for IP address after login failures (in seconds) (1800 sec. = 30 minutes) $GLOBALS['config']['OPEN_SHAARLI'] = false; // If true, anyone can add/edit/delete links without having to login $GLOBALS['config']['HIDE_TIMESTAMPS'] = false; // If true, the moment when links were saved are not shown to users that are not logged in. -$GLOBALS['config']['ENABLE_THUMBNAILS'] = true; // Enable thumbnails in links. +$GLOBALS['config']['ENABLE_THUMBNAILS'] = false; // Enable thumbnails in links. $GLOBALS['config']['CACHEDIR'] = 'cache'; // Cache directory for thumbnails for SLOW services (like flickr) $GLOBALS['config']['PAGECACHE'] = 'pagecache'; // Page cache directory. -$GLOBALS['config']['ENABLE_LOCALCACHE'] = true; // Enable Shaarli to store thumbnail in a local cache. Disable to reduce webspace usage. +$GLOBALS['config']['ENABLE_LOCALCACHE'] = false; // Enable Shaarli to store thumbnail in a local cache. Disable to reduce webspace usage. $GLOBALS['config']['PUBSUBHUB_URL'] = ''; // PubSubHubbub support. Put an empty string to disable, or put your hub url here to enable. $GLOBALS['config']['UPDATECHECK_FILENAME'] = $GLOBALS['config']['DATADIR'].'/lastupdatecheck.txt'; // For updates check of Shaarli. $GLOBALS['config']['UPDATECHECK_INTERVAL'] = 86400 ; // Updates check frequency for Shaarli. 86400 seconds=24 hours @@ -413,6 +413,13 @@ if (isset($_POST['login'])) // ------------------------------------------------------------------------------------------ // Misc utility functions: + +// Try to get just domain for @via +function getJustDomain($url){ + $parts = parse_url($url); + return trim($parts['host']); + } + // Returns the server URL (including port and http/https), without path. // eg. "http://myserver.com:8080" // You can append $_SERVER['SCRIPT_NAME'] to get the current script URL. @@ -770,8 +777,10 @@ class linkdb implements Iterator, Countable, ArrayAccess { $found= (strpos(strtolower($l['title']),$s)!==false) || (strpos(strtolower($l['description']),$s)!==false) + || (strpos(strtolower($l['snippet']),$s)!==false) || (strpos(strtolower($l['url']),$s)!==false) - || (strpos(strtolower($l['tags']),$s)!==false); + || (strpos(strtolower($l['tags']),$s)!==false) + || (strpos(strtolower($l['via']),$s)!==false); if ($found) $filtered[$l['linkdate']] = $l; } krsort($filtered); @@ -1395,8 +1404,7 @@ function renderPage() if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away ! $tags = trim(preg_replace('/\s\s+/',' ', $_POST['lf_tags'])); // Remove multiple spaces. $linkdate=$_POST['lf_linkdate']; - $link = array('title'=>trim($_POST['lf_title']),'url'=>trim($_POST['lf_url']),'description'=>trim($_POST['lf_description']),'private'=>(isset($_POST['lf_private']) ? 1 : 0), - 'linkdate'=>$linkdate,'tags'=>str_replace(',',' ',$tags)); + $link = array('title'=>trim($_POST['lf_title']),'url'=>trim($_POST['lf_url']),'description'=>trim($_POST['lf_description']),'snippet'=>trim($_POST['lf_snippet']),'private'=>(isset($_POST['lf_private']) ? 1 : 0),'linkdate'=>$linkdate,'tags'=>str_replace(',',' ',$tags), 'via'=>trim($_POST['lf_via'])); if ($link['title']=='') $link['title']=$link['url']; // If title is empty, use the URL as title. $LINKSDB[$linkdate] = $link; $LINKSDB->savedb(); // save to disk @@ -1470,7 +1478,7 @@ function renderPage() $link_is_new = true; // This is a new link $linkdate = strval(date('Ymd_His')); $title = (empty($_GET['title']) ? '' : $_GET['title'] ); // Get title if it was provided in URL (by the bookmarklet). - $description=''; $tags=''; $private=0; + $snippet = $via = '';$description=''; $tags=''; $private=0; if (($url!='') && parse_url($url,PHP_URL_SCHEME)=='') $url = 'http://'.$url; // If this is an HTTP link, we try go get the page to extact the title (otherwise we will to straight to the edit form.) if (empty($title) && parse_url($url,PHP_URL_SCHEME)=='http') @@ -1481,7 +1489,7 @@ function renderPage() } if ($url=='') $url='?'.smallHash($linkdate); // In case of empty URL, this is just a text (with a link that point to itself) - $link = array('linkdate'=>$linkdate,'title'=>$title,'url'=>$url,'description'=>$description,'tags'=>$tags,'private'=>0); + $link = array('linkdate'=>$linkdate,'title'=>$title,'url'=>$url,'description'=>$description,'snippet'=>$snippet,'tags'=>$tags,'via'=>$via,'private'=>0); } $PAGE = new pageBuilder; @@ -1720,6 +1728,8 @@ function buildLinkList($PAGE,$LINKSDB) { $link = $linksToDisplay[$keys[$i]]; $link['description']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description'])))); + $link['snippet']=nl2br(keepMultipleSpaces(htmlspecialchars($link['snippet']))); + $link['via']=nl2br(htmlspecialchars($link['via'])); $title=$link['title']; $classLi = $i%2!=0 ? '' : 'publicLinkHightLight'; $link['class'] = ($link['private']==0 ? $classLi : 'private'); diff --git a/tpl/editlink.html b/tpl/editlink.html index 4ad43b3..ce0925a 100644 --- a/tpl/editlink.html +++ b/tpl/editlink.html @@ -13,7 +13,9 @@ URL

Title

Description

+ Snippet

Tags

+ Via

 
diff --git a/tpl/findSnippet.html b/tpl/findSnippet.html new file mode 100644 index 0000000..94bc0d0 --- /dev/null +++ b/tpl/findSnippet.html @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/tpl/includes.html b/tpl/includes.html index 5319f45..2e81fea 100644 --- a/tpl/includes.html +++ b/tpl/includes.html @@ -6,5 +6,7 @@ + {if condition="is_file('inc/user.css')"}{/if} + diff --git a/tpl/index.php b/tpl/index.php new file mode 100644 index 0000000..5f14434 --- /dev/null +++ b/tpl/index.php @@ -0,0 +1,2331 @@ +'); // Suffix to encapsulate data in php code. + +// Force cookie path (but do not change lifetime) +$cookie=session_get_cookie_params(); +session_set_cookie_params($cookie['lifetime'],dirname($_SERVER["SCRIPT_NAME"]).'/'); // Default cookie expiration and path. + +// PHP Settings +ini_set('max_input_time','60'); // High execution time in case of problematic imports/exports. +ini_set('memory_limit', '128M'); // Try to set max upload file size and read (May not work on some hosts). +ini_set('post_max_size', '16M'); +ini_set('upload_max_filesize', '16M'); +checkphpversion(); +error_reporting(E_ALL^E_WARNING); // See all error except warnings. +//error_reporting(-1); // See all errors (for debugging only) + +include "inc/rain.tpl.class.php"; //include Rain TPL +raintpl::$tpl_dir = "tpl/"; // template directory +if (!is_dir('tmp')) { mkdir('tmp',0705); chmod('tmp',0705); } +raintpl::$cache_dir = "tmp/"; // cache directory + +ob_start(); // Output buffering for the page cache. + + +// In case stupid admin has left magic_quotes enabled in php.ini: +if (get_magic_quotes_gpc()) +{ + function stripslashes_deep($value) { $value = is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value); return $value; } + $_POST = array_map('stripslashes_deep', $_POST); + $_GET = array_map('stripslashes_deep', $_GET); + $_COOKIE = array_map('stripslashes_deep', $_COOKIE); +} + +// Prevent caching on client side or proxy: (yes, it's ugly) +header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); +header("Cache-Control: no-store, no-cache, must-revalidate"); +header("Cache-Control: post-check=0, pre-check=0", false); +header("Pragma: no-cache"); + +// Directories creations (Note that your web host may require differents rights than 705.) +if (!is_dir($GLOBALS['config']['DATADIR'])) { mkdir($GLOBALS['config']['DATADIR'],0705); chmod($GLOBALS['config']['DATADIR'],0705); } +if (!is_dir('tmp')) { mkdir('tmp',0705); chmod('tmp',0705); } // For RainTPL temporary files. +if (!is_file($GLOBALS['config']['DATADIR'].'/.htaccess')) { file_put_contents($GLOBALS['config']['DATADIR'].'/.htaccess',"Allow from none\nDeny from all\n"); } // Protect data files. +if ($GLOBALS['config']['ENABLE_LOCALCACHE']) +{ + if (!is_dir($GLOBALS['config']['CACHEDIR'])) { mkdir($GLOBALS['config']['CACHEDIR'],0705); chmod($GLOBALS['config']['CACHEDIR'],0705); } + if (!is_file($GLOBALS['config']['CACHEDIR'].'/.htaccess')) { file_put_contents($GLOBALS['config']['CACHEDIR'].'/.htaccess',"Allow from none\nDeny from all\n"); } // Protect data files. +} + +// Run config screen if first run: +if (!is_file($GLOBALS['config']['CONFIG_FILE'])) install(); + +require $GLOBALS['config']['CONFIG_FILE']; // Read login/password hash into $GLOBALS. + +// Handling of old config file which do not have the new parameters. +if (empty($GLOBALS['title'])) $GLOBALS['title']='Shared links on '.htmlspecialchars(indexUrl()); +if (empty($GLOBALS['timezone'])) $GLOBALS['timezone']=date_default_timezone_get(); +if (empty($GLOBALS['disablesessionprotection'])) $GLOBALS['disablesessionprotection']=false; + + +autoLocale(); // Sniff browser language and set date format accordingly. +header('Content-Type: text/html; charset=utf-8'); // We use UTF-8 for proper international characters handling. + +// Check php version +function checkphpversion() +{ + if (version_compare(PHP_VERSION, '5.1.0') < 0) + { + header('Content-Type: text/plain; charset=utf-8'); + echo 'Your server supports php '.PHP_VERSION.'. Shaarli requires at last php 5.1.0, and thus cannot run. Sorry.'; + exit; + } +} + +// Checks if an update is available for Shaarli. +// (at most once a day, and only for registered user.) +// Output: '' = no new version. +// other= the available version. +function checkUpdate() +{ + if (!isLoggedIn()) return ''; // Do not check versions for visitors. + + // Get latest version number at most once a day. + if (!is_file($GLOBALS['config']['UPDATECHECK_FILENAME']) || (filemtime($GLOBALS['config']['UPDATECHECK_FILENAME'])url = $url; + $this->filename = $GLOBALS['config']['PAGECACHE'].'/'.sha1($url).'.cache'; + $this->shouldBeCached = $shouldBeCached; + } + + // If the page should be cached and a cached version exists, + // returns the cached version (otherwise, return null). + public function cachedVersion() + { + if (!$this->shouldBeCached) return null; + if (is_file($this->filename)) { return file_get_contents($this->filename); exit; } + return null; + } + + // Put a page in the cache. + public function cache($page) + { + if (!$this->shouldBeCached) return; + if (!is_dir($GLOBALS['config']['PAGECACHE'])) { mkdir($GLOBALS['config']['PAGECACHE'],0705); chmod($GLOBALS['config']['PAGECACHE'],0705); } + file_put_contents($this->filename,$page); + } + + // Purge the whole cache. + // (call with pageCache::purgeCache()) + public static function purgeCache() + { + if (is_dir($GLOBALS['config']['PAGECACHE'])) + { + $handler = opendir($GLOBALS['config']['PAGECACHE']); + if ($handle!==false) + { + while (($filename = readdir($handler))!==false) + { + if (endsWith($filename,'.cache')) { unlink($GLOBALS['config']['PAGECACHE'].'/'.$filename); } + } + closedir($handler); + } + } + } + +} + + +// ----------------------------------------------------------------------------------------------- +// Log to text file +function logm($message) +{ + $t = strval(date('Y/m/d_H:i:s')).' - '.$_SERVER["REMOTE_ADDR"].' - '.strval($message)."\n"; + file_put_contents($GLOBALS['config']['DATADIR'].'/log.txt',$t,FILE_APPEND); +} + +// Same as nl2br(), but escapes < and > +function nl2br_escaped($html) +{ + return str_replace('>','>',str_replace('<','<',nl2br($html))); +} + +/* Returns the small hash of a string + eg. smallHash('20111006_131924') --> yZH23w + Small hashes: + - are unique (well, as unique as crc32, at last) + - are always 6 characters long. + - only use the following characters: a-z A-Z 0-9 - _ @ + - are NOT cryptographically secure (they CAN be forged) + In Shaarli, they are used as a tinyurl-like link to individual entries. +*/ +function smallHash($text) +{ + $t = rtrim(base64_encode(hash('crc32',$text,true)),'='); + $t = str_replace('+','-',$t); // Get rid of characters which need encoding in URLs. + $t = str_replace('/','_',$t); + $t = str_replace('=','@',$t); + return $t; +} + +// In a string, converts urls to clickable links. +// Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722 +function text2clickable($url) +{ + $redir = empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector']; + return preg_replace('!(((?:https?|ftp|file)://|apt:)\S+[[:alnum:]]/?)!si','$1',$url); +} + +// This function inserts   where relevant so that multiple spaces are properly displayed in HTML +// even in the absence of
  (This is used in description to keep text formatting)
+function keepMultipleSpaces($text)
+{
+    return str_replace('  ','  ',$text);
+    
+}
+// ------------------------------------------------------------------------------------------
+// Sniff browser language to display dates in the right format automatically.
+// (Note that is may not work on your server if the corresponding local is not installed.)
+function autoLocale()
+{
+    $loc='en_US'; // Default if browser does not send HTTP_ACCEPT_LANGUAGE
+    if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) // eg. "fr,fr-fr;q=0.8,en;q=0.5,en-us;q=0.3"
+    {   // (It's a bit crude, but it works very well. Prefered language is always presented first.)
+        if (preg_match('/([a-z]{2}(-[a-z]{2})?)/i',$_SERVER['HTTP_ACCEPT_LANGUAGE'],$matches)) $loc=$matches[1];
+    }
+    setlocale(LC_TIME,$loc);  // LC_TIME = Set local for date/time format only.
+}
+
+// ------------------------------------------------------------------------------------------
+// PubSubHubbub protocol support (if enabled)  [UNTESTED]
+// (Source: http://aldarone.fr/les-flux-rss-shaarli-et-pubsubhubbub/ )
+if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) include './publisher.php';
+function pubsubhub()
+{
+    if (!empty($GLOBALS['config']['PUBSUBHUB_URL']))
+    {
+       $p = new Publisher($GLOBALS['config']['PUBSUBHUB_URL']);
+       $topic_url = array (
+                       indexUrl().'?do=atom',
+                       indexUrl().'?do=rss'
+                    );
+       $p->publish_update($topic_url);
+    }
+}
+
+// ------------------------------------------------------------------------------------------
+// Session management
+define('INACTIVITY_TIMEOUT',3600); // (in seconds). If the user does not access any page within this time, his/her session is considered expired.
+ini_set('session.use_cookies', 1);       // Use cookies to store session.
+ini_set('session.use_only_cookies', 1);  // Force cookies for session (phpsessionID forbidden in URL)
+ini_set('session.use_trans_sid', false); // Prevent php to use sessionID in URL if cookies are disabled.
+session_name('shaarli');
+session_start();
+
+// Returns the IP address of the client (Used to prevent session cookie hijacking.)
+function allIPs()
+{
+    $ip = $_SERVER["REMOTE_ADDR"];
+    // Then we use more HTTP headers to prevent session hijacking from users behind the same proxy.
+    if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip=$ip.'_'.$_SERVER['HTTP_X_FORWARDED_FOR']; }
+    if (isset($_SERVER['HTTP_CLIENT_IP'])) { $ip=$ip.'_'.$_SERVER['HTTP_CLIENT_IP']; }
+    return $ip;
+}
+
+// Check that user/password is correct.
+function check_auth($login,$password)
+{
+    $hash = sha1($password.$login.$GLOBALS['salt']);
+    if ($login==$GLOBALS['login'] && $hash==$GLOBALS['hash'])
+    {   // Login/password is correct.
+        $_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand()); // generate unique random number (different than phpsessionid)
+        $_SESSION['ip']=allIPs();                // We store IP address(es) of the client to make sure session is not hijacked.
+        $_SESSION['username']=$login;
+        $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT;  // Set session expiration.
+        logm('Login successful');
+        return True;
+    }
+    logm('Login failed for user '.$login);
+    return False;
+}
+
+// Returns true if the user is logged in.
+function isLoggedIn()
+{
+    if ($GLOBALS['config']['OPEN_SHAARLI']) return true;
+
+    // If session does not exist on server side, or IP address has changed, or session has expired, logout.
+    if (empty($_SESSION['uid']) || ($GLOBALS['disablesessionprotection']==false && $_SESSION['ip']!=allIPs()) || time()>=$_SESSION['expires_on'])
+    {
+        logout();
+        return false;
+    }
+    if (!empty($_SESSION['longlastingsession']))  $_SESSION['expires_on']=time()+$_SESSION['longlastingsession']; // In case of "Stay signed in" checked.
+    else $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Standard session expiration date.
+
+    return true;
+}
+
+// Force logout.
+function logout() { if (isset($_SESSION)) { unset($_SESSION['uid']); unset($_SESSION['ip']); unset($_SESSION['username']);}  }
+
+
+// ------------------------------------------------------------------------------------------
+// Brute force protection system
+// Several consecutive failed logins will ban the IP address for 30 minutes.
+if (!is_file($GLOBALS['config']['IPBANS_FILENAME'])) file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "array(),'BANS'=>array()),true).";\n?>");
+include $GLOBALS['config']['IPBANS_FILENAME'];
+// Signal a failed login. Will ban the IP if too many failures:
+function ban_loginFailed()
+{
+    $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS'];
+    if (!isset($gb['FAILURES'][$ip])) $gb['FAILURES'][$ip]=0;
+    $gb['FAILURES'][$ip]++;
+    if ($gb['FAILURES'][$ip]>($GLOBALS['config']['BAN_AFTER']-1))
+    {
+        $gb['BANS'][$ip]=time()+$GLOBALS['config']['BAN_DURATION'];
+        logm('IP address banned from login');
+    }
+    $GLOBALS['IPBANS'] = $gb;
+    file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "");
+}
+
+// Signals a successful login. Resets failed login counter.
+function ban_loginOk()
+{
+    $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS'];
+    unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]);
+    $GLOBALS['IPBANS'] = $gb;
+    file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "");
+}
+
+// Checks if the user CAN login. If 'true', the user can try to login.
+function ban_canLogin()
+{
+    $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS'];
+    if (isset($gb['BANS'][$ip]))
+    {
+        // User is banned. Check if the ban has expired:
+        if ($gb['BANS'][$ip]<=time())
+        {   // Ban expired, user can try to login again.
+            logm('Ban lifted.');
+            unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]);
+            file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "");
+            return true; // Ban has expired, user can login.
+        }
+        return false; // User is banned.
+    }
+    return true; // User is not banned.
+}
+
+// ------------------------------------------------------------------------------------------
+// Process login form: Check if login/password is correct.
+if (isset($_POST['login']))
+{
+    if (!ban_canLogin()) die('I said: NO. You are banned for the moment. Go away.');
+    if (isset($_POST['password']) && tokenOk($_POST['token']) && (check_auth($_POST['login'], $_POST['password'])))
+    {   // Login/password is ok.
+        ban_loginOk();
+        // If user wants to keep the session cookie even after the browser closes:
+        if (!empty($_POST['longlastingsession']))
+        {
+            $_SESSION['longlastingsession']=31536000;  // (31536000 seconds = 1 year)
+            $_SESSION['expires_on']=time()+$_SESSION['longlastingsession'];  // Set session expiration on server-side.
+            session_set_cookie_params($_SESSION['longlastingsession'],dirname($_SERVER["SCRIPT_NAME"]).'/'); // Set session cookie expiration on client side
+            // Note: Never forget the trailing slash on the cookie path !
+            session_regenerate_id(true);  // Send cookie with new expiration date to browser.
+        }
+        else // Standard session expiration (=when browser closes)
+        {
+            session_set_cookie_params(0,dirname($_SERVER["SCRIPT_NAME"]).'/'); // 0 means "When browser closes"
+            session_regenerate_id(true);
+        }
+        // Optional redirect after login:
+        if (isset($_GET['post'])) { header('Location: ?post='.urlencode($_GET['post']).(!empty($_GET['title'])?'&title='.urlencode($_GET['title']):'').(!empty($_GET['source'])?'&source='.urlencode($_GET['source']):'')); exit; }
+        if (isset($_POST['returnurl']))
+        {
+            if (endsWith($_POST['returnurl'],'?do=login')) { header('Location: ?'); exit; } // Prevent loops over login screen.
+            header('Location: '.$_POST['returnurl']); exit;
+        }
+        header('Location: ?'); exit;
+    }
+    else
+    {
+        ban_loginFailed();
+        echo ''; // Redirect to login screen.
+        exit;
+    }
+}
+
+// ------------------------------------------------------------------------------------------
+// Misc utility functions:
+
+
+// Try to get just domain for @via 
+function getJustDomain($url){
+    $parts = parse_url($url);
+    return trim($parts['host']);
+    }
+
+// Returns the server URL (including port and http/https), without path.
+// eg. "http://myserver.com:8080"
+// You can append $_SERVER['SCRIPT_NAME'] to get the current script URL.
+function serverUrl()
+{
+    $https = (!empty($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS'])=='on')) || $_SERVER["SERVER_PORT"]=='443'; // HTTPS detection.
+    $serverport = ($_SERVER["SERVER_PORT"]=='80' || ($https && $_SERVER["SERVER_PORT"]=='443') ? '' : ':'.$_SERVER["SERVER_PORT"]);
+    return 'http'.($https?'s':'').'://'.$_SERVER["SERVER_NAME"].$serverport;
+}
+
+// Returns the absolute URL of current script, without the query.
+// (eg. http://sebsauvage.net/links/)
+function indexUrl()
+{
+    return serverUrl() . ($_SERVER["SCRIPT_NAME"] == '/index.php' ? '/' : $_SERVER["SCRIPT_NAME"]);
+}
+
+// Returns the absolute URL of current script, WITH the query.
+// (eg. http://sebsauvage.net/links/?toto=titi&spamspamspam=humbug)
+function pageUrl()
+{
+    return indexUrl().(!empty($_SERVER["QUERY_STRING"]) ? '?'.$_SERVER["QUERY_STRING"] : '');
+}
+
+// Convert post_max_size/upload_max_filesize (eg.'16M') parameters to bytes.
+function return_bytes($val)
+{
+    $val = trim($val); $last=strtolower($val[strlen($val)-1]);
+    switch($last)
+    {
+        case 'g': $val *= 1024;
+        case 'm': $val *= 1024;
+        case 'k': $val *= 1024;
+    }
+    return $val;
+}
+
+// Try to determine max file size for uploads (POST).
+// Returns an integer (in bytes)
+function getMaxFileSize()
+{
+    $size1 = return_bytes(ini_get('post_max_size'));
+    $size2 = return_bytes(ini_get('upload_max_filesize'));
+    // Return the smaller of two:
+    $maxsize = min($size1,$size2);
+    // FIXME: Then convert back to readable notations ? (eg. 2M instead of 2000000)
+    return $maxsize;
+}
+
+// Tells if a string start with a substring or not.
+function startsWith($haystack,$needle,$case=true)
+{
+    if($case){return (strcmp(substr($haystack, 0, strlen($needle)),$needle)===0);}
+    return (strcasecmp(substr($haystack, 0, strlen($needle)),$needle)===0);
+}
+
+// Tells if a string ends with a substring or not.
+function endsWith($haystack,$needle,$case=true)
+{
+    if($case){return (strcmp(substr($haystack, strlen($haystack) - strlen($needle)),$needle)===0);}
+    return (strcasecmp(substr($haystack, strlen($haystack) - strlen($needle)),$needle)===0);
+}
+
+/*  Converts a linkdate time (YYYYMMDD_HHMMSS) of an article to a timestamp (Unix epoch)
+    (used to build the ADD_DATE attribute in Netscape-bookmarks file)
+    PS: I could have used strptime(), but it does not exist on Windows. I'm too kind. */
+function linkdate2timestamp($linkdate)
+{
+    $Y=$M=$D=$h=$m=$s=0;
+    $r = sscanf($linkdate,'%4d%2d%2d_%2d%2d%2d',$Y,$M,$D,$h,$m,$s);
+    return mktime($h,$m,$s,$M,$D,$Y);
+}
+
+/*  Converts a linkdate time (YYYYMMDD_HHMMSS) of an article to a RFC822 date.
+    (used to build the pubDate attribute in RSS feed.)  */
+function linkdate2rfc822($linkdate)
+{
+    return date('r',linkdate2timestamp($linkdate)); // 'r' is for RFC822 date format.
+}
+
+/*  Converts a linkdate time (YYYYMMDD_HHMMSS) of an article to a ISO 8601 date.
+    (used to build the updated tags in ATOM feed.)  */
+function linkdate2iso8601($linkdate)
+{
+    return date('c',linkdate2timestamp($linkdate)); // 'c' is for ISO 8601 date format.
+}
+
+/*  Converts a linkdate time (YYYYMMDD_HHMMSS) of an article to a localized date format.
+    (used to display link date on screen)
+    The date format is automatically chosen according to locale/languages sniffed from browser headers (see autoLocale()). */
+function linkdate2locale($linkdate)
+{
+    return utf8_encode(strftime('%c',linkdate2timestamp($linkdate))); // %c is for automatic date format according to locale.
+    // Note that if you use a local which is not installed on your webserver,
+    // the date will not be displayed in the chosen locale, but probably in US notation.
+}
+
+// Parse HTTP response headers and return an associative array.
+function http_parse_headers_shaarli( $headers )
+{
+    $res=array();
+    foreach($headers as $header)
+    {
+        $i = strpos($header,': ');
+        if ($i!==false)
+        {
+            $key=substr($header,0,$i);
+            $value=substr($header,$i+2,strlen($header)-$i-2);
+            $res[$key]=$value;
+        }
+    }
+    return $res;
+}
+
+/* GET an URL.
+   Input: $url : url to get (http://...)
+          $timeout : Network timeout (will wait this many seconds for an anwser before giving up).
+   Output: An array.  [0] = HTTP status message (eg. "HTTP/1.1 200 OK") or error message
+                      [1] = associative array containing HTTP response headers (eg. echo getHTTP($url)[1]['Content-Type'])
+                      [2] = data
+    Example: list($httpstatus,$headers,$data) = getHTTP('http://sebauvage.net/');
+             if (strpos($httpstatus,'200 OK')!==false)
+                 echo 'Data type: '.htmlspecialchars($headers['Content-Type']);
+             else
+                 echo 'There was an error: '.htmlspecialchars($httpstatus)
+*/
+function getHTTP($url,$timeout=30)
+{
+    try
+    {
+        $options = array('http'=>array('method'=>'GET','timeout' => $timeout)); // Force network timeout
+        $context = stream_context_create($options);
+        $data=file_get_contents($url,false,$context,-1, 4000000); // We download at most 4 Mb from source.
+        if (!$data) { return array('HTTP Error',array(),''); }
+        $httpStatus=$http_response_header[0]; // eg. "HTTP/1.1 200 OK"
+        $responseHeaders=http_parse_headers_shaarli($http_response_header);
+        return array($httpStatus,$responseHeaders,$data);
+    }
+    catch (Exception $e)  // getHTTP *can* fail silentely (we don't care if the title cannot be fetched)
+    {
+        return array($e->getMessage(),'','');
+    }
+}
+
+// Extract title from an HTML document.
+// (Returns an empty string if not found.)
+function html_extract_title($html)
+{
+  return preg_match('!(.*?)!is', $html, $matches) ? trim(str_replace("\n",' ', $matches[1])) : '' ;
+}
+
+// ------------------------------------------------------------------------------------------
+// Token management for XSRF protection
+// Token should be used in any form which acts on data (create,update,delete,import...).
+if (!isset($_SESSION['tokens'])) $_SESSION['tokens']=array();  // Token are attached to the session.
+
+// Returns a token.
+function getToken()
+{
+    $rnd = sha1(uniqid('',true).'_'.mt_rand());  // We generate a random string.
+    $_SESSION['tokens'][$rnd]=1;  // Store it on the server side.
+    return $rnd;
+}
+
+// Tells if a token is ok. Using this function will destroy the token.
+// true=token is ok.
+function tokenOk($token)
+{
+    if (isset($_SESSION['tokens'][$token]))
+    {
+        unset($_SESSION['tokens'][$token]); // Token is used: destroy it.
+        return true; // Token is ok.
+    }
+    return false; // Wrong token, or already used.
+}
+
+// ------------------------------------------------------------------------------------------
+/* This class is in charge of building the final page.
+   (This is basically a wrapper around RainTPL which pre-fills some fields.)
+   p = new pageBuilder;
+   p.assign('myfield','myvalue');
+   p.renderPage('mytemplate');
+   
+*/
+class pageBuilder
+{
+    private $tpl; // RainTPL template
+
+    function __construct()
+    {
+        $this->tpl=false;
+    } 
+
+    private function initialize()
+    {    
+        $this->tpl = new RainTPL;    
+        $this->tpl->assign('newversion',checkUpdate());
+        $this->tpl->assign('feedurl',htmlspecialchars(indexUrl()));
+        $searchcrits=''; // Search criteria
+        if (!empty($_GET['searchtags'])) $searchcrits.='&searchtags='.urlencode($_GET['searchtags']);
+        elseif (!empty($_GET['searchterm'])) $searchcrits.='&searchterm='.urlencode($_GET['searchterm']);
+        $this->tpl->assign('searchcrits',$searchcrits);
+        $this->tpl->assign('source',indexUrl());
+        $this->tpl->assign('version',shaarli_version);
+        $this->tpl->assign('scripturl',indexUrl());
+        $this->tpl->assign('pagetitle','Shaarli');
+        $this->tpl->assign('privateonly',!empty($_SESSION['privateonly'])); // Show only private links ?
+        if (!empty($GLOBALS['title'])) $this->tpl->assign('pagetitle',$GLOBALS['title']);
+        if (!empty($GLOBALS['pagetitle'])) $this->tpl->assign('pagetitle',$GLOBALS['pagetitle']);
+        $this->tpl->assign('shaarlititle',empty($GLOBALS['title']) ? 'Shaarli': $GLOBALS['title'] );
+        return;    
+    }
+    
+    // The following assign() method is basically the same as RainTPL (except that it's lazy)
+    public function assign($what,$where)
+    {
+        if ($this->tpl===false) $this->initialize(); // Lazy initialization
+        $this->tpl->assign($what,$where);
+    }
+    
+    // Render a specific page (using a template).
+    // eg. pb.renderPage('picwall')
+    public function renderPage($page)
+    {
+        if ($this->tpl===false) $this->initialize(); // Lazy initialization
+        $this->tpl->draw($page);
+    }
+}
+
+// ------------------------------------------------------------------------------------------
+/* Data storage for links.
+   This object behaves like an associative array.
+   Example:
+      $mylinks = new linkdb();
+      echo $mylinks['20110826_161819']['title'];
+      foreach($mylinks as $link)
+         echo $link['title'].' at url '.$link['url'].' ; description:'.$link['description'];
+   
+   Available keys:
+       title : Title of the link
+       url : URL of the link. Can be absolute or relative. Relative URLs are permalinks (eg.'?m-ukcw')
+       description : description of the entry
+       private : Is this link private ? 0=no, other value=yes
+       linkdate : date of the creation of this entry, in the form YYYYMMDD_HHMMSS (eg.'20110914_192317')
+       tags : tags attached to this entry (separated by spaces)                   
+
+   We implement 3 interfaces:
+     - ArrayAccess so that this object behaves like an associative array.
+     - Iterator so that this object can be used in foreach() loops.
+     - Countable interface so that we can do a count() on this object.
+*/
+class linkdb implements Iterator, Countable, ArrayAccess
+{
+    private $links; // List of links (associative array. Key=linkdate (eg. "20110823_124546"), value= associative array (keys:title,description...)
+    private $urls;  // List of all recorded URLs (key=url, value=linkdate) for fast reserve search (url-->linkdate)
+    private $keys;  // List of linkdate keys (for the Iterator interface implementation)
+    private $position; // Position in the $this->keys array. (for the Iterator interface implementation.)
+    private $loggedin; // Is the used logged in ? (used to filter private links)
+
+    // Constructor:
+    function __construct($isLoggedIn)
+    // Input : $isLoggedIn : is the used logged in ?
+    {
+        $this->loggedin = $isLoggedIn;
+        $this->checkdb(); // Make sure data file exists.
+        $this->readdb();  // Then read it.
+    }
+
+    // ---- Countable interface implementation
+    public function count() { return count($this->links); }
+
+    // ---- ArrayAccess interface implementation
+    public function offsetSet($offset, $value)
+    {
+        if (!$this->loggedin) die('You are not authorized to add a link.');
+        if (empty($value['linkdate']) || empty($value['url'])) die('Internal Error: A link should always have a linkdate and url.');
+        if (empty($offset)) die('You must specify a key.');
+        $this->links[$offset] = $value;
+        $this->urls[$value['url']]=$offset;
+    }
+    public function offsetExists($offset) { return array_key_exists($offset,$this->links); }
+    public function offsetUnset($offset)
+    {
+        if (!$this->loggedin) die('You are not authorized to delete a link.');
+        $url = $this->links[$offset]['url']; unset($this->urls[$url]);
+        unset($this->links[$offset]);
+    }
+    public function offsetGet($offset) { return isset($this->links[$offset]) ? $this->links[$offset] : null; }
+
+    // ---- Iterator interface implementation
+    function rewind() { $this->keys=array_keys($this->links); rsort($this->keys); $this->position=0; } // Start over for iteration, ordered by date (latest first).
+    function key() { return $this->keys[$this->position]; } // current key
+    function current() { return $this->links[$this->keys[$this->position]]; } // current value
+    function next() { ++$this->position; } // go to next item
+    function valid() { return isset($this->keys[$this->position]); }    // Check if current position is valid.
+
+    // ---- Misc methods
+    private function checkdb() // Check if db directory and file exists.
+    {
+        if (!file_exists($GLOBALS['config']['DATASTORE'])) // Create a dummy database for example.
+        {
+             $this->links = array();
+             $link = array('title'=>'Shaarli - sebsauvage.net','url'=>'http://sebsauvage.net/wiki/doku.php?id=php:shaarli','description'=>'Welcome to Shaarli ! This is a bookmark. To edit or delete me, you must first login.','private'=>0,'linkdate'=>'20110914_190000','tags'=>'opensource software');
+             $this->links[$link['linkdate']] = $link;
+             $link = array('title'=>'My secret stuff... - Pastebin.com','url'=>'http://pastebin.com/smCEEeSn','description'=>'SShhhh!!  I\'m a private link only YOU can see. You can delete me too.','private'=>1,'linkdate'=>'20110914_074522','tags'=>'secretstuff');
+             $this->links[$link['linkdate']] = $link;
+             file_put_contents($GLOBALS['config']['DATASTORE'], PHPPREFIX.base64_encode(gzdeflate(serialize($this->links))).PHPSUFFIX); // Write database to disk
+        }
+    }
+
+    // Read database from disk to memory
+    private function readdb()
+    {
+        // Read data
+        $this->links=(file_exists($GLOBALS['config']['DATASTORE']) ? unserialize(gzinflate(base64_decode(substr(file_get_contents($GLOBALS['config']['DATASTORE']),strlen(PHPPREFIX),-strlen(PHPSUFFIX))))) : array() );
+        // Note that gzinflate is faster than gzuncompress. See: http://www.php.net/manual/en/function.gzdeflate.php#96439
+
+        // If user is not logged in, filter private links.
+        if (!$this->loggedin)
+        {
+            $toremove=array();
+            foreach($this->links as $link) { if ($link['private']!=0) $toremove[]=$link['linkdate']; }
+            foreach($toremove as $linkdate) { unset($this->links[$linkdate]); }
+        }
+
+        // Keep the list of the mapping URLs-->linkdate up-to-date.
+        $this->urls=array();
+        foreach($this->links as $link) { $this->urls[$link['url']]=$link['linkdate']; }
+    }
+
+    // Save database from memory to disk.
+    public function savedb()
+    {
+        if (!$this->loggedin) die('You are not authorized to change the database.');
+        file_put_contents($GLOBALS['config']['DATASTORE'], PHPPREFIX.base64_encode(gzdeflate(serialize($this->links))).PHPSUFFIX);
+        invalidateCaches();
+    }
+
+    // Returns the link for a given URL (if it exists). false it does not exist.
+    public function getLinkFromUrl($url)
+    {
+        if (isset($this->urls[$url])) return $this->links[$this->urls[$url]];
+        return false;
+    }
+
+    // Case insentitive search among links (in url, title and description). Returns filtered list of links.
+    // eg. print_r($mydb->filterFulltext('hollandais'));
+    public function filterFulltext($searchterms)
+    {
+        // FIXME: explode(' ',$searchterms) and perform a AND search.
+        // FIXME: accept double-quotes to search for a string "as is" ?
+        $filtered=array();
+        $s = strtolower($searchterms);
+        foreach($this->links as $l)
+        {
+            $found=   (strpos(strtolower($l['title']),$s)!==false)
+                   || (strpos(strtolower($l['description']),$s)!==false)
+                   || (strpos(strtolower($l['snippet']),$s)!==false)
+                   || (strpos(strtolower($l['url']),$s)!==false)
+                   || (strpos(strtolower($l['tags']),$s)!==false)
+                   || (strpos(strtolower($l['via']),$s)!==false);
+            if ($found) $filtered[$l['linkdate']] = $l;
+        }
+        krsort($filtered);
+        return $filtered;
+    }
+
+    // Filter by tag.
+    // You can specify one or more tags (tags can be separated by space or comma).
+    // eg. print_r($mydb->filterTags('linux programming'));
+    public function filterTags($tags,$casesensitive=false)
+    {
+        $t = str_replace(',',' ',($casesensitive?$tags:strtolower($tags)));
+        $searchtags=explode(' ',$t);
+        $filtered=array();
+        foreach($this->links as $l)
+        {
+            $linktags = explode(' ',($casesensitive?$l['tags']:strtolower($l['tags'])));
+            if (count(array_intersect($linktags,$searchtags)) == count($searchtags))
+                $filtered[$l['linkdate']] = $l;
+        }
+        krsort($filtered);
+        return $filtered;
+    }
+
+    // Filter by day. Day must be in the form 'YYYYMMDD' (eg. '20120125')
+    // Sort order is: older articles first.
+    // eg. print_r($mydb->filterDay('20120125'));
+    public function filterDay($day)
+    {
+        $filtered=array();
+        foreach($this->links as $l)
+        {
+            if (startsWith($l['linkdate'],$day)) $filtered[$l['linkdate']] = $l;
+        }
+        ksort($filtered);
+        return $filtered;
+    }
+    // Filter by smallHash.
+    // Only 1 article is returned.
+    public function filterSmallHash($smallHash)
+    {
+        $filtered=array();
+        foreach($this->links as $l)
+        {
+            if ($smallHash==smallHash($l['linkdate'])) // Yes, this is ugly and slow
+            {
+                $filtered[$l['linkdate']] = $l;
+                return $filtered;
+            }
+        }
+        return $filtered;
+    }
+
+    // Returns the list of all tags
+    // Output: associative array key=tags, value=0
+    public function allTags()
+    {
+        $tags=array();
+        foreach($this->links as $link)
+            foreach(explode(' ',$link['tags']) as $tag)
+                if (!empty($tag)) $tags[$tag]=(empty($tags[$tag]) ? 1 : $tags[$tag]+1);
+        arsort($tags); // Sort tags by usage (most used tag first)
+        return $tags;
+    }
+    
+    // Returns the list of days containing articles (oldest first)
+    // Output: An array containing days (in format YYYYMMDD).
+    public function days()
+    {
+        $linkdays=array();
+        foreach(array_keys($this->links) as $day)
+        {
+            $linkdays[substr($day,0,8)]=0;
+        }
+        $linkdays=array_keys($linkdays);
+        sort($linkdays);
+        return $linkdays;
+    }
+}
+
+// ------------------------------------------------------------------------------------------
+// Ouput the last 50 links in RSS 2.0 format.
+function showRSS()
+{
+    header('Content-Type: application/rss+xml; charset=utf-8');
+
+    // Cache system
+    $query = $_SERVER["QUERY_STRING"];
+    $cache = new pageCache(pageUrl(),startsWith($query,'do=rss') && !isLoggedIn());
+    $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; }
+
+    // If cached was not found (or not usable), then read the database and build the response:
+    $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']);  // Read links from database (and filter private links if used it not logged in).
+
+    // Optionnaly filter the results:
+    $linksToDisplay=array();
+    if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']);
+    elseif (!empty($_GET['searchtags']))   $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags']));
+    else $linksToDisplay = $LINKSDB;
+
+    $pageaddr=htmlspecialchars(indexUrl());
+    echo '';
+    echo ''.htmlspecialchars($GLOBALS['title']).''.$pageaddr.'';
+    echo 'Shared linksen-en'.$pageaddr.''."\n\n";
+    if (!empty($GLOBALS['config']['PUBSUBHUB_URL']))
+    {
+        echo '';
+        echo '';
+        echo '';
+        echo '';
+    }
+    $i=0;
+    $keys=array(); foreach($linksToDisplay as $key=>$value) { $keys[]=$key; }  // No, I can't use array_keys().
+    while ($i<50 && $i'.htmlspecialchars($link['title']).''.$guid.''.$absurl.'';
+        if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) echo ''.htmlspecialchars($rfc822date)."\n";
+        if ($link['tags']!='') // Adding tags to each RSS entry (as mentioned in RSS specification)
+        {
+            foreach(explode(' ',$link['tags']) as $tag) { echo ''.htmlspecialchars($tag).''."\n"; }
+        }
+        echo ''."\n\n";
+        $i++;
+    }
+    echo '';
+
+    $cache->cache(ob_get_contents());
+    ob_end_flush();
+    exit;
+}
+
+// ------------------------------------------------------------------------------------------
+// Ouput the last 50 links in ATOM format.
+function showATOM()
+{
+    header('Content-Type: application/atom+xml; charset=utf-8');
+
+    // Cache system
+    $query = $_SERVER["QUERY_STRING"];
+    $cache = new pageCache(pageUrl(),startsWith($query,'do=atom') && !isLoggedIn());
+    $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; }
+    // If cached was not found (or not usable), then read the database and build the response:
+
+    $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']);  // Read links from database (and filter private links if used it not logged in).
+
+
+    // Optionnaly filter the results:
+    $linksToDisplay=array();
+    if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']);
+    elseif (!empty($_GET['searchtags']))   $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags']));
+    else $linksToDisplay = $LINKSDB;
+
+    $pageaddr=htmlspecialchars(indexUrl());
+    $latestDate = '';
+    $entries='';
+    $i=0;
+    $keys=array(); foreach($linksToDisplay as $key=>$value) { $keys[]=$key; }  // No, I can't use array_keys().
+    while ($i<50 && $i'.$guid.'';
+        if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $entries.=''.htmlspecialchars($iso8601date).'';
+        $entries.=''.htmlspecialchars(nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description'])))))."\n";
+        if ($link['tags']!='') // Adding tags to each ATOM entry (as mentioned in ATOM specification)
+        {
+            foreach(explode(' ',$link['tags']) as $tag)
+                { $entries.=''."\n"; }
+        }
+        $entries.="\n";
+        $i++;
+    }
+    $feed='';
+    $feed.=''.htmlspecialchars($GLOBALS['title']).'';
+    if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $feed.=''.htmlspecialchars($latestDate).'';
+    $feed.='';
+    if (!empty($GLOBALS['config']['PUBSUBHUB_URL']))
+    {
+        $feed.='';
+        $feed.='';
+        $feed.='';
+    }
+    $feed.=''.htmlspecialchars($pageaddr).''.htmlspecialchars($pageaddr).'';
+    $feed.=''.htmlspecialchars($pageaddr).''."\n\n"; // Yes, I know I should use a real IRI (RFC3987), but the site URL will do.
+    $feed.=$entries;
+    $feed.='';
+    echo $feed;
+    
+    $cache->cache(ob_get_contents());
+    ob_end_flush();
+    exit;
+}
+
+// ------------------------------------------------------------------------------------------
+// Daily RSS feed: 1 RSS entry per day giving all the links on that day.
+// Gives the last 7 days (which have links).
+// This RSS feed cannot be filtered.
+function showDailyRSS()
+{
+    // Cache system
+    $query = $_SERVER["QUERY_STRING"];
+    $cache = new pageCache(pageUrl(),startsWith($query,'do=dailyrss') && !isLoggedIn());
+    $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; }
+    // If cached was not found (or not usable), then read the database and build the response:
+    $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']);  // Read links from database (and filter private links if used it not logged in).
+    
+    /* Some Shaarlies may have very few links, so we need to look
+       back in time (rsort()) until we have enough days ($nb_of_days).
+    */
+    $linkdates=array(); foreach($LINKSDB as $linkdate=>$value) { $linkdates[]=$linkdate; } 
+    rsort($linkdates);
+    $nb_of_days=7; // We take 7 days.
+    $today=Date('Ymd');
+    $days=array();
+    foreach($linkdates as $linkdate)
+    {
+        $day=substr($linkdate,0,8); // Extract day (without time)
+        if (strcmp($day,$today)<0)
+        {
+            if (empty($days[$day])) $days[$day]=array();
+            $days[$day][]=$linkdate;
+        }
+        if (count($days)>$nb_of_days) break; // Have we collected enough days ?
+    }
+    
+    // Build the RSS feed.
+    header('Content-Type: application/rss+xml; charset=utf-8');
+    $pageaddr=htmlspecialchars(indexUrl());
+    echo '';
+    echo 'Daily - '.htmlspecialchars($GLOBALS['title']).''.$pageaddr.'';
+    echo 'Daily shared linksen-en'.$pageaddr.''."\n";
+    
+    foreach($days as $day=>$linkdates) // For each day.
+    {
+        $daydate = utf8_encode(strftime('%A %d, %B %Y',linkdate2timestamp($day.'_000000'))); // Full text date
+        $rfc822date = linkdate2rfc822($day.'_000000');
+        $absurl=htmlspecialchars(indexUrl().'?do=daily&day='.$day);  // Absolute URL of the corresponding "Daily" page.
+        echo ''.htmlspecialchars($GLOBALS['title'].' - '.$daydate).''.$absurl.''.$absurl.'';
+        echo ''.htmlspecialchars($rfc822date)."";
+        
+        // Build the HTML body of this RSS entry.
+        $html='';
+        $href='';
+        $links=array();
+        // We pre-format some fields for proper output.
+        foreach($linkdates as $linkdate)
+        {
+            $l = $LINKSDB[$linkdate];
+            $l['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($l['description']))));
+            $l['thumbnail'] = thumbnail($l['url']);  
+            $l['localdate']=linkdate2locale($l['linkdate']);            
+            if (startsWith($l['url'],'?')) $l['url']=indexUrl().$l['url'];  // make permalink URL absolute
+            $links[$linkdate]=$l;    
+        }
+        // Then build the HTML for this day:
+        $tpl = new RainTPL;    
+        $tpl->assign('links',$links);
+        $html = $tpl->draw('dailyrss',$return_string=true);
+        echo "\n";
+        echo ''."\n\n\n";
+
+    }    
+    echo '';
+    
+    $cache->cache(ob_get_contents());
+    ob_end_flush();
+    exit;
+}
+
+// "Daily" page.
+function showDaily()
+{
+    $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']);  // Read links from database (and filter private links if used it not logged in).
+
+
+    $day=Date('Ymd',strtotime('-1 day')); // Yesterday, in format YYYYMMDD.
+    if (isset($_GET['day'])) $day=$_GET['day'];
+    
+    $days = $LINKSDB->days();
+    $i = array_search($day,$days);
+    if ($i==false) { $i=count($days)-1; $day=$days[$i]; }
+    $previousday=''; 
+    $nextday=''; 
+    if ($i!==false)
+    {
+        if ($i>1) $previousday=$days[$i-1];
+        if ($ifilterDay($day);
+    // We pre-format some fields for proper output.
+    foreach($linksToDisplay as $key=>$link)
+    {
+        $linksToDisplay[$key]['taglist']=explode(' ',$link['tags']);
+        $linksToDisplay[$key]['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description']))));
+        $linksToDisplay[$key]['thumbnail'] = thumbnail($link['url']);            
+    }
+    
+    /* We need to spread the articles on 3 columns.
+       I did not want to use a javascript lib like http://masonry.desandro.com/
+       so I manually spread entries with a simple method: I roughly evaluate the 
+       height of a div according to title and description length.
+    */
+    $columns=array(array(),array(),array()); // Entries to display, for each column.
+    $fill=array(0,0,0);  // Rough estimate of columns fill.
+    foreach($linksToDisplay as $key=>$link)
+    {
+        // Roughly estimate length of entry (by counting characters)
+        // Title: 30 chars = 1 line. 1 line is 30 pixels height.
+        // Description: 836 characters gives roughly 342 pixel height.
+        // This is not perfect, but it's usually ok.
+        $length=strlen($link['title'])+(342*strlen($link['description']))/836;
+        if ($link['thumbnail']) $length +=100; // 1 thumbnails roughly takes 100 pixels height.
+        // Then put in column which is the less filled:
+        $smallest=min($fill); // find smallest value in array.
+        $index=array_search($smallest,$fill); // find index of this smallest value.
+        array_push($columns[$index],$link); // Put entry in this column.
+        $fill[$index]+=$length;
+    }
+    $PAGE = new pageBuilder;
+    $PAGE->assign('linksToDisplay',$linksToDisplay);
+    $PAGE->assign('linkcount',count($LINKSDB));
+    $PAGE->assign('col1',$columns[0]);
+    $PAGE->assign('col1',$columns[0]);
+    $PAGE->assign('col2',$columns[1]);
+    $PAGE->assign('col3',$columns[2]);
+    $PAGE->assign('day',utf8_encode(strftime('%A %d, %B %Y',linkdate2timestamp($day.'_000000'))));
+    $PAGE->assign('previousday',$previousday);
+    $PAGE->assign('nextday',$nextday);    
+    $PAGE->renderPage('daily');
+    exit;
+}
+
+
+// ------------------------------------------------------------------------------------------
+// Render HTML page (according to URL parameters and user rights)
+function renderPage()
+{
+    $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']);  // Read links from database (and filter private links if used it not logged in).
+
+    // -------- Display login form.
+    if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=login'))
+    {
+        if ($GLOBALS['config']['OPEN_SHAARLI']) { header('Location: ?'); exit; }  // No need to login for open Shaarli
+        $token=''; if (ban_canLogin()) $token=getToken(); // Do not waste token generation if not useful.
+        $PAGE = new pageBuilder;
+        $PAGE->assign('token',$token);
+        $PAGE->assign('returnurl',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER']:''));
+        $PAGE->renderPage('loginform');
+        exit;
+    }
+    // -------- User wants to logout.
+    if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=logout'))
+    {
+        invalidateCaches();
+        logout();
+        header('Location: ?');
+        exit;
+    }
+
+    // -------- Picture wall
+    if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=picwall'))
+    {
+        // Optionnaly filter the results:
+        $links=array();
+        if (!empty($_GET['searchterm'])) $links = $LINKSDB->filterFulltext($_GET['searchterm']);
+        elseif (!empty($_GET['searchtags']))   $links = $LINKSDB->filterTags(trim($_GET['searchtags']));
+        else $links = $LINKSDB;
+        $body='';
+        $linksToDisplay=array();
+
+        // Get only links which have a thumbnail.
+        foreach($links as $link)
+        {
+            $permalink='?'.htmlspecialchars(smallhash($link['linkdate']),ENT_QUOTES);
+            $thumb=lazyThumbnail($link['url'],$permalink);
+            if ($thumb!='') // Only output links which have a thumbnail.
+            {
+                $link['thumbnail']=$thumb; // Thumbnail HTML code.
+                $link['permalink']=$permalink;
+                $linksToDisplay[]=$link; // Add to array.
+            }
+        }
+        $PAGE = new pageBuilder;
+        $PAGE->assign('linkcount',count($LINKSDB));
+        $PAGE->assign('linksToDisplay',$linksToDisplay);
+        $PAGE->renderPage('picwall');
+        exit;
+    }
+
+    // -------- Tag cloud
+    if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=tagcloud'))
+    {
+        $tags= $LINKSDB->allTags();
+        // We sort tags alphabetically, then choose a font size according to count.
+        // First, find max value.
+        $maxcount=0; foreach($tags as $key=>$value) $maxcount=max($maxcount,$value);
+        ksort($tags);
+        $tagList=array();
+        foreach($tags as $key=>$value)
+        {
+            $tagList[$key] = array('count'=>$value,'size'=>max(40*$value/$maxcount,8));
+        }
+        $PAGE = new pageBuilder;
+        $PAGE->assign('linkcount',count($LINKSDB));
+        $PAGE->assign('tags',$tagList);
+        $PAGE->renderPage('tagcloud');
+        exit;    
+    }
+
+    // -------- User clicks on a tag in a link: The tag is added to the list of searched tags (searchtags=...)
+    if (isset($_GET['addtag']))
+    {
+        // Get previous URL (http_referer) and add the tag to the searchtags parameters in query.
+        if (empty($_SERVER['HTTP_REFERER'])) { header('Location: ?searchtags='.urlencode($_GET['addtag'])); exit; } // In case browser does not send HTTP_REFERER
+        parse_str(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_QUERY), $params);
+        $params['searchtags'] = (empty($params['searchtags']) ?  trim($_GET['addtag']) : trim($params['searchtags']).' '.trim($_GET['addtag']));
+        unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different)
+        header('Location: ?'.http_build_query($params));
+        exit;
+    }
+
+    // -------- User clicks on a tag in result count: Remove the tag from the list of searched tags (searchtags=...)
+    if (isset($_GET['removetag']))
+    {
+        // Get previous URL (http_referer) and remove the tag from the searchtags parameters in query.
+        if (empty($_SERVER['HTTP_REFERER'])) { header('Location: ?'); exit; } // In case browser does not send HTTP_REFERER
+        parse_str(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_QUERY), $params);
+        if (isset($params['searchtags']))
+        {
+            $tags = explode(' ',$params['searchtags']);
+            $tags=array_diff($tags, array($_GET['removetag'])); // Remove value from array $tags.
+            if (count($tags)==0) unset($params['searchtags']); else $params['searchtags'] = implode(' ',$tags);
+            unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different)
+        }
+        header('Location: ?'.http_build_query($params));
+        exit;
+    }
+
+    // -------- User wants to change the number of links per page (linksperpage=...)
+    if (isset($_GET['linksperpage']))
+    {
+        if (is_numeric($_GET['linksperpage'])) { $_SESSION['LINKS_PER_PAGE']=abs(intval($_GET['linksperpage'])); }
+        header('Location: '.(empty($_SERVER['HTTP_REFERER'])?'?':$_SERVER['HTTP_REFERER']));
+        exit;
+    }
+    
+    // -------- User wants to see only private links (toggle)
+    if (isset($_GET['privateonly']))
+    {
+        if (empty($_SESSION['privateonly']))
+        {
+            $_SESSION['privateonly']=1; // See only private links
+        }
+        else
+        {
+            unset($_SESSION['privateonly']); // See all links
+        }
+        header('Location: '.(empty($_SERVER['HTTP_REFERER'])?'?':$_SERVER['HTTP_REFERER']));
+        exit;
+    }
+
+    // -------- Handle other actions allowed for non-logged in users:
+    if (!isLoggedIn())
+    {
+        // User tries to post new link but is not loggedin:
+        // Show login screen, then redirect to ?post=...
+        if (isset($_GET['post']))
+        {
+            header('Location: ?do=login&post='.urlencode($_GET['post']).(!empty($_GET['title'])?'&title='.urlencode($_GET['title']):'').(!empty($_GET['source'])?'&source='.urlencode($_GET['source']):'')); // Redirect to login page, then back to post link.
+            exit;
+        }
+        $PAGE = new pageBuilder;
+        buildLinkList($PAGE,$LINKSDB); // Compute list of links to display
+        $PAGE->renderPage('linklist');
+        exit; // Never remove this one ! All operations below are reserved for logged in user.
+    }
+
+    // -------- All other functions are reserved for the registered user:
+
+    // -------- Display the Tools menu if requested (import/export/bookmarklet...)
+    if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=tools'))
+    {
+        $PAGE = new pageBuilder;
+        $PAGE->assign('linkcount',count($LINKSDB));
+        $PAGE->assign('pageabsaddr',indexUrl());
+        $PAGE->renderPage('tools');
+        exit;
+    }
+
+    // -------- User wants to change his/her password.
+    if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=changepasswd'))
+    {
+        if ($GLOBALS['config']['OPEN_SHAARLI']) die('You are not supposed to change a password on an Open Shaarli.');
+        if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword']))
+        {
+            if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away !
+
+            // Make sure old password is correct.
+            $oldhash = sha1($_POST['oldpassword'].$GLOBALS['login'].$GLOBALS['salt']);
+            if ($oldhash!=$GLOBALS['hash']) { echo ''; exit; }
+            // Save new password
+            $GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless.
+            $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']);
+            writeConfig();
+            echo '';
+            exit;
+        }
+        else // show the change password form.
+        {
+            $PAGE = new pageBuilder;
+            $PAGE->assign('linkcount',count($LINKSDB));
+            $PAGE->assign('token',getToken());
+            $PAGE->renderPage('changepassword');
+            exit;
+        }
+    }
+
+    // -------- User wants to change configuration
+    if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=configure'))
+    {
+        if (!empty($_POST['title']) )
+        {
+            if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away !
+            $tz = 'UTC';
+            if (!empty($_POST['continent']) && !empty($_POST['city']))
+                if (isTZvalid($_POST['continent'],$_POST['city']))
+                    $tz = $_POST['continent'].'/'.$_POST['city'];
+            $GLOBALS['timezone'] = $tz;
+            $GLOBALS['title']=$_POST['title'];
+            $GLOBALS['redirector']=$_POST['redirector'];
+            $GLOBALS['disablesessionprotection']=!empty($_POST['disablesessionprotection']);
+            writeConfig();
+            echo '';
+            exit;
+        }
+        else // Show the configuration form.
+        {
+            $PAGE = new pageBuilder;
+            $PAGE->assign('linkcount',count($LINKSDB));
+            $PAGE->assign('token',getToken());
+            $PAGE->assign('title',htmlspecialchars( empty($GLOBALS['title']) ? '' : $GLOBALS['title'] , ENT_QUOTES));
+            $PAGE->assign('redirector',htmlspecialchars( empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] , ENT_QUOTES));
+            list($timezone_form,$timezone_js) = templateTZform($GLOBALS['timezone']);
+            $PAGE->assign('timezone_form',$timezone_form); // FIXME: put entire tz form generation in template ?
+            $PAGE->assign('timezone_js',$timezone_js);
+            $PAGE->renderPage('configure');
+            exit;
+        }
+    }
+
+    // -------- User wants to rename a tag or delete it
+    if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=changetag'))
+    {
+        if (empty($_POST['fromtag']))
+        {
+            $PAGE = new pageBuilder;
+            $PAGE->assign('linkcount',count($LINKSDB));
+            $PAGE->assign('token',getToken());
+            $PAGE->renderPage('changetag');
+            exit;
+        }
+        if (!tokenOk($_POST['token'])) die('Wrong token.');
+
+        // Delete a tag:
+        if (!empty($_POST['deletetag']) && !empty($_POST['fromtag']))
+        {
+            $needle=trim($_POST['fromtag']);
+            $linksToAlter = $LINKSDB->filterTags($needle,true); // true for case-sensitive tag search.
+            foreach($linksToAlter as $key=>$value)
+            {
+                $tags = explode(' ',trim($value['tags']));
+                unset($tags[array_search($needle,$tags)]); // Remove tag.
+                $value['tags']=trim(implode(' ',$tags));
+                $LINKSDB[$key]=$value;
+            }
+            $LINKSDB->savedb(); // save to disk
+            echo '';
+            exit;
+        }
+
+        // Rename a tag:
+        if (!empty($_POST['renametag']) && !empty($_POST['fromtag']) && !empty($_POST['totag']))
+        {
+            $needle=trim($_POST['fromtag']);
+            $linksToAlter = $LINKSDB->filterTags($needle,true); // true for case-sensitive tag search.
+            foreach($linksToAlter as $key=>$value)
+            {
+                $tags = explode(' ',trim($value['tags']));
+                $tags[array_search($needle,$tags)] = trim($_POST['totag']); // Remplace tags value.
+                $value['tags']=trim(implode(' ',$tags));
+                $LINKSDB[$key]=$value;
+            }
+            $LINKSDB->savedb(); // save to disk
+            echo '';
+            exit;
+        }
+    }
+
+    // -------- User wants to add a link without using the bookmarklet: show form.
+    if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=addlink'))
+    {
+        $PAGE = new pageBuilder;
+        $PAGE->assign('linkcount',count($LINKSDB));
+        $PAGE->renderPage('addlink');
+        exit;
+    }
+
+    // -------- User clicked the "Save" button when editing a link: Save link to database.
+    if (isset($_POST['save_edit']))
+    {
+        if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away !
+        $tags = trim(preg_replace('/\s\s+/',' ', $_POST['lf_tags'])); // Remove multiple spaces.
+        $linkdate=$_POST['lf_linkdate'];
+        $link = array('title'=>trim($_POST['lf_title']),'url'=>trim($_POST['lf_url']),'description'=>trim($_POST['lf_description']),'snippet'=>trim($_POST['lf_snippet']),'private'=>(isset($_POST['lf_private']) ? 1 : 0),'linkdate'=>$linkdate,'tags'=>str_replace(',',' ',$tags), 'via'=>trim($_POST['lf_via']));
+        if ($link['title']=='') $link['title']=$link['url']; // If title is empty, use the URL as title.
+        $LINKSDB[$linkdate] = $link;
+        $LINKSDB->savedb(); // save to disk
+        pubsubhub();
+
+        // If we are called from the bookmarklet, we must close the popup:
+        if (isset($_GET['source']) && $_GET['source']=='bookmarklet') { echo ''; exit; }
+        $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' );
+        header('Location: '.$returnurl); // After saving the link, redirect to the page the user was on.
+        exit;
+    }
+
+    // -------- User clicked the "Cancel" button when editing a link.
+    if (isset($_POST['cancel_edit']))
+    {
+        // If we are called from the bookmarklet, we must close the popup;
+        if (isset($_GET['source']) && $_GET['source']=='bookmarklet') { echo ''; exit; }
+        $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' );
+        header('Location: '.$returnurl); // After canceling, redirect to the page the user was on.
+        exit;
+    }
+
+    // -------- User clicked the "Delete" button when editing a link : Delete link from database.
+    if (isset($_POST['delete_link']))
+    {
+        if (!tokenOk($_POST['token'])) die('Wrong token.');
+        // We do not need to ask for confirmation:
+        // - confirmation is handled by javascript
+        // - we are protected from XSRF by the token.
+        $linkdate=$_POST['lf_linkdate'];
+        unset($LINKSDB[$linkdate]);
+        $LINKSDB->savedb(); // save to disk
+
+        // If we are called from the bookmarklet, we must close the popup:
+        if (isset($_GET['source']) && $_GET['source']=='bookmarklet') { echo ''; exit; }
+        $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' );
+        if ($returnurl=='?') { $returnurl = (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '?'); }
+        header('Location: '.$returnurl); // After deleting the link, redirect to the page the user was on.
+        exit;
+    }
+
+    // -------- User clicked the "EDIT" button on a link: Display link edit form.
+    if (isset($_GET['edit_link']))
+    {
+        $link = $LINKSDB[$_GET['edit_link']];  // Read database
+        if (!$link) { header('Location: ?'); exit; } // Link not found in database.
+        $PAGE = new pageBuilder;
+        $PAGE->assign('linkcount',count($LINKSDB));
+        $PAGE->assign('link',$link);
+        $PAGE->assign('link_is_new',false);
+        $PAGE->assign('token',getToken()); // XSRF protection.
+        $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''));
+        $PAGE->renderPage('editlink');
+        exit;
+    }
+
+    // -------- User want to post a new link: Display link edit form.
+    if (isset($_GET['post']))
+    {
+        $url=$_GET['post'];
+
+        // We remove the annoying parameters added by FeedBurner and GoogleFeedProxy (?utm_source=...)
+        $i=strpos($url,'&utm_source='); if ($i!==false) $url=substr($url,0,$i);
+        $i=strpos($url,'?utm_source='); if ($i!==false) $url=substr($url,0,$i);
+        $i=strpos($url,'#xtor=RSS-'); if ($i!==false) $url=substr($url,0,$i);
+
+        $link_is_new = false;
+        $link = $LINKSDB->getLinkFromUrl($url); // Check if URL is not already in database (in this case, we will edit the existing link)
+        if (!$link)
+        {
+            $link_is_new = true;  // This is a new link
+            $linkdate = strval(date('Ymd_His'));
+            $title = (empty($_GET['title']) ? '' : $_GET['title'] ); // Get title if it was provided in URL (by the bookmarklet).
+            $snippet = $via = '';$description=''; $tags=''; $private=0;
+            if (($url!='') && parse_url($url,PHP_URL_SCHEME)=='') $url = 'http://'.$url;
+            // If this is an HTTP link, we try go get the page to extact the title (otherwise we will to straight to the edit form.)
+            if (empty($title) && parse_url($url,PHP_URL_SCHEME)=='http')
+            {
+                list($status,$headers,$data) = getHTTP($url,4); // Short timeout to keep the application responsive.
+                // FIXME: Decode charset according to specified in either 1) HTTP response headers or 2)  in html
+                if (strpos($status,'200 OK')!==false) $title=html_entity_decode(html_extract_title($data),ENT_QUOTES,'UTF-8');
+
+            }
+            if ($url=='') $url='?'.smallHash($linkdate); // In case of empty URL, this is just a text (with a link that point to itself)
+            $link = array('linkdate'=>$linkdate,'title'=>$title,'url'=>$url,'description'=>$description,'snippet'=>$snippet,'tags'=>$tags,'via'=>$via,'private'=>0);
+        }
+
+        $PAGE = new pageBuilder;
+        $PAGE->assign('linkcount',count($LINKSDB));
+        $PAGE->assign('link',$link);
+        $PAGE->assign('link_is_new',$link_is_new);
+        $PAGE->assign('token',getToken()); // XSRF protection.
+        $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''));
+        $PAGE->renderPage('editlink');
+        exit;
+    }
+
+    // -------- Export as Netscape Bookmarks HTML file.
+    if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=export'))
+    {
+        if (empty($_GET['what']))
+        {
+            $PAGE = new pageBuilder;
+            $PAGE->assign('linkcount',count($LINKSDB));
+            $PAGE->renderPage('export');
+            exit;
+        }
+        $exportWhat=$_GET['what'];
+        if (!array_intersect(array('all','public','private'),array($exportWhat))) die('What are you trying to export ???');
+
+        header('Content-Type: text/html; charset=utf-8');
+        header('Content-disposition: attachment; filename=bookmarks_'.$exportWhat.'_'.strval(date('Ymd_His')).'.html');
+        $currentdate=date('Y/m/d H:i:s');
+        echo <<
+
+
+
+Bookmarks
+

Bookmarks

+HTML; + foreach($LINKSDB as $link) + { + if ($exportWhat=='all' || + ($exportWhat=='private' && $link['private']!=0) || + ($exportWhat=='public' && $link['private']==0)) + { + echo '
'.htmlspecialchars($link['title'])."\n"; + if ($link['description']!='') echo '
'.htmlspecialchars($link['description'])."\n"; + } + } + exit; + } + + // -------- User is uploading a file for import + if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=upload')) + { + // If file is too big, some form field may be missing. + if (!isset($_POST['token']) || (!isset($_FILES)) || (isset($_FILES['filetoupload']['size']) && $_FILES['filetoupload']['size']==0)) + { + $returnurl = ( empty($_SERVER['HTTP_REFERER']) ? '?' : $_SERVER['HTTP_REFERER'] ); + echo ''; + exit; + } + if (!tokenOk($_POST['token'])) die('Wrong token.'); + importFile(); + exit; + } + + // -------- Show upload/import dialog: + if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=import')) + { + $PAGE = new pageBuilder; + $PAGE->assign('linkcount',count($LINKSDB)); + $PAGE->assign('token',getToken()); + $PAGE->assign('maxfilesize',getMaxFileSize()); + $PAGE->renderPage('import'); + exit; + } + + // -------- Otherwise, simply display search form and links: + $PAGE = new pageBuilder; + $PAGE->assign('linkcount',count($LINKSDB)); + buildLinkList($PAGE,$LINKSDB); // Compute list of links to display + $PAGE->renderPage('linklist'); + exit; +} + +// ----------------------------------------------------------------------------------------------- +// Process the import file form. +function importFile() +{ + if (!(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI'])) { die('Not allowed.'); } + $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). + $filename=$_FILES['filetoupload']['name']; + $filesize=$_FILES['filetoupload']['size']; + $data=file_get_contents($_FILES['filetoupload']['tmp_name']); + $private = (empty($_POST['private']) ? 0 : 1); // Should the links be imported as private ? + $overwrite = !empty($_POST['overwrite']) ; // Should the imported links overwrite existing ones ? + $import_count=0; + + // Sniff file type: + $type='unknown'; + if (startsWith($data,'')) $type='netscape'; // Netscape bookmark file (aka Firefox). + + // Then import the bookmarks. + if ($type=='netscape') + { + // This is a standard Netscape-style bookmark file. + // This format is supported by all browsers (except IE, of course), also delicious, diigo and others. + foreach(explode('
',$data) as $html) // explode is very fast + { + $link = array('linkdate'=>'','title'=>'','url'=>'','description'=>'','tags'=>'','private'=>0); + $d = explode('
',$html); + if (startswith($d[0],'(.*?)!i',$d[0],$matches); $link['title'] = (isset($matches[1]) ? trim($matches[1]) : ''); // Get title + $link['title'] = html_entity_decode($link['title'],ENT_QUOTES,'UTF-8'); + preg_match_all('! ([A-Z_]+)=\"(.*?)"!i',$html,$matches,PREG_SET_ORDER); // Get all other attributes + $raw_add_date=0; + foreach($matches as $m) + { + $attr=$m[1]; $value=$m[2]; + if ($attr=='HREF') $link['url']=html_entity_decode($value,ENT_QUOTES,'UTF-8'); + elseif ($attr=='ADD_DATE') $raw_add_date=intval($value); + elseif ($attr=='PRIVATE') $link['private']=($value=='0'?0:1); + elseif ($attr=='TAGS') $link['tags']=html_entity_decode(str_replace(',',' ',$value),ENT_QUOTES,'UTF-8'); + } + if ($link['url']!='') + { + if ($private==1) $link['private']=1; + $dblink = $LINKSDB->getLinkFromUrl($link['url']); // See if the link is already in database. + if ($dblink==false) + { // Link not in database, let's import it... + if (empty($raw_add_date)) $raw_add_date=time(); // In case of shitty bookmark file with no ADD_DATE + + // Make sure date/time is not already used by another link. + // (Some bookmark files have several different links with the same ADD_DATE) + // We increment date by 1 second until we find a date which is not used in db. + // (so that links that have the same date/time are more or less kept grouped by date, but do not conflict.) + while (!empty($LINKSDB[date('Ymd_His',$raw_add_date)])) { $raw_add_date++; }// Yes, I know it's ugly. + $link['linkdate']=date('Ymd_His',$raw_add_date); + $LINKSDB[$link['linkdate']] = $link; + $import_count++; + } + else // link already present in database. + { + if ($overwrite) + { // If overwrite is required, we import link data, except date/time. + $link['linkdate']=$dblink['linkdate']; + $LINKSDB[$link['linkdate']] = $link; + $import_count++; + } + } + + } + } + } + $LINKSDB->savedb(); + + echo ''; + } + else + { + echo ''; + } +} + +// ----------------------------------------------------------------------------------------------- +// Template for the list of links ( {include="page.footer"} - - + + \ No newline at end of file diff --git a/tpl/page.footer.html b/tpl/page.footer.html index 7fe1501..54d7986 100644 --- a/tpl/page.footer.html +++ b/tpl/page.footer.html @@ -1,5 +1,5 @@ {if="$newversion"}
Shaarli {$newversion|htmlspecialchars} is available.
diff --git a/tpl/page.header.html b/tpl/page.header.html index 60fc176..7cc83ca 100644 --- a/tpl/page.header.html +++ b/tpl/page.header.html @@ -22,5 +22,3 @@ Daily {/if}
- - diff --git a/tpl/readme.txt b/tpl/readme.txt index b18deae..bbf3d40 100644 --- a/tpl/readme.txt +++ b/tpl/readme.txt @@ -38,5 +38,3 @@ Example: "Add new link" form: ----------------------------------------------------- - -