]> git.immae.eu Git - github/wallabag/wallabag.git/commitdiff
first commit
authorNicolas Lœuillet <nicolas@coteo.com>
Wed, 3 Apr 2013 13:14:01 +0000 (15:14 +0200)
committerNicolas Lœuillet <nicolas@coteo.com>
Wed, 3 Apr 2013 13:14:01 +0000 (15:14 +0200)
19 files changed:
COPYING [new file with mode: 0644]
README.md [new file with mode: 0755]
cache/footer.32a3c4422ad65642b8dbb7e731f4d990.rtpl.php [new file with mode: 0644]
cache/index.0b3442bc62f6c429fc13004b3c821ba0.rtpl.php [new file with mode: 0644]
css/index.html [new file with mode: 0755]
css/knacss.css [new file with mode: 0644]
css/reset.css [new file with mode: 0755]
css/style.css [new file with mode: 0644]
css/typography.css [new file with mode: 0755]
inc/Encoding.php [new file with mode: 0755]
inc/JSLikeHTMLElement.php [new file with mode: 0755]
inc/Readability.php [new file with mode: 0755]
inc/index.html [new file with mode: 0755]
inc/rain.tpl.class.php [new file with mode: 0755]
index.php [new file with mode: 0755]
poche.sqlite [new file with mode: 0755]
readityourself.php [new file with mode: 0755]
tpl/footer.html [new file with mode: 0755]
tpl/index.html [new file with mode: 0755]

diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..ee7d6a5
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,14 @@
+            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE\r
+                    Version 2, December 2004\r
+\r
+ Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>\r
+\r
+ Everyone is permitted to copy and distribute verbatim or modified\r
+ copies of this license document, and changing it is allowed as long\r
+ as the name is changed.\r
+\r
+            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE\r
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\r
+\r
+  0. You just DO WHAT THE FUCK YOU WANT TO.\r
+\r
diff --git a/README.md b/README.md
new file mode 100755 (executable)
index 0000000..b66aba1
--- /dev/null
+++ b/README.md
@@ -0,0 +1,13 @@
+# poche
+
+Abandon Pocket, Instapaper and other Readibility service : adopt poche. It is the same, but it is open source.
+
+## Usage
+
+...
+
+## License
+Copyright © 2010-2013 Nicolas Lœuillet <nicolas.loeuillet@gmail.com>
+This work is free. You can redistribute it and/or modify it under the
+terms of the Do What The Fuck You Want To Public License, Version 2,
+as published by Sam Hocevar. See the COPYING file for more details.
\ No newline at end of file
diff --git a/cache/footer.32a3c4422ad65642b8dbb7e731f4d990.rtpl.php b/cache/footer.32a3c4422ad65642b8dbb7e731f4d990.rtpl.php
new file mode 100644 (file)
index 0000000..e069cab
--- /dev/null
@@ -0,0 +1,7 @@
+<?php if(!class_exists('raintpl')){exit;}?><footer>
+       <div>  
+       Copyright &copy; <a href="http://www.memiks.fr/">memiks.fr</a> | <a href="http://shaarli.memiks.fr/">Liens</a> / <a href="http://rss.memiks.fr/">RSS</a> / <a href="http://wiki.memiks.fr/">Wiki</a>  / <a href="mailto:&#109;&#101;&#109;&#105;&#107;&#115;&#064;&#109;&#101;&#109;&#105;&#107;&#115;&#046;&#102;&#114;">Contact</a><br>
+                       Licence: WTF Licence<br>
+                       More information HERE: <a href="http://www.memiks.fr/readityourself/">http://www.memiks.fr/readityourself/</a> Version : <span class="version"><?php echo $version;?></span>
+       </div>
+</footer>
diff --git a/cache/index.0b3442bc62f6c429fc13004b3c821ba0.rtpl.php b/cache/index.0b3442bc62f6c429fc13004b3c821ba0.rtpl.php
new file mode 100644 (file)
index 0000000..6dd72a4
--- /dev/null
@@ -0,0 +1,20 @@
+<?php if(!class_exists('raintpl')){exit;}?><html>
+       <head>
+               <link rel='stylesheet' href='./css/reset.css' type='text/css' media='all' />
+               <link rel='stylesheet' href='./css/typography.css' type='text/css' media='all' />
+       
+               <title><?php echo $title;?></title>
+       </head>
+       <body>
+               <article>
+                       <h1><a href="<?php echo $url;?>"><?php echo $title;?></a></h1>
+                       <div id="readityourselfcontent">
+                               <?php echo $content;?>
+
+                       </div>
+                       <span class="comeFrom">Come From : <a href="<?php echo $url;?>"><?php echo $url;?></a>
+               </article>
+               <?php $tpl = new RainTPL;$tpl_dir_temp = self::$tpl_dir;$tpl->assign( $this->var );$tpl->draw( dirname("footer") . ( substr("footer",-1,1) != "/" ? "/" : "" ) . basename("footer") );?>
+
+       </body>
+</html>
diff --git a/css/index.html b/css/index.html
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/css/knacss.css b/css/knacss.css
new file mode 100644 (file)
index 0000000..56e91f9
--- /dev/null
@@ -0,0 +1,1070 @@
+/*
+* www.KNACSS.com V2.6c @author: Raphael Goetter, Alsacreations
+* Licence CC-BY http://creativecommons.org/licenses/by/3.0/fr/
+*/
+
+/* ----------------------------- */
+/* ==reset */
+/* ----------------------------- */
+
+/* base font-size corresponds to 10px and is adapted to rem unit */
+html {
+       font-size: 62.5%;
+}
+body {
+       background-color: #fff;
+       color: #000;
+       font-family: "Century Gothic", helvetica, arial, sans-serif;
+       font-size: 1.4em; /* equiv 14px */
+       line-height: 1.5; /* adapt to your design */
+}
+
+/* font-sizing for content */
+/* preserve vertical-rythm, thanks to http://soqr.fr/vertical-rhythm/ */
+p,
+ul,
+ol,
+dl,
+blockquote,
+pre,
+td,
+th,
+label,
+textarea,
+caption,
+details, 
+figure, 
+hgroup {
+       font-size: 1em; /* equiv 14px */
+       line-height: 1.5;
+       margin: .75em 0 0;
+}
+h1, .h1-like {
+       font-size: 1.8571em; /* equiv 26px */
+       font-weight: normal;
+       line-height: 1.6154em;
+       margin: .8077em 0 0 0;
+}
+h2, .h2-like {
+       font-size: 1.7143em; /* equiv 24px */
+       font-weight: normal;
+       line-height: 1.75em;
+       margin: .875em 0 0 0;
+}
+h3, .h3-like {
+       font-size: 1.5714em; /* equiv 22px */
+       font-weight: normal;
+       line-height: 1.909em;
+       margin: .9545em 0 0 0;
+}
+h4, .h4-like {
+       font-size: 1.4286em; /* equiv 20px */
+       font-weight: normal;
+       line-height: 1.05em;
+       margin:  1.05em 0 0 0;
+}
+h5, .h5-like {
+       font-size: 1.2857em; /* equiv 18px */
+       font-weight: normal;
+       line-height: 1.1667em;
+       margin:  1.1667em 0 0 0;
+}
+h6, .h6-like {
+       font-size: 1.1429em; /* equiv 16px */
+       font-weight: normal;
+       line-height: 1.3125em;
+       margin:  1.3125em 0 0 0;
+}
+
+/* alternate font-sizing */
+.smaller {
+       font-size: .7143em; /* equiv 10px */
+}
+.small {
+       font-size: .8571em; /* equiv 12px */
+}
+.big {
+       font-size: 1.1429em; /* equiv 16px */
+}
+.bigger {
+       font-size: 1.2857em; /* equiv 18px */
+}
+.biggest {
+       font-size: 1.4286em; /* equiv 20px */
+}
+
+/* soft reset */
+html,
+body,
+textarea,
+figure,
+label {
+       margin: 0;
+       padding: 0;
+}
+ul,
+ol {
+       padding-left: 2em;
+}
+code, 
+pre,
+samp,
+kbd {
+       white-space: pre-wrap;
+       font-family: consolas, 'DejaVu Sans Mono', courier, monospace;
+       line-height: 1em;
+}
+code, kbd, mark {
+       border-radius: 2px;
+}
+em {
+       font-style: italic;
+}
+strong {
+       font-weight: bold;
+}
+kbd {
+       padding: 0 2px;
+       border: 1px solid #999;
+}
+code {
+       padding: 2px 4px;
+       background: rgba(0,0,0,.04);
+       color: #b11; 
+}
+mark {
+       padding:2px 4px;
+       background: #ff0;
+}
+
+table { margin-bottom: 1.5em; }
+
+/* avoid top margins on first content element */
+p:first-child,
+ul:first-child,
+ol:first-child,
+dl:first-child,
+blockquote:first-child,
+pre:first-child,
+h1:first-child,
+h2:first-child,
+h3:first-child,
+h4:first-child,
+h5:first-child,
+h6:first-child {
+       margin-top: 0;
+}
+
+/* avoid margins on nested elements */
+li p,
+li ul,
+li ol {
+       margin-top: 0;
+       margin-bottom: 0;
+}
+
+/* max values */
+img, table, td, blockquote, code, pre, textarea, input, video {
+       max-width: 100%;
+}
+
+/* you shall not pass */
+div, textarea, table, td, th, code, pre, samp {
+       word-wrap: break-word;
+       -webkit-hyphens: auto;
+       -moz-hyphens: auto;
+       -ms-hyphens: auto;
+       -o-hyphens: auto;
+       hyphens: auto;
+}
+
+/* pictures */
+img {
+       height: auto;
+       vertical-align: middle;
+}
+/* Gmap3 max-width bug fix on images */
+#map_canvas img,
+.gmnoprint img {max-width: none;}
+
+a img { border: 0; }
+
+/* scripts */
+body > script {display: none !important;}
+
+/* skip-links */
+.skip-links {
+       position: absolute;
+}
+.skip-links a {
+       position: absolute;
+       left: -7000px;
+       padding: 0.5em;
+       background: #000;
+       color:#fff;
+       text-decoration: none;
+}
+.skip-links a:focus {
+       position: static;
+}
+
+/* ----------------------------- */
+/* ==layout and modules */
+/* ----------------------------- */
+
+/* switching box model for all elements */
+* {
+       -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+       box-sizing: border-box;
+}
+
+/* float layout */
+/* ----------- */
+
+/* module, contains floats (.item is the same) */
+.mod, .item { 
+       overflow: hidden;
+}
+
+/* table layout */
+/* ------------------ */
+.row {
+       display: table;
+       table-layout: fixed;
+       width: 100%;
+}
+.row > *,
+.col {
+       display: table-cell;
+       vertical-align: top;
+}
+
+/* blocks that needs to be placed under floats */
+.clear,
+.line,
+.row {
+       clear: both;
+}
+
+/* blocks that must contain floats */
+.clearfix:after,
+.line:after,
+.mod:after {
+       content: "";
+       display: table;
+       clear: both;
+}
+
+/* alignments (blocks and inline) */
+/* ------------------------------ */
+
+/* left elements */
+.left {
+       float: left;
+}
+img.left {
+       margin-right: 1em;
+}
+
+/* right elements */
+.right {
+       float: right;
+}
+img.right {
+       margin-left: 1em;
+}
+
+img.left, img.right {
+       margin-bottom: 5px;
+}
+
+.center    { margin-left: auto; margin-right: auto; }
+.txtleft   { text-align: left; }
+.txtright  { text-align: right; }
+.txtcenter { text-align: center; }
+
+/* just inline-block */
+.inbl {
+       display: inline-block;
+       vertical-align: top;
+       margin-right: -.25em;
+}
+
+/* blocks widths (percentage and pixels) */
+.w10    { width: 10%; }
+.w20    { width: 20%; }
+.w25    { width: 25%; }
+.w30    { width: 30%; }
+.w33    { width: 33.333%; }
+.w40    { width: 40%; }
+.w50    { width: 50%; }
+.w60    { width: 60%; }
+.w66    { width: 66.666%; }
+.w70    { width: 70%; }
+.w75    { width: 75%; }
+.w80    { width: 80%; }
+.w90    { width: 90%; }
+.w100   { width: 100%; }
+
+.w50p   { width: 50px; }
+.w100p  { width: 100px; }
+.w150p  { width: 150px; }
+.w200p  { width: 200px; }
+.w300p  { width: 300px; }
+.w400p  { width: 400px; }
+.w500p  { width: 500px; }
+.w600p  { width: 600px; }
+.w700p  { width: 700px; }
+.w800p  { width: 800px; }
+.w960p  { width: 960px; }
+.mw960p { max-width: 960px; }
+
+/* spacing helpers
+p,m = padding,margin
+a,t,r,b,l = all,top,right,bottom,left
+s,m,l,n = small(10px),medium(20px),large(30px),none(0)
+source https://github.com/stubbornella/oocss/blob/master/core/spacing/space.css
+*/
+.m-reset, .ma0 { margin: 0 !important; }
+.p-reset, .pa0 { padding: 0 !important; }
+.ma1, .mas { margin: 10px !important; }
+.ma2, .mam { margin: 20px !important; }
+.ma3, .mal { margin: 30px !important; }
+.pa1, .pas { padding: 10px; }
+.pa2, .pam { padding: 20px; }
+.pa3, .pal { padding: 30px; }
+
+.mt0, .mtn { margin-top: 0 !important; }
+.mt1, .mts { margin-top: 10px !important; }
+.mt2, .mtm { margin-top: 20px !important; }
+.mt3, .mtl { margin-top: 30px !important; }
+.mr0, .mrn { margin-right: 0; }
+.mr1, .mrs { margin-right: 10px; }
+.mr2, .mrm { margin-right: 20px; }
+.mr3, .mrl { margin-right: 30px; }
+.mb0, .mbn { margin-bottom: 0 !important; }
+.mb1, .mbs { margin-bottom: 10px !important; }
+.mb2, .mbm { margin-bottom: 20px !important; }
+.mb3, .mbl { margin-bottom: 30px !important; }
+.ml0, .mln { margin-left: 0; }
+.ml1, .mls { margin-left: 10px; }
+.ml2, .mlm { margin-left: 20px; }
+.ml3, .mll { margin-left: 30px; }
+
+.pt0, .ptn { padding-top: 0; }
+.pt1, .pts { padding-top: 10px; }
+.pt2, .ptm { padding-top: 20px; }
+.pt3, .ptl { padding-top: 30px; }
+.pr0, .prn { padding-right: 0; }
+.pr1, .prs { padding-right: 10px; }
+.pr2, .prm { padding-right: 20px; }
+.pr3, .prl { padding-right: 30px; }
+.pb0, .pbn { padding-bottom: 0; }
+.pb1, .pbs { padding-bottom: 10px; }
+.pb2, .pbm { padding-bottom: 20px; }
+.pb3, .pbl { padding-bottom: 30px; }
+.pl0, .pln { padding-left: 0; }
+.pl1, .pls { padding-left: 10px; }
+.pl2, .plm { padding-left: 20px; }
+.pl3, .pll { padding-left: 30px; }
+
+/* hiding content */
+.visually-hidden {
+       position: absolute;
+       left: -7000px;
+       overflow: hidden;
+}
+[dir=rtl] .visually-hidden {
+       left: auto;
+       right: -7000px;
+}
+
+.desktop-hidden { display: none; } /* hidden on desktop */
+
+/* ----------------------------- */
+/* ==header */
+/* ----------------------------- */
+
+/* ----------------------------- */
+/* ==sidebar */
+/* ----------------------------- */
+
+/* ----------------------------- */
+/* ==footer */
+/* ----------------------------- */
+
+/* ----------------------------- */
+/* ==forms */
+/* ----------------------------- */
+form,
+fieldset {
+       border: none;
+}
+input,
+button,
+select,
+label,
+.btn {
+       vertical-align: middle; /* @bugfix alignment */
+       font-family: inherit;
+}
+textarea {
+       resize: vertical;
+       font-family: inherit;
+}
+
+/* ----------------------------- */
+/* ==main */
+/* ----------------------------- */
+
+/* ----------------------------- */
+/* ==iefix */
+/* ----------------------------- */
+
+/* haslayout for IE6/IE7 */
+.ie67 .clearfix,
+.ie67 .line,
+.ie67 .mod,
+.ie67 .row,
+.ie67 .col {
+       zoom: 1;
+}
+
+/* inline-block and table-cell for IE6/IE7 */
+/* warning: .col needs width on IE6/IE7 */
+.ie67 .btn,
+.ie67 .col,
+.ie67 .inbl {
+       display: inline;
+       zoom: 1;
+}
+.ie8 img {
+       width: auto; /* @bugfix for IE8 */
+}
+
+/* Active box-sizing for IE6/IE7 */
+/* @source https://github.com/Schepp/box-sizing-polyfill */
+/*
+.ie67 * {
+       behavior: url(/js/boxsizing.htc);
+}
+*/
+
+/* ----------------------------- */
+/* ==print */
+/* ----------------------------- */
+
+/* quick print reset */
+@media print {
+       p,
+       blockquote {
+               orphans: 2;
+               widows: 2;
+       }
+       blockquote,
+       ul,
+       ol {
+               page-break-inside: avoid;
+       }
+       h1,
+       h2,
+       h3,
+       caption {
+               page-break-after: avoid;
+       }
+}
+
+/* orientation iOS font-size fix */
+@media (orientation: landscape) and (max-device-width: 768px) {
+       html,
+       body {
+               -webkit-text-size-adjust: 100%;
+       }
+}
+/* ----------------------------- */
+/* ==grids                       */
+/* ----------------------------- */
+
+/* equal grids with 2% gutter */
+[class*=grid] > * {float: left; } /* direct childrens are floating */
+[class*=grid] > * + * { margin-left: 2%; } /* here's the gutter */
+.grid2 > * { width: 49%; }
+.grid3 > * { width: 32%; }
+.grid4 > * { width: 23.5%; }
+.grid5 > * { width: 18.4%; }
+.grid6 > * { width: 15%; }
+
+/* unequal grids (1-2, 2-1, 1-3 and 3-1) */
+.grid2-1 > *:first-child,
+.grid1-2 > * + * { width: 66%; }
+.grid1-2 > *:first-child,
+.grid2-1 > * + * { width: 32%; }
+.grid1-3 > *:first-child,
+.grid3-1 > * + * { width: 23.5%; }
+.grid3-1 > *:first-child,
+.grid1-3 > * + * { width: 74.5%; }
+
+
+/* ----------------------------- */
+/* ==tables                      */
+/* ----------------------------- */
+
+table,
+.table {
+       max-width : 100%;
+       table-layout: fixed;
+       border-collapse: collapse;
+       vertical-align: top;
+}
+table {
+       width: 100%;
+}
+.table {
+       display: table;
+}
+caption {
+       padding: 10px;
+       color: #555;
+       font-style: italic;     
+}
+table { 
+       border: 1px solid #ccc;
+}
+tr > * + * {
+       border-left: 1px solid #ccc;
+}
+th,
+td {
+       padding: .3em .8em;
+       text-align: left;
+       border-bottom: 1px solid #ccc;
+}
+td {
+       color: #333;
+}
+
+/* alternate tables */
+.alternate { border: 0; }
+.alternate tbody { 
+       border: 1px solid #ccc; 
+}
+.alternate thead tr > * + * {
+       border-left: 0;
+}
+.alternate tbody tr > * + * {
+       border-left: 1px solid #ccc;
+}
+
+/* alternate-vert tables */
+.alternate-vert { 
+       border: 0;
+       border-right: 1px solid #ccc;
+}
+.alternate-vert tr > :first-child {
+       border-bottom: 0;
+}
+.alternate-vert tr > * + * {
+       border-top: 1px solid #ccc;
+}
+
+/* striped tables */
+.striped tbody tr:nth-child(odd) {
+       background: #eee;
+       background: rgba(0, 0, 0, .05);
+}
+
+/* striped-vert tables */
+.striped-vert tr > :first-child {
+       background: #eee;
+       background: rgba(0, 0, 0, .05);
+}
+/* ----------------------------- */
+/* ==forms                       */
+/* ----------------------------- */
+
+/* thanks to HTML5boilerplate, github.com/nathansmith/formalize and www.sitepen.com */
+
+
+/* buttons */
+.btn { display: inline-block; }
+
+.btn.alternate {}
+.btn.highlight {}
+.login {}
+.logout {}
+.primary {}
+.warning {}
+.error {}
+.success {}
+
+/* forms items */
+label { 
+       display: inline-block;
+       vertical-align: middle;
+       cursor: pointer;
+}
+legend {
+       border: 0;
+       white-space: normal;
+}
+button,
+input,
+select {
+       font-family: "Century Gothic", helvetica, arial, sans-serif;
+       font-size: 100%;
+       margin: 0;
+       vertical-align: middle;
+}
+textarea {
+       overflow: auto; /* Removes default vertical scrollbar on empty textarea in IE6/7/8/9 */
+       min-height: 5em;
+       font-size: 1.75em;
+       vertical-align: top;
+       resize: vertical;
+}
+button,
+input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+       cursor: pointer;
+       -webkit-appearance: button; /* clickable input types in iOS */
+       *overflow: visible; /* Corrects inner spacing displayed oddly in IE7 */
+}
+input[type="checkbox"],
+input[type="radio"] {
+       padding: 0; /* Corrects excess space around these inputs in IE8/9 */
+       *width: 13px; *height: 13px; /* Corrects excess space around these inputs in IE7 */
+}
+input[type="search"] { -webkit-appearance: textfield; }
+
+/* if select styling bugs on WebKit */
+/* select { -webkit-appearance: none; } */
+
+/* 'x' appears on right of search input when text is entered. This removes it */
+input[type="search"]::-webkit-search-decoration,
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-results-button,
+input[type="search"]::-webkit-search-results-decoration {
+       display: none;
+}
+::-webkit-input-placeholder { color: #777; }
+input:-moz-placeholder,
+textarea:-moz-placeholder   { color: #777; }
+
+/* Removes inner padding and border in FF3+ */
+button::-moz-focus-inner,
+input[type='button']::-moz-focus-inner,
+input[type='reset']::-moz-focus-inner,
+input[type='submit']::-moz-focus-inner {
+       border: 0;
+       padding: 0;
+}
+
+/* ----------------------------- */
+/* ==icons and bullets           */
+/* ----------------------------- */
+
+.icon {display: inline-block;}
+
+.icon:before,
+.icon > li:before,
+.icon.after:after,
+.icon.after > li:after {
+  content: "";
+  display: inline-block;
+  vertical-align: middle;
+  position: relative; top: -.1em;
+  margin: 0 0.3em 0 0;
+  font: 1.4em/1 sans-serif;
+  color: #000;
+  text-shadow: 1px 1px 0 rgba(0,0,0,.1);
+  speak: none;
+}
+
+@media (min-device-width: 768px) {
+  .icon:before,
+  .icon > li:before,
+  .icon.after:after,
+  .icon.after > li:after {
+  font: 1em/0.6 sans-serif;
+  -webkit-transform: rotateZ(0.05deg);
+  }
+}
+
+.icon.after:after,
+.icon.after > li:after {
+  margin: 0 0 0 8px;
+}
+
+ul.icon {display: block;}
+ul.icon > li {list-style: none;}
+ul.icon:before,
+ul.icon.after:after {content:""}
+.icon.after:before,
+.icon.after > li:before {content: "" !important}
+
+.icon-rate:before, 
+.icon-rate > li:before,
+.icon-rate.after:after, 
+.icon-rate.after > li:after {
+  content: "\2605";
+}
+.icon-unrate:before, 
+.icon-unrate > li:before,
+.icon-unrate.after:after, 
+.icon-unrate.after > li:after {
+  content: "\2606";
+}
+.icon-check:before, 
+.icon-check > li:before,
+.icon-check.after:after, 
+.icon-check.after > li:after {
+  content: "\2713";
+}
+.icon-uncheck:before, 
+.icon-uncheck > li:before,
+.icon-uncheck.after:after, 
+.icon-uncheck.after > li:after {
+  content: "\2717";
+}
+.icon-cloud:before, 
+.icon-cloud > li:before,
+.icon-cloud.after:after, 
+.icon-cloud.after > li:after {
+  content: "\2601";
+}
+.icon-dl:before, 
+.icon-dl > li:before,
+.icon-dl.after:after, 
+.icon-dl.after > li:after {
+  content: "\21E3";
+  font-weight: bold;
+}
+.icon-cross:before, 
+.icon-cross > li:before,
+.icon-cross.after:after, 
+.icon-cross.after > li:after {
+  content: "\2716";
+  font-weight: bold;
+}
+.icon-arrow1:before, 
+.icon-arrow1 > li:before,
+.icon-arrow1.after:after, 
+.icon-arrow1.after > li:after {
+  content: "\2192";
+  position: relative; top: -0.15em;
+}
+.icon-arrow2:before, 
+.icon-arrow2 > li:before,
+.icon-arrow2.after:after, 
+.icon-arrow2.after > li:after {
+  content: "\279E";
+}
+.icon-arrow3:before, 
+.icon-arrow3 > li:before,
+.icon-arrow3.after:after, 
+.icon-arrow3.after > li:after {
+  content: "\279A";
+}
+.icon-bracket1:before, 
+.icon-bracket1 > li:before,
+.icon-bracket1.after:after, 
+.icon-bracket1.after > li:after {
+  content: "\2039";
+  font-weight: bold;
+  font-size: 1.6em;
+  position: relative; top: -0.15em;
+}
+.icon-bracket2:before, 
+.icon-bracket2 > li:before,
+.icon-bracket2.after:after, 
+.icon-bracket2.after > li:after {
+  content: "\203A";
+  font-weight: bold;
+  font-size: 1.6em;
+  position: relative; top: -0.15em;
+}
+.icon-up:before, 
+.icon-up > li:before,
+.icon-up.after:after, 
+.icon-up.after > li:after {
+  content: "\25B2";
+}
+.icon-down:before, 
+.icon-down > li:before,
+.icon-down.after:after, 
+.icon-down.after > li:after {
+  content: "\25BC";
+}
+.icon-bull:before, 
+.icon-bull > li:before,
+.icon-bull.after:after, 
+.icon-bull.after > li:after {
+  content: "\2022";
+  font-size: 1.2em;
+  top: -0.05em;
+}
+.icon-bull2:before, 
+.icon-bull2 > li:before,
+.icon-bull2.after:after, 
+.icon-bull2.after > li:after {
+  content: "\25E6";
+  top: -0.05em;
+}
+.icon-bull3:before, 
+.icon-bull3 > li:before,
+.icon-bull3.after:after, 
+.icon-bull3.after > li:after {
+  content: "\2023";
+  font-size: 1.6em;
+  top: -0.05em;
+}
+.icon-nav:before, 
+.icon-nav > li:before,
+.icon-nav.after:after, 
+.icon-nav.after > li:after {
+  content: "\2261";
+  font-weight: bold;
+  font-size: 1.6em;
+}
+.icon-losange:before, 
+.icon-losange > li:before,
+.icon-losange.after:after, 
+.icon-losange.after > li:after {
+  content: "\25C6";
+}
+.icon-asteri:before, 
+.icon-asteri > li:before,
+.icon-asteri.after:after, 
+.icon-asteri.after > li:after {
+  content: "\2731";
+  font-weight: bold;
+}
+.icon-mail:before, 
+.icon-mail > li:before,
+.icon-mail.after:after, 
+.icon-mail.after > li:after {
+  content: "\2709";
+  font-size: 1.6em;
+  top: -.05em;
+}
+
+ol.styled {counter-reset: styled;} 
+ol.styled > li {
+    list-style-type: none;
+    counter-increment: styled;
+    margin-bottom: .3em;
+}
+ol.styled > li:before {
+    content: counter(styled); 
+    display: inline-block;
+    width: 1em; height: 1em;
+    line-height: 1;
+    padding: 2px;
+    margin-right: .4em;
+    vertical-align: middle;
+    background: rgba(0,0,0,.5);
+    border-radius: 50%;
+    font-size: .9em;
+    text-align: center;
+    text-indent: -0.1em;
+    color: white;              
+}
+/* ----------------------------- */
+/* ==desktop and retina medias   */
+/* ----------------------------- */
+
+@media (min-width: 641px) {
+/* here go rules for big resources and big screens like: background-images, font-faces, etc. */
+}
+@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi), (min-resolution: 2dppx) {
+/* Style adjustments for retina devices */
+}
+
+/* ---------------------------------- */
+/* ==Responsive large / medium / tiny */
+/* ---------------------------------- */
+
+@media (min-width: 1280px) {
+
+       /* layouts for large (l) screens */
+       .large-hidden,
+       .tablet-hidden { display: none !important; }
+       .large-visible { display: block !important; }
+       .large-no-float {float: none; }
+       .large-inbl {
+               display: inline-block;
+               float: none;
+               vertical-align: top;
+       }
+       .large-row {
+               display: table;
+               table-layout: fixed;
+               width: 100% !important;
+       }
+       .large-col {
+               display: table-cell;
+               vertical-align: top;
+       }
+
+       /* widths for large (l) screens */
+       .large-w25 { width: 25% !important; }
+       .large-w33 { width: 33.3333% !important; }
+       .large-w50 { width: 50% !important; }
+       .large-w66 { width: 66.6666% !important; }
+       .large-w75 { width: 75% !important; }
+       .large-w100 {
+               display: block !important;
+               float: none !important;
+               clear: none !important;
+               width: auto !important;
+               margin-left: 0 !important;
+               margin-right: 0 !important;
+               border: 0;              
+       }
+
+       /* margins for large (l) screens */
+       .large-ma0,
+       .large-man { margin: 0 !important; }
+}
+
+@media (max-width: 768px) {
+
+       /* quick tablet reset */
+       .w60,
+       .w66,
+       .w70,
+       .w75,
+       .w80,
+       .w90,
+       .w100,
+       .w600p,
+       .w700p,
+       .w800p,
+       .w960p,
+       .mw960p,
+       .medium-wauto { width: auto; } 
+
+       /* layouts for medium (m) screens */
+       .medium-hidden,
+       .tablet-hidden { display: none !important; }
+       .medium-visible { display: block !important; }
+       .medium-no-float {float: none; }
+       .medium-inbl {
+               display: inline-block;
+               float: none;
+               vertical-align: top;
+       }
+       .medium-row {
+               display: table;
+               table-layout: fixed;
+               width: 100% !important;
+       }
+       .medium-col {
+               display: table-cell;
+               vertical-align: top;
+       }
+
+       /* widths for medium (m) screens */
+       .medium-w25 { width: 25% !important; }
+       .medium-w33 { width: 33.3333% !important; }
+       .medium-w50 { width: 50% !important; }
+       .medium-w66 { width: 66.6666% !important; }
+       .medium-w75 { width: 75% !important; }
+       .medium-w100 {
+               display: block !important;
+               float: none !important;
+               clear: none !important;
+               width: auto !important;
+               margin-left: 0 !important;
+               margin-right: 0 !important;
+               border: 0;              
+       }
+       /* margins for medium (m) screens */
+       .medium-ma0,
+       .medium-man { margin: 0 !important; }
+
+       /* Responsive grids */
+       .grid4 > * {width: 49% !important; } 
+       .grid4 > :first-child + * + * {margin-left: 0 !important;}
+       .grid6 > * {width: 32% !important; }  
+       .grid6 > :first-child + * + * + * {margin-left: 0 !important;}
+}
+
+@media (max-width: 640px) {
+
+       /* quick smartphone reset */
+       .mod,
+       .item,
+       .col,
+       fieldset {
+               display: block !important;
+               float: none !important;
+               clear: none !important;
+               width: auto !important;
+               margin-left: 0 !important;
+               margin-right: 0 !important;
+               border: 0;
+       }
+       .w30,
+       .w33, 
+       .w40,
+       .w50,
+       .w300p,
+       .w400p,
+       .w500p {
+               width: auto;
+       }
+       .row { 
+               display: block !important;
+               width: 100% !important;
+       }
+
+       /* layouts for tiny (t) screens */
+       .tiny-hidden,
+       .phone-hidden { display: none !important; }
+       .tiny-visible { display: block !important; }
+       .tiny-no-float {float: none;}
+       .tiny-inbl {
+               display: inline-block;
+               float: none;
+               vertical-align: top;
+       }
+       .tiny-row {
+               display: table;
+               table-layout: fixed;
+               width: 100% !important;
+       }
+       .tiny-col {
+               display: table-cell;
+               vertical-align: top;
+       }
+       th,
+       td {
+               display: block !important;
+               width: auto !important;
+               text-align: left !important;
+       }
+       thead { display: none; }
+
+       /* widths for tiny (t) screens */
+       .tiny-w25 { width: 25% !important; }
+       .tiny-w33 { width: 33.3333% !important; }
+       .tiny-w50 { width: 50% !important; }
+       .tiny-w66 { width: 66.6666% !important; }
+       .tiny-w75 { width: 75% !important; }
+       .tiny-w100 { 
+               display: block !important;
+               float: none !important;
+               clear: none !important;
+               width: auto !important;
+               margin-left: 0 !important;
+               margin-right: 0 !important;
+               border: 0;
+       }
+       /* margins for tiny (t) screens */
+       .tiny-ma0,
+       .tiny-man { margin: 0 !important; }
+}
+
diff --git a/css/reset.css b/css/reset.css
new file mode 100755 (executable)
index 0000000..530ddc3
--- /dev/null
@@ -0,0 +1,35 @@
+html, body, div, span, object, iframe,\r
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,\r
+a, abbr, acronym, address, code,\r
+del, dfn, em, img, q, dl, dt, dd, ol, ul, li,\r
+fieldset, form, label, legend,\r
+table, caption, tbody, tfoot, thead, tr, th, td {\r
+  margin: 0;\r
+  padding: 0;\r
+  border: 0;\r
+  font-weight: inherit;\r
+  font-style: inherit;\r
+  font-size: 100%;\r
+  font-family: inherit;\r
+  vertical-align: baseline;\r
+}\r
+\r
+\r
+/* Tables still need 'cellspacing="0"' in the markup. */\r
+table { border-collapse: separate; border-spacing: 0; }\r
+caption, th, td { text-align: left; font-weight: normal; }\r
+table, td, th { vertical-align: middle; }\r
+\r
+/* Remove possible quote marks (") from <q>, <blockquote>. */\r
+blockquote:before, blockquote:after, q:before, q:after { content: ""; }\r
+blockquote, q { quotes: "" ""; }\r
+\r
+/* Remove annoying border on linked images. */\r
+a img { border: none; }\r
+\r
+\r
+body {\r
+  \r
+  margin: 10px;\r
+}\r
+\r
diff --git a/css/style.css b/css/style.css
new file mode 100644 (file)
index 0000000..41a6178
--- /dev/null
@@ -0,0 +1,35 @@
+body {
+    color: #222222;
+    font: 20px/1.3em Palatino,Georgia,serif;
+    background-color: #e6e6e6;
+}
+
+a, a:hover, a:visited {
+    color: #000;
+}
+header {
+    text-align: center;
+}
+
+#main {
+    margin: 0 auto;
+}
+
+#main ul#links {
+    padding: 0;
+    list-style-type: none;
+    text-align: center;
+}
+
+#main ul#links li {
+    display: inline;
+    padding: 15px;
+}
+
+#main a.tool {
+    text-decoration: none;
+}
+
+footer {
+    text-align: right;
+}
\ No newline at end of file
diff --git a/css/typography.css b/css/typography.css
new file mode 100755 (executable)
index 0000000..e41db09
--- /dev/null
@@ -0,0 +1,85 @@
+\r
+body { \r
+       font:1em/1.625em "lucida grande","lucida sans unicode", sans-serif; background-color:#FFFEF0;  \r
+       font-size-adjust:none;\r
+       font-style:normal;\r
+       font-variant:normal;\r
+       font-weight:normal;\r
+       padding: 15px;\r
+       margin: 15px auto;\r
+}\r
+\r
+article {\r
+       border: 3px solid grey;\r
+       max-width:700px;\r
+       margin: 15px auto;\r
+       padding: 15px;\r
+}\r
+\r
+footer {\r
+       border: 1px solid black;\r
+       padding: 15px;\r
+       margin: 15px auto;\r
+}\r
+\r
+p { padding:0 0  0.8125em 0; color:#111; font-weight:300;}\r
+\r
+p + p { text-indent:1.625em;}\r
+\r
+img       { display: block; margin: 0.5em 0.8125em 0.8125em 0; padding: 0; }\r
+\r
+p > img { display: inline-block; margin: 0; }\r
+\r
+h1,h2{ font-weight:normal; color: #333; font-family:Georgia, serif;  }\r
+h3,h4,h5,h6 { font-weight: normal; color: #333; font-family:Georgia, serif; }\r
+\r
+\r
+h1 { font-size: 2.125em; margin-bottom: 0.765em; line-height: 1.5em;}\r
+h2 { font-size: 1.9em;  margin-bottom: 0.855em; }\r
+h3 { font-size: 1.7em;  margin-bottom: 0.956em; }\r
+h4 { font-size: 1.4em;  margin-bottom: 1.161em; }\r
+h5,h6 { font-size: 1.313em;  margin-bottom: 1.238em; }\r
+\r
+\r
+\r
+ul{list-style-position:outside;}\r
+li ul, \r
+li ol  { margin:0 1.625em;  }\r
+ul, ol { margin: 0 0 1.625em 0; }\r
+\r
+\r
+dl { margin: 0 0 1.625em 0; }\r
+dl dt { font-weight: bold; }\r
+dl dd { margin-left: 1.625em; }\r
+\r
+a { color:#005AF2; text-decoration:none; }\r
+a:hover { text-decoration: underline; }\r
+\r
+\r
+table { margin-bottom:1.625em; border-collapse: collapse; }\r
+th { font-weight:bold; }\r
+tr,th,td { margin:0; padding:0 1.625em 0 1em; height:26px; }\r
+tfoot { font-style: italic; }\r
+caption { text-align:center; font-family:Georgia, serif; }\r
+\r
+\r
+abbr, acronym { border-bottom:1px dotted #000; }\r
+address { margin-top:1.625em; font-style: italic; }\r
+del {color:#000;}\r
+\r
+\r
+blockquote { padding:1em 1em 1.625em 1em; font-family:georgia,serif;font-style: italic;  }\r
+blockquote:before { content:"\201C";font-size:3em;margin-left:-.625em; font-family:georgia,serif;color:#aaa;line-height:0;}/* From Tripoli  */\r
+blockquote > p {padding:0; margin:0; }\r
+\r
+strong { font-weight: bold; }\r
+em, dfn { font-style: italic; }\r
+dfn { font-weight: bold; }\r
+pre, code { margin: 1.625em 0; white-space: pre; }\r
+pre, code, tt { font: 1em monospace; line-height: 1.5; } \r
+tt { display: block; margin: 1.625em 0; }\r
+hr { margin-bottom:1.625em; }\r
+\r
+.oldbook { font-family:"Warnock Pro","Goudy Old Style","Book Antiqua","Palatino",Georgia,serif; }\r
+.note { font-family:Georgia, "Times New Roman", Times, serif; font-style:italic; font-size:0.9em; margin:0.1em; color:#333; } \r
+.mono { font-family:"Courier New", Courier, monospace; }\r
diff --git a/inc/Encoding.php b/inc/Encoding.php
new file mode 100755 (executable)
index 0000000..ac107af
--- /dev/null
@@ -0,0 +1,262 @@
+<?php \r
+/**\r
+ * @author   "Sebastián Grignoli" <grignoli@framework2.com.ar>\r
+ * @package  Encoding\r
+ * @version  1.1\r
+ * @link     http://www.framework2.com.ar/dzone/forceUTF8-es/\r
+ * @example  http://www.framework2.com.ar/dzone/forceUTF8-es/\r
+  */\r
+\r
+class Encoding {\r
+    \r
+  protected static $win1252ToUtf8 = array(\r
+        128 => "\xe2\x82\xac",\r
+\r
+        130 => "\xe2\x80\x9a",\r
+        131 => "\xc6\x92",\r
+        132 => "\xe2\x80\x9e",\r
+        133 => "\xe2\x80\xa6",\r
+        134 => "\xe2\x80\xa0",\r
+        135 => "\xe2\x80\xa1",\r
+        136 => "\xcb\x86",\r
+        137 => "\xe2\x80\xb0",\r
+        138 => "\xc5\xa0",\r
+        139 => "\xe2\x80\xb9",\r
+        140 => "\xc5\x92",\r
+\r
+        142 => "\xc5\xbd",\r
+\r
+\r
+        145 => "\xe2\x80\x98",\r
+        146 => "\xe2\x80\x99",\r
+        147 => "\xe2\x80\x9c",\r
+        148 => "\xe2\x80\x9d",\r
+        149 => "\xe2\x80\xa2",\r
+        150 => "\xe2\x80\x93",\r
+        151 => "\xe2\x80\x94",\r
+        152 => "\xcb\x9c",\r
+        153 => "\xe2\x84\xa2",\r
+        154 => "\xc5\xa1",\r
+        155 => "\xe2\x80\xba",\r
+        156 => "\xc5\x93",\r
+\r
+        158 => "\xc5\xbe",\r
+        159 => "\xc5\xb8"\r
+  );\r
+  \r
+    protected static $brokenUtf8ToUtf8 = array(\r
+        "\xc2\x80" => "\xe2\x82\xac",\r
+        \r
+        "\xc2\x82" => "\xe2\x80\x9a",\r
+        "\xc2\x83" => "\xc6\x92",\r
+        "\xc2\x84" => "\xe2\x80\x9e",\r
+        "\xc2\x85" => "\xe2\x80\xa6",\r
+        "\xc2\x86" => "\xe2\x80\xa0",\r
+        "\xc2\x87" => "\xe2\x80\xa1",\r
+        "\xc2\x88" => "\xcb\x86",\r
+        "\xc2\x89" => "\xe2\x80\xb0",\r
+        "\xc2\x8a" => "\xc5\xa0",\r
+        "\xc2\x8b" => "\xe2\x80\xb9",\r
+        "\xc2\x8c" => "\xc5\x92",\r
+        \r
+        "\xc2\x8e" => "\xc5\xbd",\r
+        \r
+        \r
+        "\xc2\x91" => "\xe2\x80\x98",\r
+        "\xc2\x92" => "\xe2\x80\x99",\r
+        "\xc2\x93" => "\xe2\x80\x9c",\r
+        "\xc2\x94" => "\xe2\x80\x9d",\r
+        "\xc2\x95" => "\xe2\x80\xa2",\r
+        "\xc2\x96" => "\xe2\x80\x93",\r
+        "\xc2\x97" => "\xe2\x80\x94",\r
+        "\xc2\x98" => "\xcb\x9c",\r
+        "\xc2\x99" => "\xe2\x84\xa2",\r
+        "\xc2\x9a" => "\xc5\xa1",\r
+        "\xc2\x9b" => "\xe2\x80\xba",\r
+        "\xc2\x9c" => "\xc5\x93",\r
+        \r
+        "\xc2\x9e" => "\xc5\xbe",\r
+        "\xc2\x9f" => "\xc5\xb8"\r
+  );\r
+    \r
+  protected static $utf8ToWin1252 = array(\r
+       "\xe2\x82\xac" => "\x80",\r
+       \r
+       "\xe2\x80\x9a" => "\x82",\r
+       "\xc6\x92"     => "\x83",\r
+       "\xe2\x80\x9e" => "\x84",\r
+       "\xe2\x80\xa6" => "\x85",\r
+       "\xe2\x80\xa0" => "\x86",\r
+       "\xe2\x80\xa1" => "\x87",\r
+       "\xcb\x86"     => "\x88",\r
+       "\xe2\x80\xb0" => "\x89",\r
+       "\xc5\xa0"     => "\x8a",\r
+       "\xe2\x80\xb9" => "\x8b",\r
+       "\xc5\x92"     => "\x8c",\r
+       \r
+       "\xc5\xbd"     => "\x8e",\r
+       \r
+       \r
+       "\xe2\x80\x98" => "\x91",\r
+       "\xe2\x80\x99" => "\x92",\r
+       "\xe2\x80\x9c" => "\x93",\r
+       "\xe2\x80\x9d" => "\x94",\r
+       "\xe2\x80\xa2" => "\x95",\r
+       "\xe2\x80\x93" => "\x96",\r
+       "\xe2\x80\x94" => "\x97",\r
+       "\xcb\x9c"     => "\x98",\r
+       "\xe2\x84\xa2" => "\x99",\r
+       "\xc5\xa1"     => "\x9a",\r
+       "\xe2\x80\xba" => "\x9b",\r
+       "\xc5\x93"     => "\x9c",\r
+       \r
+       "\xc5\xbe"     => "\x9e",\r
+       "\xc5\xb8"     => "\x9f"\r
+    );\r
+\r
+  static function toUTF8($text){\r
+  /**\r
+   * Function Encoding::toUTF8\r
+   *\r
+   * This function leaves UTF8 characters alone, while converting almost all non-UTF8 to UTF8.\r
+   * \r
+   * It assumes that the encoding of the original string is either Windows-1252 or ISO 8859-1.\r
+   *\r
+   * It may fail to convert characters to UTF-8 if they fall into one of these scenarios:\r
+   *\r
+   * 1) when any of these characters:   ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß\r
+   *    are followed by any of these:  ("group B")\r
+   *                                    ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶•¸¹º»¼½¾¿\r
+   * For example:   %ABREPRESENT%C9%BB. «REPRESENTÉ»\r
+   * The "«" (%AB) character will be converted, but the "É" followed by "»" (%C9%BB) \r
+   * is also a valid unicode character, and will be left unchanged.\r
+   *\r
+   * 2) when any of these: àáâãäåæçèéêëìíîï  are followed by TWO chars from group B,\r
+   * 3) when any of these: ðñòó  are followed by THREE chars from group B.\r
+   *\r
+   * @name toUTF8\r
+   * @param string $text  Any string.\r
+   * @return string  The same string, UTF8 encoded\r
+   *\r
+   */\r
+\r
+    if(is_array($text))\r
+    {\r
+      foreach($text as $k => $v)\r
+      {\r
+        $text[$k] = self::toUTF8($v);\r
+      }\r
+      return $text;\r
+    } elseif(is_string($text)) {\r
+    \r
+      $max = strlen($text);\r
+      $buf = "";\r
+      for($i = 0; $i < $max; $i++){\r
+          $c1 = $text{$i};\r
+          if($c1>="\xc0"){ //Should be converted to UTF8, if it's not UTF8 already\r
+            $c2 = $i+1 >= $max? "\x00" : $text{$i+1};\r
+            $c3 = $i+2 >= $max? "\x00" : $text{$i+2};\r
+            $c4 = $i+3 >= $max? "\x00" : $text{$i+3};\r
+              if($c1 >= "\xc0" & $c1 <= "\xdf"){ //looks like 2 bytes UTF8\r
+                  if($c2 >= "\x80" && $c2 <= "\xbf"){ //yeah, almost sure it's UTF8 already\r
+                      $buf .= $c1 . $c2;\r
+                      $i++;\r
+                  } else { //not valid UTF8.  Convert it.\r
+                      $cc1 = (chr(ord($c1) / 64) | "\xc0");\r
+                      $cc2 = ($c1 & "\x3f") | "\x80";\r
+                      $buf .= $cc1 . $cc2;\r
+                  }\r
+              } elseif($c1 >= "\xe0" & $c1 <= "\xef"){ //looks like 3 bytes UTF8\r
+                  if($c2 >= "\x80" && $c2 <= "\xbf" && $c3 >= "\x80" && $c3 <= "\xbf"){ //yeah, almost sure it's UTF8 already\r
+                      $buf .= $c1 . $c2 . $c3;\r
+                      $i = $i + 2;\r
+                  } else { //not valid UTF8.  Convert it.\r
+                      $cc1 = (chr(ord($c1) / 64) | "\xc0");\r
+                      $cc2 = ($c1 & "\x3f") | "\x80";\r
+                      $buf .= $cc1 . $cc2;\r
+                  }\r
+              } elseif($c1 >= "\xf0" & $c1 <= "\xf7"){ //looks like 4 bytes UTF8\r
+                  if($c2 >= "\x80" && $c2 <= "\xbf" && $c3 >= "\x80" && $c3 <= "\xbf" && $c4 >= "\x80" && $c4 <= "\xbf"){ //yeah, almost sure it's UTF8 already\r
+                      $buf .= $c1 . $c2 . $c3;\r
+                      $i = $i + 2;\r
+                  } else { //not valid UTF8.  Convert it.\r
+                      $cc1 = (chr(ord($c1) / 64) | "\xc0");\r
+                      $cc2 = ($c1 & "\x3f") | "\x80";\r
+                      $buf .= $cc1 . $cc2;\r
+                  }\r
+              } else { //doesn't look like UTF8, but should be converted\r
+                      $cc1 = (chr(ord($c1) / 64) | "\xc0");\r
+                      $cc2 = (($c1 & "\x3f") | "\x80");\r
+                      $buf .= $cc1 . $cc2;\r
+              }\r
+          } elseif(($c1 & "\xc0") == "\x80"){ // needs conversion\r
+                if(isset(self::$win1252ToUtf8[ord($c1)])) { //found in Windows-1252 special cases\r
+                    $buf .= self::$win1252ToUtf8[ord($c1)];\r
+                } else {\r
+                  $cc1 = (chr(ord($c1) / 64) | "\xc0");\r
+                  $cc2 = (($c1 & "\x3f") | "\x80");\r
+                  $buf .= $cc1 . $cc2;\r
+                }\r
+          } else { // it doesn't need convesion\r
+              $buf .= $c1;\r
+          }\r
+      }\r
+      return $buf;\r
+    } else {\r
+      return $text;\r
+    }\r
+  }\r
+\r
+  static function toWin1252($text) {\r
+    if(is_array($text)) {\r
+      foreach($text as $k => $v) {\r
+        $text[$k] = self::toWin1252($v);\r
+      }\r
+      return $text;\r
+    } elseif(is_string($text)) {\r
+      return utf8_decode(str_replace(array_keys(self::$utf8ToWin1252), array_values(self::$utf8ToWin1252), self::toUTF8($text)));\r
+    } else {\r
+      return $text;\r
+    }\r
+  }\r
+\r
+  static function toISO8859($text) {\r
+    return self::toWin1252($text);\r
+  }\r
+\r
+  static function toLatin1($text) {\r
+    return self::toWin1252($text);\r
+  }\r
+\r
+  static function fixUTF8($text){\r
+    if(is_array($text)) {\r
+      foreach($text as $k => $v) {\r
+        $text[$k] = self::fixUTF8($v);\r
+      }\r
+      return $text;\r
+    }\r
+\r
+    $last = "";\r
+    while($last <> $text){\r
+      $last = $text;\r
+      $text = self::toUTF8(utf8_decode(str_replace(array_keys(self::$utf8ToWin1252), array_values(self::$utf8ToWin1252), $text)));\r
+    }\r
+    $text = self::toUTF8(utf8_decode(str_replace(array_keys(self::$utf8ToWin1252), array_values(self::$utf8ToWin1252), $text)));\r
+    return $text;\r
+  }\r
+  \r
+  static function UTF8FixWin1252Chars($text){\r
+    // If you received an UTF-8 string that was converted from Windows-1252 as it was ISO8859-1 \r
+    // (ignoring Windows-1252 chars from 80 to 9F) use this function to fix it.\r
+    // See: http://en.wikipedia.org/wiki/Windows-1252\r
+    \r
+    return str_replace(array_keys(self::$brokenUtf8ToUtf8), array_values(self::$brokenUtf8ToUtf8), $text);\r
+  }\r
+  \r
+  static function removeBOM($str=""){\r
+    if(substr($str, 0,3) == pack("CCC",0xef,0xbb,0xbf)) {\r
+      $str=substr($str, 3);\r
+    }\r
+    return $str;\r
+  }\r
+}
\ No newline at end of file
diff --git a/inc/JSLikeHTMLElement.php b/inc/JSLikeHTMLElement.php
new file mode 100755 (executable)
index 0000000..0557205
--- /dev/null
@@ -0,0 +1,110 @@
+<?php
+/**
+* JavaScript-like HTML DOM Element
+*
+* This class extends PHP's DOMElement to allow
+* users to get and set the innerHTML property of
+* HTML elements in the same way it's done in 
+* JavaScript.
+*
+* Example usage:
+* @code
+* require_once 'JSLikeHTMLElement.php';
+* header('Content-Type: text/plain');
+* $doc = new DOMDocument();
+* $doc->registerNodeClass('DOMElement', 'JSLikeHTMLElement');
+* $doc->loadHTML('<div><p>Para 1</p><p>Para 2</p></div>');
+* $elem = $doc->getElementsByTagName('div')->item(0);
+* 
+* // print innerHTML
+* echo $elem->innerHTML; // prints '<p>Para 1</p><p>Para 2</p>'
+* echo "\n\n";
+* 
+* // set innerHTML
+* $elem->innerHTML = '<a href="http://fivefilters.org">FiveFilters.org</a>';
+* echo $elem->innerHTML; // prints '<a href="http://fivefilters.org">FiveFilters.org</a>'
+* echo "\n\n";
+* 
+* // print document (with our changes)
+* echo $doc->saveXML();
+* @endcode
+*
+* @author Keyvan Minoukadeh - http://www.keyvan.net - keyvan@keyvan.net
+* @see http://fivefilters.org (the project this was written for)
+*/
+class JSLikeHTMLElement extends DOMElement
+{
+       /**
+       * Used for setting innerHTML like it's done in JavaScript:
+       * @code
+       * $div->innerHTML = '<h2>Chapter 2</h2><p>The story begins...</p>';
+       * @endcode
+       */
+       public function __set($name, $value) {
+               if ($name == 'innerHTML') {
+                       // first, empty the element
+                       for ($x=$this->childNodes->length-1; $x>=0; $x--) {
+                               $this->removeChild($this->childNodes->item($x));
+                       }
+                       // $value holds our new inner HTML
+                       if ($value != '') {
+                               $f = $this->ownerDocument->createDocumentFragment();
+                               // appendXML() expects well-formed markup (XHTML)
+                               $result = @$f->appendXML($value); // @ to suppress PHP warnings
+                               if ($result) {
+                                       if ($f->hasChildNodes()) $this->appendChild($f);
+                               } else {
+                                       // $value is probably ill-formed
+                                       $f = new DOMDocument();
+                                       $value = mb_convert_encoding($value, 'HTML-ENTITIES', 'UTF-8');
+                                       // Using <htmlfragment> will generate a warning, but so will bad HTML
+                                       // (and by this point, bad HTML is what we've got).
+                                       // We use it (and suppress the warning) because an HTML fragment will 
+                                       // be wrapped around <html><body> tags which we don't really want to keep.
+                                       // Note: despite the warning, if loadHTML succeeds it will return true.
+                                       $result = @$f->loadHTML('<htmlfragment>'.$value.'</htmlfragment>');
+                                       if ($result) {
+                                               $import = $f->getElementsByTagName('htmlfragment')->item(0);
+                                               foreach ($import->childNodes as $child) {
+                                                       $importedNode = $this->ownerDocument->importNode($child, true);
+                                                       $this->appendChild($importedNode);
+                                               }
+                                       } else {
+                                               // oh well, we tried, we really did. :(
+                                               // this element is now empty
+                                       }
+                               }
+                       }
+               } else {
+                       $trace = debug_backtrace();
+                       trigger_error('Undefined property via __set(): '.$name.' in '.$trace[0]['file'].' on line '.$trace[0]['line'], E_USER_NOTICE);
+               }
+       }
+
+       /**
+       * Used for getting innerHTML like it's done in JavaScript:
+       * @code
+       * $string = $div->innerHTML;
+       * @endcode
+       */      
+       public function __get($name)
+       {
+               if ($name == 'innerHTML') {
+                       $inner = '';
+                       foreach ($this->childNodes as $child) {
+                               $inner .= $this->ownerDocument->saveXML($child);
+                       }
+                       return $inner;
+               }
+
+               $trace = debug_backtrace();
+               trigger_error('Undefined property via __get(): '.$name.' in '.$trace[0]['file'].' on line '.$trace[0]['line'], E_USER_NOTICE);
+               return null;
+       }
+
+       public function __toString()
+       {
+               return '['.$this->tagName.']';
+       }
+}
+?>
\ No newline at end of file
diff --git a/inc/Readability.php b/inc/Readability.php
new file mode 100755 (executable)
index 0000000..52a37d5
--- /dev/null
@@ -0,0 +1,1103 @@
+<?php
+/** 
+* Arc90's Readability ported to PHP for FiveFilters.org
+* Based on readability.js version 1.7.1 (without multi-page support)
+* ------------------------------------------------------
+* Original URL: http://lab.arc90.com/experiments/readability/js/readability.js
+* Arc90's project URL: http://lab.arc90.com/experiments/readability/
+* JS Source: http://code.google.com/p/arc90labs-readability
+* Ported by: Keyvan Minoukadeh, http://www.keyvan.net
+* More information: http://fivefilters.org/content-only/
+* License: Apache License, Version 2.0
+* Requires: PHP5
+* Date: 2011-07-22
+* 
+* Differences between the PHP port and the original
+* ------------------------------------------------------
+* Arc90's Readability is designed to run in the browser. It works on the DOM 
+* tree (the parsed HTML) after the page's CSS styles have been applied and 
+* Javascript code executed. This PHP port does not run inside a browser. 
+* We use PHP's ability to parse HTML to build our DOM tree, but we cannot 
+* rely on CSS or Javascript support. As such, the results will not always 
+* match Arc90's Readability. (For example, if a web page contains CSS style 
+* rules or Javascript code which hide certain HTML elements from display, 
+* Arc90's Readability will dismiss those from consideration but our PHP port, 
+* unable to understand CSS or Javascript, will not know any better.)
+* 
+* Another significant difference is that the aim of Arc90's Readability is 
+* to re-present the main content block of a given web page so users can 
+* read it more easily in their browsers. Correct identification, clean up, 
+* and separation of the content block is only a part of this process. 
+* This PHP port is only concerned with this part, it does not include code 
+* that relates to presentation in the browser - Arc90 already do 
+* that extremely well, and for PDF output there's FiveFilters.org's 
+* PDF Newspaper: http://fivefilters.org/pdf-newspaper/.
+* 
+* Finally, this class contains methods that might be useful for developers 
+* working on HTML document fragments. So without deviating too much from 
+* the original code (which I don't want to do because it makes debugging 
+* and updating more difficult), I've tried to make it a little more 
+* developer friendly. You should be able to use the methods here on 
+* existing DOMElement objects without passing an entire HTML document to 
+* be parsed.
+*/
+
+// This class allows us to do JavaScript like assignements to innerHTML
+require_once(dirname(__FILE__).'/JSLikeHTMLElement.php');
+
+// Alternative usage (for testing only!)
+// uncomment the lines below and call Readability.php in your browser 
+// passing it the URL of the page you'd like content from, e.g.:
+// Readability.php?url=http://medialens.org/alerts/09/090615_the_guardian_climate.php
+
+/*
+if (!isset($_GET['url']) || $_GET['url'] == '') {
+       die('Please pass a URL to the script. E.g. Readability.php?url=bla.com/story.html');
+}
+$url = $_GET['url'];
+if (!preg_match('!^https?://!i', $url)) $url = 'http://'.$url;
+$html = file_get_contents($url);
+$r = new Readability($html, $url);
+$r->init();
+echo $r->articleContent->innerHTML;
+*/
+
+       
+class Readability
+{
+       /* constants */
+       const FLAG_STRIP_UNLIKELYS = 1;
+       const FLAG_WEIGHT_CLASSES = 2;
+       const FLAG_CLEAN_CONDITIONALLY = 4;
+
+       public $version = '1.7.1-without-multi-page';
+       public $convertLinksToFootnotes = false;
+       public $revertForcedParagraphElements = true;
+       public $articleTitle;
+       public $articleContent;
+       public $dom;
+       public $url = null; // optional - URL where HTML was retrieved
+       public $debug = false;
+       protected $body = null; // 
+       protected $bodyCache = null; // Cache the body HTML in case we need to re-use it later
+       protected $flags = FLAG_CLEAN_CONDITIONALLY; // 1 | 2 | 4;   // Start with all flags set.
+       protected $success = false; // indicates whether we were able to extract or not
+       
+       /**
+       * All of the regular expressions in use within readability.
+       * Defined up here so we don't instantiate them repeatedly in loops.
+       **/
+       public $regexps = array(
+               'unlikelyCandidates' => '/combx|comment|comments|community|disqus|extra|foot|header|menu|remark|rss|shoutbox|sidebar|sponsor|ad-break|agegate|pagination|pager|popup|tweet|twitter/i',
+               'okMaybeItsACandidate' => '/and|article|body|column|main|shadow/i',
+               'positive' => '/article|body|content|entry|hentry|main|page|pagination|post|text|blog|story/i',
+               'negative' => '/combx|comment|comments|com-|contact|foot|footer|footnote|masthead|media|meta|outbrain|promo|related|scroll|shoutbox|sidebar|sponsor|shopping|tags|tool|widget/i',
+               'divToPElements' => '/<(a|blockquote|dl|div|ol|p|pre|table|ul)/i',
+               'replaceBrs' => '/(<br[^>]*>[ \n\r\t]*){2,}/i',
+               'replaceFonts' => '/<(\/?)font[^>]*>/i',
+               // 'trimRe' => '/^\s+|\s+$/g', // PHP has trim()
+               'normalize' => '/\s{2,}/',
+               'killBreaks' => '/(<br\s*\/?>(\s|&nbsp;?)*){1,}/',
+               'video' => '/http:\/\/(www\.)?(youtube|vimeo|dailymotion)\.com/i',
+               'skipFootnoteLink' => '/^\s*(\[?[a-z0-9]{1,2}\]?|^|edit|citation needed)\s*$/i'
+       );      
+       
+       /**
+       * Create instance of Readability
+       * @param string UTF-8 encoded string
+       * @param string (optional) URL associated with HTML (used for footnotes)
+       */      
+       function __construct($html, $url=null)
+       {
+               /* Turn all double br's into p's */
+               $html = preg_replace($this->regexps['replaceBrs'], '</p><p>', $html);
+               $html = preg_replace($this->regexps['replaceFonts'], '<$1span>', $html);
+               $html = mb_convert_encoding($html, 'HTML-ENTITIES', "UTF-8");
+               $this->dom = new DOMDocument();
+               $this->dom->preserveWhiteSpace = false;
+               $this->dom->registerNodeClass('DOMElement', 'JSLikeHTMLElement');
+               if (trim($html) == '') $html = '<html></html>';
+               @$this->dom->loadHTML($html);
+               $this->url = $url;
+       }
+
+       /**
+       * Get article title element
+       * @return DOMElement
+       */
+       public function getTitle() {
+               return $this->articleTitle;
+       }
+       
+       /**
+       * Get article content element
+       * @return DOMElement
+       */
+       public function getContent() {
+               return $this->articleContent;
+       }       
+       
+       /**
+       * Runs readability.
+       * 
+       * Workflow:
+       *  1. Prep the document by removing script tags, css, etc.
+       *  2. Build readability's DOM tree.
+       *  3. Grab the article content from the current dom tree.
+       *  4. Replace the current DOM tree with the new one.
+       *  5. Read peacefully.
+       *
+       * @return boolean true if we found content, false otherwise
+       **/
+       public function init()
+       {
+               if (!isset($this->dom->documentElement)) return false;
+               $this->removeScripts($this->dom);
+               //die($this->getInnerHTML($this->dom->documentElement));
+               
+               // Assume successful outcome
+               $this->success = true;
+
+               $bodyElems = $this->dom->getElementsByTagName('body');
+               if ($bodyElems->length > 0) {
+                       if ($this->bodyCache == null) {
+                               $this->bodyCache = $bodyElems->item(0)->innerHTML;
+                       }
+                       if ($this->body == null) {
+                               $this->body = $bodyElems->item(0);
+                       }
+               }
+
+               $this->prepDocument();
+               
+               //die($this->dom->documentElement->parentNode->nodeType);
+               //$this->setInnerHTML($this->dom->documentElement, $this->getInnerHTML($this->dom->documentElement));
+               //die($this->getInnerHTML($this->dom->documentElement));
+
+               /* Build readability's DOM tree */
+               $overlay        = $this->dom->createElement('div');
+               $innerDiv       = $this->dom->createElement('div');
+               $articleTitle   = $this->getArticleTitle();
+               $articleContent = $this->grabArticle();
+
+               if (!$articleContent) {
+                       $this->success = false;
+                       $articleContent = $this->dom->createElement('div');
+                       $articleContent->setAttribute('id', 'readability-content');
+                       $articleContent->innerHTML = '<p>Sorry, Readability was unable to parse this page for content.</p>';            
+               }
+               
+               $overlay->setAttribute('id', 'readOverlay');
+               $innerDiv->setAttribute('id', 'readInner');
+
+               /* Glue the structure of our document together. */
+               $innerDiv->appendChild($articleTitle);
+               $innerDiv->appendChild($articleContent);
+               $overlay->appendChild($innerDiv);
+               
+               /* Clear the old HTML, insert the new content. */
+               $this->body->innerHTML = '';
+               $this->body->appendChild($overlay);
+               //document.body.insertBefore(overlay, document.body.firstChild);
+               $this->body->removeAttribute('style');
+
+               $this->postProcessContent($articleContent);
+               
+               // Set title and content instance variables
+               $this->articleTitle = $articleTitle;
+               $this->articleContent = $articleContent;
+               
+               return $this->success;
+       }
+       
+       /**
+       * Debug
+       */
+       protected function dbg($msg) {
+               if ($this->debug) echo '* ',$msg, '<br />', "\n";
+       }
+       
+       /**
+       * Run any post-process modifications to article content as necessary.
+       *
+       * @param DOMElement
+       * @return void
+       */
+       public function postProcessContent($articleContent) {
+               if ($this->convertLinksToFootnotes && !preg_match('/wikipedia\.org/', @$this->url)) { 
+                       $this->addFootnotes($articleContent);
+               }
+       }
+       
+       /**
+       * Get the article title as an H1.
+       *
+       * @return DOMElement
+       */
+       protected function getArticleTitle() {
+               $curTitle = '';
+               $origTitle = '';
+
+               try {
+                       $curTitle = $origTitle = $this->getInnerText($this->dom->getElementsByTagName('title')->item(0));
+               } catch(Exception $e) {}
+               
+               if (preg_match('/ [\|\-] /', $curTitle))
+               {
+                       $curTitle = preg_replace('/(.*)[\|\-] .*/i', '$1', $origTitle);
+                       
+                       if (count(explode(' ', $curTitle)) < 3) {
+                               $curTitle = preg_replace('/[^\|\-]*[\|\-](.*)/i', '$1', $origTitle);
+                       }
+               }
+               else if (strpos($curTitle, ': ') !== false)
+               {
+                       $curTitle = preg_replace('/.*:(.*)/i', '$1', $origTitle);
+
+                       if (count(explode(' ', $curTitle)) < 3) {
+                               $curTitle = preg_replace('/[^:]*[:](.*)/i','$1', $origTitle);
+                       }
+               }
+               else if(strlen($curTitle) > 150 || strlen($curTitle) < 15)
+               {
+                       $hOnes = $this->dom->getElementsByTagName('h1');
+                       if($hOnes->length == 1)
+                       {
+                               $curTitle = $this->getInnerText($hOnes->item(0));
+                       }
+               }
+
+               $curTitle = trim($curTitle);
+
+               if (count(explode(' ', $curTitle)) <= 4) {
+                       $curTitle = $origTitle;
+               }
+               
+               $articleTitle = $this->dom->createElement('h1');
+               $articleTitle->innerHTML = $curTitle;
+               
+               return $articleTitle;
+       }
+       
+       /**
+       * Prepare the HTML document for readability to scrape it.
+       * This includes things like stripping javascript, CSS, and handling terrible markup.
+       * 
+       * @return void
+       **/
+       protected function prepDocument() {
+               /**
+               * In some cases a body element can't be found (if the HTML is totally hosed for example)
+               * so we create a new body node and append it to the document.
+               */
+               if ($this->body == null)
+               {
+                       $this->body = $this->dom->createElement('body');
+                       $this->dom->documentElement->appendChild($this->body);
+               }
+               $this->body->setAttribute('id', 'readabilityBody');
+
+               /* Remove all style tags in head */
+               $styleTags = $this->dom->getElementsByTagName('style');
+               for ($i = $styleTags->length-1; $i >= 0; $i--)
+               {
+                       $styleTags->item($i)->parentNode->removeChild($styleTags->item($i));
+               }
+
+               /* Turn all double br's into p's */
+               /* Note, this is pretty costly as far as processing goes. Maybe optimize later. */
+               //document.body.innerHTML = document.body.innerHTML.replace(readability.regexps.replaceBrs, '</p><p>').replace(readability.regexps.replaceFonts, '<$1span>');
+               // We do this in the constructor for PHP as that's when we have raw HTML - before parsing it into a DOM tree.
+               // Manipulating innerHTML as it's done in JS is not possible in PHP.
+       }
+
+       /**
+       * For easier reading, convert this document to have footnotes at the bottom rather than inline links.
+       * @see http://www.roughtype.com/archives/2010/05/experiments_in.php
+       *
+       * @return void
+       **/
+       public function addFootnotes($articleContent) {
+               $footnotesWrapper = $this->dom->createElement('div');
+               $footnotesWrapper->setAttribute('id', 'readability-footnotes');
+               $footnotesWrapper->innerHTML = '<h3>References</h3>';
+               
+               $articleFootnotes = $this->dom->createElement('ol');
+               $articleFootnotes->setAttribute('id', 'readability-footnotes-list');
+               $footnotesWrapper->appendChild($articleFootnotes);
+               
+               $articleLinks = $articleContent->getElementsByTagName('a');
+               
+               $linkCount = 0;
+               for ($i = 0; $i < $articleLinks->length; $i++)
+               {
+                       $articleLink  = $articleLinks->item($i);
+                       $footnoteLink = $articleLink->cloneNode(true);
+                       $refLink      = $this->dom->createElement('a');
+                       $footnote     = $this->dom->createElement('li');
+                       $linkDomain   = @parse_url($footnoteLink->getAttribute('href'), PHP_URL_HOST);
+                       if (!$linkDomain && isset($this->url)) $linkDomain = @parse_url($this->url, PHP_URL_HOST);
+                       //linkDomain   = footnoteLink.host ? footnoteLink.host : document.location.host,
+                       $linkText     = $this->getInnerText($articleLink);
+                       
+                       if ((strpos($articleLink->getAttribute('class'), 'readability-DoNotFootnote') !== false) || preg_match($this->regexps['skipFootnoteLink'], $linkText)) {
+                               continue;
+                       }
+                       
+                       $linkCount++;
+
+                       /** Add a superscript reference after the article link */
+                       $refLink->setAttribute('href', '#readabilityFootnoteLink-' . $linkCount);
+                       $refLink->innerHTML = '<small><sup>[' . $linkCount . ']</sup></small>';
+                       $refLink->setAttribute('class', 'readability-DoNotFootnote');
+                       $refLink->setAttribute('style', 'color: inherit;');
+                       
+                       //TODO: does this work or should we use DOMNode.isSameNode()?
+                       if ($articleLink->parentNode->lastChild == $articleLink) {
+                               $articleLink->parentNode->appendChild($refLink);
+                       } else {
+                               $articleLink->parentNode->insertBefore($refLink, $articleLink->nextSibling);
+                       }
+
+                       $articleLink->setAttribute('style', 'color: inherit; text-decoration: none;');
+                       $articleLink->setAttribute('name', 'readabilityLink-' . $linkCount);
+
+                       $footnote->innerHTML = '<small><sup><a href="#readabilityLink-' . $linkCount . '" title="Jump to Link in Article">^</a></sup></small> ';
+
+                       $footnoteLink->innerHTML = ($footnoteLink->getAttribute('title') != '' ? $footnoteLink->getAttribute('title') : $linkText);
+                       $footnoteLink->setAttribute('name', 'readabilityFootnoteLink-' . $linkCount);
+                       
+                       $footnote->appendChild($footnoteLink);
+                       if ($linkDomain) $footnote->innerHTML = $footnote->innerHTML . '<small> (' . $linkDomain . ')</small>';
+                       
+                       $articleFootnotes->appendChild($footnote);
+               }
+
+               if ($linkCount > 0) {
+                       $articleContent->appendChild($footnotesWrapper);           
+               }
+       }
+
+       /**
+       * Reverts P elements with class 'readability-styled'
+       * to text nodes - which is what they were before.
+       *
+       * @param DOMElement
+       * @return void
+       */
+       function revertReadabilityStyledElements($articleContent) {
+               $xpath = new DOMXPath($articleContent->ownerDocument);
+               $elems = $xpath->query('.//p[@class="readability-styled"]', $articleContent);
+               //$elems = $articleContent->getElementsByTagName('p');
+               for ($i = $elems->length-1; $i >= 0; $i--) {
+                       $e = $elems->item($i);
+                       $e->parentNode->replaceChild($articleContent->ownerDocument->createTextNode($e->textContent), $e);
+                       //if ($e->hasAttribute('class') && $e->getAttribute('class') == 'readability-styled') {
+                       //      $e->parentNode->replaceChild($this->dom->createTextNode($e->textContent), $e);
+                       //}
+               }
+       }
+       
+       /**
+       * Prepare the article node for display. Clean out any inline styles,
+       * iframes, forms, strip extraneous <p> tags, etc.
+       *
+       * @param DOMElement
+       * @return void
+       */
+       function prepArticle($articleContent) {
+               $this->cleanStyles($articleContent);
+               $this->killBreaks($articleContent);
+               if ($this->revertForcedParagraphElements) {
+                       $this->revertReadabilityStyledElements($articleContent);
+               }
+
+               /* Clean out junk from the article content */
+               $this->cleanConditionally($articleContent, 'form');
+               $this->clean($articleContent, 'object');
+               $this->clean($articleContent, 'h1');
+
+               /**
+               * If there is only one h2, they are probably using it
+               * as a header and not a subheader, so remove it since we already have a header.
+               ***/
+               if ($articleContent->getElementsByTagName('h2')->length == 1) {
+                       $this->clean($articleContent, 'h2'); 
+               }
+               $this->clean($articleContent, 'iframe');
+
+               $this->cleanHeaders($articleContent);
+
+               /* Do these last as the previous stuff may have removed junk that will affect these */
+               $this->cleanConditionally($articleContent, 'table');
+               $this->cleanConditionally($articleContent, 'ul');
+               $this->cleanConditionally($articleContent, 'div');
+
+               /* Remove extra paragraphs */
+               $articleParagraphs = $articleContent->getElementsByTagName('p');
+               for ($i = $articleParagraphs->length-1; $i >= 0; $i--)
+               {
+                       $imgCount    = $articleParagraphs->item($i)->getElementsByTagName('img')->length;
+                       $embedCount  = $articleParagraphs->item($i)->getElementsByTagName('embed')->length;
+                       $objectCount = $articleParagraphs->item($i)->getElementsByTagName('object')->length;
+                       
+                       if ($imgCount === 0 && $embedCount === 0 && $objectCount === 0 && $this->getInnerText($articleParagraphs->item($i), false) == '')
+                       {
+                               $articleParagraphs->item($i)->parentNode->removeChild($articleParagraphs->item($i));
+                       }
+               }
+
+               try {
+                       $articleContent->innerHTML = preg_replace('/<br[^>]*>\s*<p/i', '<p', $articleContent->innerHTML);
+                       //articleContent.innerHTML = articleContent.innerHTML.replace(/<br[^>]*>\s*<p/gi, '<p');      
+               }
+               catch (Exception $e) {
+                       $this->dbg("Cleaning innerHTML of breaks failed. This is an IE strict-block-elements bug. Ignoring.: " . $e);
+               }
+       }
+       
+       /**
+       * Initialize a node with the readability object. Also checks the
+       * className/id for special names to add to its score.
+       *
+       * @param Element
+       * @return void
+       **/
+       protected function initializeNode($node) {
+               $readability = $this->dom->createAttribute('readability');
+               $readability->value = 0; // this is our contentScore
+               $node->setAttributeNode($readability);                   
+
+               switch (strtoupper($node->tagName)) { // unsure if strtoupper is needed, but using it just in case
+                       case 'DIV':
+                               $readability->value += 5;
+                               break;
+
+                       case 'PRE':
+                       case 'TD':
+                       case 'BLOCKQUOTE':
+                               $readability->value += 3;
+                               break;
+                               
+                       case 'ADDRESS':
+                       case 'OL':
+                       case 'UL':
+                       case 'DL':
+                       case 'DD':
+                       case 'DT':
+                       case 'LI':
+                       case 'FORM':
+                               $readability->value -= 3;
+                               break;
+
+                       case 'H1':
+                       case 'H2':
+                       case 'H3':
+                       case 'H4':
+                       case 'H5':
+                       case 'H6':
+                       case 'TH':
+                               $readability->value -= 5;
+                               break;
+               }
+               $readability->value += $this->getClassWeight($node);
+       }
+       
+       /***
+       * grabArticle - Using a variety of metrics (content score, classname, element types), find the content that is
+       *               most likely to be the stuff a user wants to read. Then return it wrapped up in a div.
+       *
+       * @return DOMElement
+       **/
+       protected function grabArticle($page=null) {
+               $stripUnlikelyCandidates = $this->flagIsActive(self::FLAG_STRIP_UNLIKELYS);
+               if (!$page) $page = $this->dom;
+               $allElements = $page->getElementsByTagName('*');
+               /**
+               * First, node prepping. Trash nodes that look cruddy (like ones with the class name "comment", etc), and turn divs
+               * into P tags where they have been used inappropriately (as in, where they contain no other block level elements.)
+               *
+               * Note: Assignment from index for performance. See http://www.peachpit.com/articles/article.aspx?p=31567&seqNum=5
+               * TODO: Shouldn't this be a reverse traversal?
+               **/
+               $node = null;
+               $nodesToScore = array();
+               for ($nodeIndex = 0; ($node = $allElements->item($nodeIndex)); $nodeIndex++) {
+               //for ($nodeIndex=$targetList->length-1; $nodeIndex >= 0; $nodeIndex--) {
+                       //$node = $targetList->item($nodeIndex);
+                       $tagName = strtoupper($node->tagName);
+                       /* Remove unlikely candidates */
+                       if ($stripUnlikelyCandidates) {
+                               $unlikelyMatchString = $node->getAttribute('class') . $node->getAttribute('id');
+                               if (
+                                       preg_match($this->regexps['unlikelyCandidates'], $unlikelyMatchString) &&
+                                       !preg_match($this->regexps['okMaybeItsACandidate'], $unlikelyMatchString) &&
+                                       $tagName != 'BODY'
+                               )
+                               {
+                                       $this->dbg('Removing unlikely candidate - ' . $unlikelyMatchString);
+                                       //$nodesToRemove[] = $node;
+                                       $node->parentNode->removeChild($node);
+                                       $nodeIndex--;
+                                       continue;
+                               }               
+                       }
+
+                       if ($tagName == 'P' || $tagName == 'TD' || $tagName == 'PRE') {
+                               $nodesToScore[] = $node;
+                       }
+
+                       /* Turn all divs that don't have children block level elements into p's */
+                       if ($tagName == 'DIV') {
+                               if (!preg_match($this->regexps['divToPElements'], $node->innerHTML)) {
+                                       //$this->dbg('Altering div to p');
+                                       $newNode = $this->dom->createElement('p');
+                                       try {
+                                               $newNode->innerHTML = $node->innerHTML;
+                                               //$nodesToReplace[] = array('new'=>$newNode, 'old'=>$node);
+                                               $node->parentNode->replaceChild($newNode, $node);
+                                               $nodeIndex--;
+                                               $nodesToScore[] = $node; // or $newNode?
+                                       }
+                                       catch(Exception $e) {
+                                               $this->dbg('Could not alter div to p, reverting back to div.: ' . $e);
+                                       }
+                               }
+                               else
+                               {
+                                       // EXPERIMENTAL
+                                       // TODO: change these p elements back to text nodes after processing
+                                       for ($i = 0, $il = $node->childNodes->length; $i < $il; $i++) {
+                                               $childNode = $node->childNodes->item($i);
+                                               if ($childNode->nodeType == 3) { // XML_TEXT_NODE
+                                                       //$this->dbg('replacing text node with a p tag with the same content.');
+                                                       $p = $this->dom->createElement('p');
+                                                       $p->innerHTML = $childNode->nodeValue;
+                                                       $p->setAttribute('style', 'display: inline;');
+                                                       $p->setAttribute('class', 'readability-styled');
+                                                       $childNode->parentNode->replaceChild($p, $childNode);
+                                               }
+                                       }
+                               }
+                       }
+               }
+               
+               /**
+               * Loop through all paragraphs, and assign a score to them based on how content-y they look.
+               * Then add their score to their parent node.
+               *
+               * A score is determined by things like number of commas, class names, etc. Maybe eventually link density.
+               **/
+               $candidates = array();
+               for ($pt=0; $pt < count($nodesToScore); $pt++) {
+                       $parentNode      = $nodesToScore[$pt]->parentNode;
+                       // $grandParentNode = $parentNode ? $parentNode->parentNode : null;
+                       $grandParentNode = !$parentNode ? null : (($parentNode->parentNode instanceof DOMElement) ? $parentNode->parentNode : null);
+                       $innerText       = $this->getInnerText($nodesToScore[$pt]);
+
+                       if (!$parentNode || !isset($parentNode->tagName)) {
+                               continue;
+                       }
+
+                       /* If this paragraph is less than 25 characters, don't even count it. */
+                       if(strlen($innerText) < 25) {
+                               continue;
+                       }
+
+                       /* Initialize readability data for the parent. */
+                       if (!$parentNode->hasAttribute('readability')) 
+                       {
+                               $this->initializeNode($parentNode);
+                               $candidates[] = $parentNode;
+                       }
+
+                       /* Initialize readability data for the grandparent. */
+                       if ($grandParentNode && !$grandParentNode->hasAttribute('readability') && isset($grandParentNode->tagName))
+                       {
+                               $this->initializeNode($grandParentNode);
+                               $candidates[] = $grandParentNode;
+                       }
+
+                       $contentScore = 0;
+
+                       /* Add a point for the paragraph itself as a base. */
+                       $contentScore++;
+
+                       /* Add points for any commas within this paragraph */
+                       $contentScore += count(explode(',', $innerText));
+                       
+                       /* For every 100 characters in this paragraph, add another point. Up to 3 points. */
+                       $contentScore += min(floor(strlen($innerText) / 100), 3);
+                       
+                       /* Add the score to the parent. The grandparent gets half. */
+                       $parentNode->getAttributeNode('readability')->value += $contentScore;
+
+                       if ($grandParentNode) {
+                               $grandParentNode->getAttributeNode('readability')->value += $contentScore/2;             
+                       }
+               }
+
+               /**
+               * After we've calculated scores, loop through all of the possible candidate nodes we found
+               * and find the one with the highest score.
+               **/
+               $topCandidate = null;
+               for ($c=0, $cl=count($candidates); $c < $cl; $c++)
+               {
+                       /**
+                       * Scale the final candidates score based on link density. Good content should have a
+                       * relatively small link density (5% or less) and be mostly unaffected by this operation.
+                       **/
+                       $readability = $candidates[$c]->getAttributeNode('readability');
+                       $readability->value = $readability->value * (1-$this->getLinkDensity($candidates[$c]));
+
+                       $this->dbg('Candidate: ' . $candidates[$c]->tagName . ' (' . $candidates[$c]->getAttribute('class') . ':' . $candidates[$c]->getAttribute('id') . ') with score ' . $readability->value);
+
+                       if (!$topCandidate || $readability->value > (int)$topCandidate->getAttribute('readability')) {
+                               $topCandidate = $candidates[$c];
+                       }
+               }
+
+               /**
+               * If we still have no top candidate, just use the body as a last resort.
+               * We also have to copy the body node so it is something we can modify.
+               **/
+               if ($topCandidate === null || strtoupper($topCandidate->tagName) == 'BODY')
+               {
+                       $topCandidate = $this->dom->createElement('div');
+                       if ($page instanceof DOMDocument) {
+                               if (!isset($page->documentElement)) {
+                                       // we don't have a body either? what a mess! :)
+                               } else {
+                                       $topCandidate->innerHTML = $page->documentElement->innerHTML;
+                                       $page->documentElement->innerHTML = '';
+                                       $page->documentElement->appendChild($topCandidate);
+                               }
+                       } else {
+                               $topCandidate->innerHTML = $page->innerHTML;
+                               $page->innerHTML = '';
+                               $page->appendChild($topCandidate);
+                       }
+                       $this->initializeNode($topCandidate);
+               }
+
+               /**
+               * Now that we have the top candidate, look through its siblings for content that might also be related.
+               * Things like preambles, content split by ads that we removed, etc.
+               **/
+               $articleContent        = $this->dom->createElement('div');
+               $articleContent->setAttribute('id', 'readability-content');
+               $siblingScoreThreshold = max(10, ((int)$topCandidate->getAttribute('readability')) * 0.2);
+               $siblingNodes          = $topCandidate->parentNode->childNodes;
+               if (!isset($siblingNodes)) {
+                       $siblingNodes = new stdClass;
+                       $siblingNodes->length = 0;
+               }
+
+               for ($s=0, $sl=$siblingNodes->length; $s < $sl; $s++)
+               {
+                       $siblingNode = $siblingNodes->item($s);
+                       $append      = false;
+
+                       $this->dbg('Looking at sibling node: ' . $siblingNode->nodeName . (($siblingNode->nodeType === XML_ELEMENT_NODE && $siblingNode->hasAttribute('readability')) ? (' with score ' . $siblingNode->getAttribute('readability')) : ''));
+
+                       //dbg('Sibling has score ' . ($siblingNode->readability ? siblingNode.readability.contentScore : 'Unknown'));
+
+                       if ($siblingNode === $topCandidate)
+                       // or if ($siblingNode->isSameNode($topCandidate))
+                       {
+                               $append = true;
+                       }
+
+                       $contentBonus = 0;
+                       /* Give a bonus if sibling nodes and top candidates have the example same classname */
+                       if ($siblingNode->nodeType === XML_ELEMENT_NODE && $siblingNode->getAttribute('class') == $topCandidate->getAttribute('class') && $topCandidate->getAttribute('class') != '') {
+                               $contentBonus += ((int)$topCandidate->getAttribute('readability')) * 0.2;
+                       }
+
+                       if ($siblingNode->nodeType === XML_ELEMENT_NODE && $siblingNode->hasAttribute('readability') && (((int)$siblingNode->getAttribute('readability')) + $contentBonus) >= $siblingScoreThreshold)
+                       {
+                               $append = true;
+                       }
+                       
+                       if (strtoupper($siblingNode->nodeName) == 'P') {
+                               $linkDensity = $this->getLinkDensity($siblingNode);
+                               $nodeContent = $this->getInnerText($siblingNode);
+                               $nodeLength  = strlen($nodeContent);
+                               
+                               if ($nodeLength > 80 && $linkDensity < 0.25)
+                               {
+                                       $append = true;
+                               }
+                               else if ($nodeLength < 80 && $linkDensity === 0 && preg_match('/\.( |$)/', $nodeContent))
+                               {
+                                       $append = true;
+                               }
+                       }
+
+                       /* Look for a special classname */
+                       if ($siblingNode->nodeType === XML_ELEMENT_NODE && $siblingNode->hasAttribute('class') && $siblingNode->getAttribute('class') != '')
+                       {
+                               if (preg_match($this->regexps['okMaybeItsACandidate'], $siblingNode->getAttribute('class'))) {
+                                       $append = true;
+                               }
+                       }
+
+                       /* Look for a special classname */
+                       if ($siblingNode->nodeType === XML_ELEMENT_NODE && $siblingNode->hasAttribute('id') && $siblingNode->getAttribute('id') != '')
+                       {
+                               if (preg_match($this->regexps['okMaybeItsACandidate'], $siblingNode->getAttribute('id'))) {
+                                       $append = true;
+                               }
+                       }
+
+
+                       if ($append)
+                       {
+                               $this->dbg('Appending node: ' . $siblingNode->nodeName);
+
+                               $nodeToAppend = null;
+                               $sibNodeName = strtoupper($siblingNode->nodeName);
+                               if ($sibNodeName != 'DIV' && $sibNodeName != 'P') {
+                                       /* We have a node that isn't a common block level element, like a form or td tag. Turn it into a div so it doesn't get filtered out later by accident. */
+                                       
+                                       $this->dbg('Altering siblingNode of ' . $sibNodeName . ' to div.');
+                                       $nodeToAppend = $this->dom->createElement('div');
+                                       try {
+                                               $nodeToAppend->setAttribute('id', $siblingNode->getAttribute('id'));
+                                               $nodeToAppend->innerHTML = $siblingNode->innerHTML;
+                                       }
+                                       catch(Exception $e)
+                                       {
+                                               $this->dbg('Could not alter siblingNode to div, reverting back to original.');
+                                               $nodeToAppend = $siblingNode;
+                                               $s--;
+                                               $sl--;
+                                       }
+                               } else {
+                                       $nodeToAppend = $siblingNode;
+                                       $s--;
+                                       $sl--;
+                               }
+                               
+                               /* To ensure a node does not interfere with readability styles, remove its classnames */
+                               $nodeToAppend->removeAttribute('class');
+
+                               /* Append sibling and subtract from our list because it removes the node when you append to another node */
+                               $articleContent->appendChild($nodeToAppend);
+                       }
+               }
+
+               /**
+               * So we have all of the content that we need. Now we clean it up for presentation.
+               **/
+               $this->prepArticle($articleContent);
+
+               /**
+               * Now that we've gone through the full algorithm, check to see if we got any meaningful content.
+               * If we didn't, we may need to re-run grabArticle with different flags set. This gives us a higher
+               * likelihood of finding the content, and the sieve approach gives us a higher likelihood of
+               * finding the -right- content.
+               **/
+               if (strlen($this->getInnerText($articleContent, false)) < 250)
+               {
+                       // TODO: find out why element disappears sometimes, e.g. for this URL http://www.businessinsider.com/6-hedge-fund-etfs-for-average-investors-2011-7
+                       // in the meantime, we check and create an empty element if it's not there.
+                       if (!isset($this->body->childNodes)) $this->body = $this->dom->createElement('body');
+                       $this->body->innerHTML = $this->bodyCache;
+                       
+                       if ($this->flagIsActive(self::FLAG_STRIP_UNLIKELYS)) {
+                               $this->removeFlag(self::FLAG_STRIP_UNLIKELYS);
+                               return $this->grabArticle($this->body);
+                       }
+                       else if ($this->flagIsActive(self::FLAG_WEIGHT_CLASSES)) {
+                               $this->removeFlag(self::FLAG_WEIGHT_CLASSES);
+                               return $this->grabArticle($this->body);              
+                       }
+                       else if ($this->flagIsActive(self::FLAG_CLEAN_CONDITIONALLY)) {
+                               $this->removeFlag(self::FLAG_CLEAN_CONDITIONALLY);
+                               return $this->grabArticle($this->body);
+                       }
+                       else {
+                               return false;
+                       }
+               }
+               return $articleContent;
+       }
+       
+       /**
+       * Remove script tags from document
+       *
+       * @param DOMElement
+       * @return void
+       */
+       public function removeScripts($doc) {
+               $scripts = $doc->getElementsByTagName('script');
+               for($i = $scripts->length-1; $i >= 0; $i--)
+               {
+                       $scripts->item($i)->parentNode->removeChild($scripts->item($i));
+               }
+       }
+       
+       /**
+       * Get the inner text of a node.
+       * This also strips out any excess whitespace to be found.
+       *
+       * @param DOMElement $
+       * @param boolean $normalizeSpaces (default: true)
+       * @return string
+       **/
+       public function getInnerText($e, $normalizeSpaces=true) {
+               $textContent = '';
+
+               if (!isset($e->textContent) || $e->textContent == '') {
+                       return '';
+               }
+
+               $textContent = trim($e->textContent);
+
+               if ($normalizeSpaces) {
+                       return preg_replace($this->regexps['normalize'], ' ', $textContent);
+               } else {
+                       return $textContent;
+               }
+       }
+
+       /**
+       * Get the number of times a string $s appears in the node $e.
+       *
+       * @param DOMElement $e
+       * @param string - what to count. Default is ","
+       * @return number (integer)
+       **/
+       public function getCharCount($e, $s=',') {
+               return substr_count($this->getInnerText($e), $s);
+       }
+
+       /**
+       * Remove the style attribute on every $e and under.
+       *
+       * @param DOMElement $e
+       * @return void
+       */
+       public function cleanStyles($e) {
+               if (!is_object($e)) return;
+               $elems = $e->getElementsByTagName('*');
+               foreach ($elems as $elem) {
+                       $elem->removeAttribute('style');
+               }
+       }
+       
+       /**
+       * Get the density of links as a percentage of the content
+       * This is the amount of text that is inside a link divided by the total text in the node.
+       * 
+       * @param DOMElement $e
+       * @return number (float)
+       */
+       public function getLinkDensity($e) {
+               $links      = $e->getElementsByTagName('a');
+               $textLength = strlen($this->getInnerText($e));
+               $linkLength = 0;
+               for ($i=0, $il=$links->length; $i < $il; $i++)
+               {
+                       $linkLength += strlen($this->getInnerText($links->item($i)));
+               }
+               if ($textLength > 0) {
+                       return $linkLength / $textLength;
+               } else {
+                       return 0;
+               }
+       }
+       
+       /**
+       * Get an elements class/id weight. Uses regular expressions to tell if this 
+       * element looks good or bad.
+       *
+       * @param DOMElement $e
+       * @return number (Integer)
+       */
+       public function getClassWeight($e) {
+               if(!$this->flagIsActive(self::FLAG_WEIGHT_CLASSES)) {
+                       return 0;
+               }
+
+               $weight = 0;
+
+               /* Look for a special classname */
+               if ($e->hasAttribute('class') && $e->getAttribute('class') != '')
+               {
+                       if (preg_match($this->regexps['negative'], $e->getAttribute('class'))) {
+                               $weight -= 25;
+                       }
+                       if (preg_match($this->regexps['positive'], $e->getAttribute('class'))) {
+                               $weight += 25;
+                       }
+               }
+
+               /* Look for a special ID */
+               if ($e->hasAttribute('id') && $e->getAttribute('id') != '')
+               {
+                       if (preg_match($this->regexps['negative'], $e->getAttribute('id'))) {
+                               $weight -= 25;
+                       }
+                       if (preg_match($this->regexps['positive'], $e->getAttribute('id'))) {
+                               $weight += 25;
+                       }
+               }
+               return $weight;
+       }
+
+       /**
+       * Remove extraneous break tags from a node.
+       *
+       * @param DOMElement $node
+       * @return void
+       */
+       public function killBreaks($node) {
+               $html = $node->innerHTML;
+               $html = preg_replace($this->regexps['killBreaks'], '<br />', $html);
+               $node->innerHTML = $html;
+       }
+
+       /**
+       * Clean a node of all elements of type "tag".
+       * (Unless it's a youtube/vimeo video. People love movies.)
+       *
+       * @param DOMElement $e
+       * @param string $tag
+       * @return void
+       */
+       public function clean($e, $tag) {
+               $targetList = $e->getElementsByTagName($tag);
+               $isEmbed = ($tag == 'object' || $tag == 'embed');
+               
+               for ($y=$targetList->length-1; $y >= 0; $y--) {
+                       /* Allow youtube and vimeo videos through as people usually want to see those. */
+                       if ($isEmbed) {
+                               $attributeValues = '';
+                               for ($i=0, $il=$targetList->item($y)->attributes->length; $i < $il; $i++) {
+                                       $attributeValues .= $targetList->item($y)->attributes->item($i)->value . '|'; // DOMAttr? (TODO: test)
+                               }
+                               
+                               /* First, check the elements attributes to see if any of them contain youtube or vimeo */
+                               if (preg_match($this->regexps['video'], $attributeValues)) {
+                                       continue;
+                               }
+
+                               /* Then check the elements inside this element for the same. */
+                               if (preg_match($this->regexps['video'], $targetList->item($y)->innerHTML)) {
+                                       continue;
+                               }
+                       }
+                       $targetList->item($y)->parentNode->removeChild($targetList->item($y));
+               }
+       }
+       
+       /**
+       * Clean an element of all tags of type "tag" if they look fishy.
+       * "Fishy" is an algorithm based on content length, classnames, 
+       * link density, number of images & embeds, etc.
+       *
+       * @param DOMElement $e
+       * @param string $tag
+       * @return void
+       */
+       public function cleanConditionally($e, $tag) {
+               if (!$this->flagIsActive(self::FLAG_CLEAN_CONDITIONALLY)) {
+                       return;
+               }
+
+               $tagsList = $e->getElementsByTagName($tag);
+               $curTagsLength = $tagsList->length;
+
+               /**
+               * Gather counts for other typical elements embedded within.
+               * Traverse backwards so we can remove nodes at the same time without effecting the traversal.
+               *
+               * TODO: Consider taking into account original contentScore here.
+               */
+               for ($i=$curTagsLength-1; $i >= 0; $i--) {
+                       $weight = $this->getClassWeight($tagsList->item($i));
+                       $contentScore = ($tagsList->item($i)->hasAttribute('readability')) ? (int)$tagsList->item($i)->getAttribute('readability') : 0;
+                       
+                       $this->dbg('Cleaning Conditionally ' . $tagsList->item($i)->tagName . ' (' . $tagsList->item($i)->getAttribute('class') . ':' . $tagsList->item($i)->getAttribute('id') . ')' . (($tagsList->item($i)->hasAttribute('readability')) ? (' with score ' . $tagsList->item($i)->getAttribute('readability')) : ''));
+
+                       if ($weight + $contentScore < 0) {
+                               $tagsList->item($i)->parentNode->removeChild($tagsList->item($i));
+                       }
+                       else if ( $this->getCharCount($tagsList->item($i), ',') < 10) {
+                               /**
+                               * If there are not very many commas, and the number of
+                               * non-paragraph elements is more than paragraphs or other ominous signs, remove the element.
+                               **/
+                               $p      = $tagsList->item($i)->getElementsByTagName('p')->length;
+                               $img    = $tagsList->item($i)->getElementsByTagName('img')->length;
+                               $li     = $tagsList->item($i)->getElementsByTagName('li')->length-100;
+                               $input  = $tagsList->item($i)->getElementsByTagName('input')->length;
+
+                               $embedCount = 0;
+                               $embeds = $tagsList->item($i)->getElementsByTagName('embed');
+                               for ($ei=0, $il=$embeds->length; $ei < $il; $ei++) {
+                                       if (preg_match($this->regexps['video'], $embeds->item($ei)->getAttribute('src'))) {
+                                       $embedCount++; 
+                                       }
+                               }
+
+                               $linkDensity   = $this->getLinkDensity($tagsList->item($i));
+                               $contentLength = strlen($this->getInnerText($tagsList->item($i)));
+                               $toRemove      = false;
+
+                               if ( $img > $p ) {
+                                       $toRemove = true;
+                               } else if ($li > $p && $tag != 'ul' && $tag != 'ol') {
+                                       $toRemove = true;
+                               } else if ( $input > floor($p/3) ) {
+                                       $toRemove = true; 
+                               } else if ($contentLength < 25 && ($img === 0 || $img > 2) ) {
+                                       $toRemove = true;
+                               } else if($weight < 25 && $linkDensity > 0.2) {
+                                       $toRemove = true;
+                               } else if($weight >= 25 && $linkDensity > 0.5) {
+                                       $toRemove = true;
+                               } else if(($embedCount == 1 && $contentLength < 75) || $embedCount > 1) {
+                                       $toRemove = true;
+                               }
+
+                               if ($toRemove) {
+                                       $tagsList->item($i)->parentNode->removeChild($tagsList->item($i));
+                               }
+                       }
+               }
+       }
+
+       /**
+       * Clean out spurious headers from an Element. Checks things like classnames and link density.
+       *
+       * @param DOMElement $e
+       * @return void
+       */
+       public function cleanHeaders($e) {
+               for ($headerIndex = 1; $headerIndex < 3; $headerIndex++) {
+                       $headers = $e->getElementsByTagName('h' . $headerIndex);
+                       for ($i=$headers->length-1; $i >=0; $i--) {
+                               if ($this->getClassWeight($headers->item($i)) < 0 || $this->getLinkDensity($headers->item($i)) > 0.33) {
+                                       $headers->item($i)->parentNode->removeChild($headers->item($i));
+                               }
+                       }
+               }
+       }
+
+       public function flagIsActive($flag) {
+               return ($this->flags & $flag) > 0;
+       }
+       
+       public function addFlag($flag) {
+               $this->flags = $this->flags | $flag;
+       }
+       
+       public function removeFlag($flag) {
+               $this->flags = $this->flags & ~$flag;
+       }
+}
+?>
\ No newline at end of file
diff --git a/inc/index.html b/inc/index.html
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/inc/rain.tpl.class.php b/inc/rain.tpl.class.php
new file mode 100755 (executable)
index 0000000..ea83b2c
--- /dev/null
@@ -0,0 +1,1043 @@
+<?php
+
+/**
+ *  RainTPL
+ *  -------
+ *  Realized by Federico Ulfo & maintained by the Rain Team
+ *  Distributed under GNU/LGPL 3 License
+ *
+ *  @version 2.7.2
+ */
+
+
+class RainTPL{
+
+       // -------------------------
+       //      CONFIGURATION
+       // -------------------------
+
+               /**
+                * Template directory
+                *
+                * @var string
+                */
+               static $tpl_dir = "tpl/";
+
+
+               /**
+                * Cache directory. Is the directory where RainTPL will compile the template and save the cache
+                *
+                * @var string
+                */
+               static $cache_dir = "tmp/";
+
+
+               /**
+                * Template base URL. RainTPL will add this URL to the relative paths of element selected in $path_replace_list.
+                *
+                * @var string
+                */
+               static $base_url = null;
+
+
+               /**
+                * Template extension.
+                *
+                * @var string
+                */
+               static $tpl_ext = "html";
+
+
+               /**
+                * Path replace is a cool features that replace all relative paths of images (<img src="...">), stylesheet (<link href="...">), script (<script src="...">) and link (<a href="...">)
+                * Set true to enable the path replace.
+                *
+                * @var unknown_type
+                */
+               static $path_replace = true;
+
+
+               /**
+                * You can set what the path_replace method will replace.
+                * Avaible options: a, img, link, script, input
+                *
+                * @var array
+                */
+               static $path_replace_list = array( 'a', 'img', 'link', 'script', 'input' );
+
+
+               /**
+                * You can define in the black list what string are disabled into the template tags
+                *
+                * @var unknown_type
+                */
+               static $black_list = array( '\$this', 'raintpl::', 'self::', '_SESSION', '_SERVER', '_ENV',  'eval', 'exec', 'unlink', 'rmdir' );
+
+
+               /**
+                * Check template.
+                * true: checks template update time, if changed it compile them
+                * false: loads the compiled template. Set false if server doesn't have write permission for cache_directory.
+                *
+                */
+               static $check_template_update = true;
+                
+
+               /**
+                * PHP tags <? ?> 
+                * True: php tags are enabled into the template
+                * False: php tags are disabled into the template and rendered as html
+                *
+                * @var bool
+                */
+               static $php_enabled = false;
+
+               
+               /**
+                * Debug mode flag.
+                * True: debug mode is used, syntax errors are displayed directly in template. Execution of script is not terminated.
+                * False: exception is thrown on found error.
+                *
+                * @var bool
+                */
+               static $debug = false;
+
+       // -------------------------
+
+
+       // -------------------------
+       //      RAINTPL VARIABLES
+       // -------------------------
+
+               /**
+                * Is the array where RainTPL keep the variables assigned
+                *
+                * @var array
+                */
+               public $var = array();
+
+               protected $tpl = array(),               // variables to keep the template directories and info
+                                 $cache = false,               // static cache enabled / disabled
+                  $cache_id = null;       // identify only one cache
+
+                protected static $config_name_sum = array();   // takes all the config to create the md5 of the file
+
+       // -------------------------
+
+
+
+       const CACHE_EXPIRE_TIME = 3600; // default cache expire time = hour
+
+
+
+       /**
+        * Assign variable
+        * eg.  $t->assign('name','mickey');
+        *
+        * @param mixed $variable_name Name of template variable or associative array name/value
+        * @param mixed $value value assigned to this variable. Not set if variable_name is an associative array
+        */
+
+       function assign( $variable, $value = null ){
+               if( is_array( $variable ) )
+                       $this->var += $variable;
+               else
+                       $this->var[ $variable ] = $value;
+       }
+
+
+
+       /**
+        * Draw the template
+        * eg.  $html = $tpl->draw( 'demo', TRUE ); // return template in string
+        * or   $tpl->draw( $tpl_name ); // echo the template
+        *
+        * @param string $tpl_name  template to load
+        * @param boolean $return_string  true=return a string, false=echo the template
+        * @return string
+        */
+
+       function draw( $tpl_name, $return_string = false ){
+
+               try {
+                       // compile the template if necessary and set the template filepath
+                       $this->check_template( $tpl_name );
+               } catch (RainTpl_Exception $e) {
+                       $output = $this->printDebug($e);
+                       die($output);
+               }
+
+               // Cache is off and, return_string is false
+        // Rain just echo the template
+
+        if( !$this->cache && !$return_string ){
+            extract( $this->var );
+            include $this->tpl['compiled_filename'];
+            unset( $this->tpl );
+        }
+
+
+               // cache or return_string are enabled
+        // rain get the output buffer to save the output in the cache or to return it as string
+
+        else{
+
+            //----------------------
+            // get the output buffer
+            //----------------------
+                ob_start();
+                extract( $this->var );
+                include $this->tpl['compiled_filename'];
+                $raintpl_contents = ob_get_clean();
+            //----------------------
+
+
+            // save the output in the cache
+            if( $this->cache )
+                file_put_contents( $this->tpl['cache_filename'], "<?php if(!class_exists('raintpl')){exit;}?>" . $raintpl_contents );
+
+            // free memory
+            unset( $this->tpl );
+
+            // return or print the template
+            if( $return_string ) return $raintpl_contents; else echo $raintpl_contents;
+
+        }
+
+       }
+
+
+
+       /**
+        * If exists a valid cache for this template it returns the cache
+        *
+        * @param string $tpl_name Name of template (set the same of draw)
+        * @param int $expiration_time Set after how many seconds the cache expire and must be regenerated
+        * @return string it return the HTML or null if the cache must be recreated
+        */
+
+       function cache( $tpl_name, $expire_time = self::CACHE_EXPIRE_TIME, $cache_id = null ){
+
+        // set the cache_id
+        $this->cache_id = $cache_id;
+
+               if( !$this->check_template( $tpl_name ) && file_exists( $this->tpl['cache_filename'] ) && ( time() - filemtime( $this->tpl['cache_filename'] ) < $expire_time ) )
+                       return substr( file_get_contents( $this->tpl['cache_filename'] ), 43 );
+               else{
+                       //delete the cache of the selected template
+            if (file_exists($this->tpl['cache_filename']))
+            unlink($this->tpl['cache_filename'] );
+                       $this->cache = true;
+               }
+       }
+
+
+
+       /**
+        * Configure the settings of RainTPL
+        *
+        */
+       static function configure( $setting, $value = null ){
+               if( is_array( $setting ) )
+                       foreach( $setting as $key => $value )
+                               self::configure( $key, $value );
+               else if( property_exists( __CLASS__, $setting ) ){
+                       self::$$setting = $value;
+            self::$config_name_sum[ $setting ] = $value; // take trace of all config
+        }
+       }
+
+
+
+       // check if has to compile the template
+       // return true if the template has changed
+       protected function check_template( $tpl_name ){
+
+               if( !isset($this->tpl['checked']) ){
+
+                       $tpl_basename                       = basename( $tpl_name );                                                                                                            // template basename
+                       $tpl_basedir                        = strpos($tpl_name,"/") ? dirname($tpl_name) . '/' : null;                                          // template basedirectory
+                       $tpl_dir                            = self::$tpl_dir . $tpl_basedir;                                                            // template directory
+                       $this->tpl['tpl_filename']          = $tpl_dir . $tpl_basename . '.' . self::$tpl_ext;  // template filename
+                       $temp_compiled_filename             = self::$cache_dir . $tpl_basename . "." . md5( $tpl_dir . serialize(self::$config_name_sum));
+                       $this->tpl['compiled_filename']     = $temp_compiled_filename . '.rtpl.php';    // cache filename
+                       $this->tpl['cache_filename']        = $temp_compiled_filename . '.s_' . $this->cache_id . '.rtpl.php';  // static cache filename
+
+                       // if the template doesn't exsist throw an error
+                       if( self::$check_template_update && !file_exists( $this->tpl['tpl_filename'] ) ){
+                               $e = new RainTpl_NotFoundException( 'Template '. $tpl_basename .' not found!' );
+                               throw $e->setTemplateFile($this->tpl['tpl_filename']);
+                       }
+
+                       // file doesn't exsist, or the template was updated, Rain will compile the template
+                       if( !file_exists( $this->tpl['compiled_filename'] ) || ( self::$check_template_update && filemtime($this->tpl['compiled_filename']) < filemtime( $this->tpl['tpl_filename'] ) ) ){
+                               $this->compileFile( $tpl_basename, $tpl_basedir, $this->tpl['tpl_filename'], self::$cache_dir, $this->tpl['compiled_filename'] );
+                               return true;
+                       }
+                       $this->tpl['checked'] = true;
+               }
+       }
+
+
+       /**
+       * execute stripslaches() on the xml block. Invoqued by preg_replace_callback function below
+       * @access protected
+       */
+       protected function xml_reSubstitution($capture) {
+               return "<?php echo '<?xml ".stripslashes($capture[1])." ?>'; ?>";
+       } 
+
+       /**
+        * Compile and write the compiled template file
+        * @access protected
+        */
+       protected function compileFile( $tpl_basename, $tpl_basedir, $tpl_filename, $cache_dir, $compiled_filename ){
+
+               //read template file
+               $this->tpl['source'] = $template_code = file_get_contents( $tpl_filename );
+
+               //xml substitution
+               $template_code = preg_replace( "/<\?xml(.*?)\?>/s", "##XML\\1XML##", $template_code );
+
+               //disable php tag
+               if( !self::$php_enabled )
+                       $template_code = str_replace( array("<?","?>"), array("&lt;?","?&gt;"), $template_code );
+
+               //xml re-substitution
+               $template_code = preg_replace_callback ( "/##XML(.*?)XML##/s", array($this, 'xml_reSubstitution'), $template_code ); 
+
+               //compile template
+               $template_compiled = "<?php if(!class_exists('raintpl')){exit;}?>" . $this->compileTemplate( $template_code, $tpl_basedir );
+               
+
+               // fix the php-eating-newline-after-closing-tag-problem
+               $template_compiled = str_replace( "?>\n", "?>\n\n", $template_compiled );
+
+               // create directories
+               if( !is_dir( $cache_dir ) )
+                       mkdir( $cache_dir, 0755, true );
+
+               if( !is_writable( $cache_dir ) )
+                       throw new RainTpl_Exception ('Cache directory ' . $cache_dir . 'doesn\'t have write permission. Set write permission or set RAINTPL_CHECK_TEMPLATE_UPDATE to false. More details on http://www.raintpl.com/Documentation/Documentation-for-PHP-developers/Configuration/');
+
+               //write compiled file
+               file_put_contents( $compiled_filename, $template_compiled );
+       }
+
+
+
+       /**
+        * Compile template
+        * @access protected
+        */
+       protected function compileTemplate( $template_code, $tpl_basedir ){
+
+               //tag list
+               $tag_regexp = array( 'loop'         => '(\{loop(?: name){0,1}="\${0,1}[^"]*"\})',
+                             'loop_close'   => '(\{\/loop\})',
+                             'if'           => '(\{if(?: condition){0,1}="[^"]*"\})',
+                             'elseif'       => '(\{elseif(?: condition){0,1}="[^"]*"\})',
+                             'else'         => '(\{else\})',
+                             'if_close'     => '(\{\/if\})',
+                             'function'     => '(\{function="[^"]*"\})',
+                             'noparse'      => '(\{noparse\})',
+                             'noparse_close'=> '(\{\/noparse\})',
+                             'ignore'       => '(\{ignore\}|\{\*)',
+                             'ignore_close'    => '(\{\/ignore\}|\*\})',
+                             'include'      => '(\{include="[^"]*"(?: cache="[^"]*")?\})',
+                             'template_info'=> '(\{\$template_info\})',
+                             'function'                => '(\{function="(\w*?)(?:.*?)"\})'
+                                                       );
+
+               $tag_regexp = "/" . join( "|", $tag_regexp ) . "/";
+
+               //split the code with the tags regexp
+               $template_code = preg_split ( $tag_regexp, $template_code, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
+
+               //path replace (src of img, background and href of link)
+               $template_code = $this->path_replace( $template_code, $tpl_basedir );
+
+               //compile the code
+               $compiled_code = $this->compileCode( $template_code );
+
+               //return the compiled code
+               return $compiled_code;
+
+       }
+
+
+
+       /**
+        * Compile the code
+        * @access protected
+        */
+       protected function compileCode( $parsed_code ){
+
+               //variables initialization
+               $compiled_code = $open_if = $comment_is_open = $ignore_is_open = null;
+        $loop_level = 0;
+
+               //read all parsed code
+               while( $html = array_shift( $parsed_code ) ){
+
+                       //close ignore tag
+                       if( !$comment_is_open && ( strpos( $html, '{/ignore}' ) !== FALSE || strpos( $html, '*}' ) !== FALSE ) )
+                               $ignore_is_open = false;
+
+                       //code between tag ignore id deleted
+                       elseif( $ignore_is_open ){
+                               //ignore the code
+                       }
+
+                       //close no parse tag
+                       elseif( strpos( $html, '{/noparse}' ) !== FALSE )
+                               $comment_is_open = false;
+
+                       //code between tag noparse is not compiled
+                       elseif( $comment_is_open )
+                               $compiled_code .= $html;
+
+                       //ignore
+                       elseif( strpos( $html, '{ignore}' ) !== FALSE || strpos( $html, '{*' ) !== FALSE )
+                               $ignore_is_open = true;
+
+                       //noparse
+                       elseif( strpos( $html, '{noparse}' ) !== FALSE )
+                               $comment_is_open = true;
+
+                       //include tag
+                       elseif( preg_match( '/\{include="([^"]*)"(?: cache="([^"]*)"){0,1}\}/', $html, $code ) ){
+
+                               //variables substitution
+                               $include_var = $this->var_replace( $code[ 1 ], $left_delimiter = null, $right_delimiter = null, $php_left_delimiter = '".' , $php_right_delimiter = '."', $loop_level );
+
+                               // if the cache is active
+                               if( isset($code[ 2 ]) ){
+                                       
+                                       //dynamic include
+                                       $compiled_code .= '<?php $tpl = new '.get_class($this).';' .
+                                                                'if( $cache = $tpl->cache( $template = basename("'.$include_var.'") ) )' .
+                                                                '      echo $cache;' .
+                                                                'else{' .
+                                                                '      $tpl_dir_temp = self::$tpl_dir;' .
+                                                                '      $tpl->assign( $this->var );' .
+                                                                       ( !$loop_level ? null : '$tpl->assign( "key", $key'.$loop_level.' ); $tpl->assign( "value", $value'.$loop_level.' );' ).
+                                                                '      $tpl->draw( dirname("'.$include_var.'") . ( substr("'.$include_var.'",-1,1) != "/" ? "/" : "" ) . basename("'.$include_var.'") );'.
+                                                                '} ?>';
+                               }
+                               else{
+       
+                                       //dynamic include
+                                       $compiled_code .= '<?php $tpl = new '.get_class($this).';' .
+                                                                         '$tpl_dir_temp = self::$tpl_dir;' .
+                                                                         '$tpl->assign( $this->var );' .
+                                                                         ( !$loop_level ? null : '$tpl->assign( "key", $key'.$loop_level.' ); $tpl->assign( "value", $value'.$loop_level.' );' ).
+                                                                         '$tpl->draw( dirname("'.$include_var.'") . ( substr("'.$include_var.'",-1,1) != "/" ? "/" : "" ) . basename("'.$include_var.'") );'.
+                                                                         '?>';
+                                       
+                                       
+                               }
+
+                       }
+
+                       //loop
+                       elseif( preg_match( '/\{loop(?: name){0,1}="\${0,1}([^"]*)"\}/', $html, $code ) ){
+
+                               //increase the loop counter
+                               $loop_level++;
+
+                               //replace the variable in the loop
+                               $var = $this->var_replace( '$' . $code[ 1 ], $tag_left_delimiter=null, $tag_right_delimiter=null, $php_left_delimiter=null, $php_right_delimiter=null, $loop_level-1 );
+
+                               //loop variables
+                               $counter = "\$counter$loop_level";       // count iteration
+                               $key = "\$key$loop_level";               // key
+                               $value = "\$value$loop_level";           // value
+
+                               //loop code
+                               $compiled_code .=  "<?php $counter=-1; if( isset($var) && is_array($var) && sizeof($var) ) foreach( $var as $key => $value ){ $counter++; ?>";
+
+                       }
+
+                       //close loop tag
+                       elseif( strpos( $html, '{/loop}' ) !== FALSE ) {
+
+                               //iterator
+                               $counter = "\$counter$loop_level";
+
+                               //decrease the loop counter
+                               $loop_level--;
+
+                               //close loop code
+                               $compiled_code .=  "<?php } ?>";
+
+                       }
+
+                       //if
+                       elseif( preg_match( '/\{if(?: condition){0,1}="([^"]*)"\}/', $html, $code ) ){
+
+                               //increase open if counter (for intendation)
+                               $open_if++;
+
+                               //tag
+                               $tag = $code[ 0 ];
+
+                               //condition attribute
+                               $condition = $code[ 1 ];
+
+                               // check if there's any function disabled by black_list
+                               $this->function_check( $tag );
+
+                               //variable substitution into condition (no delimiter into the condition)
+                               $parsed_condition = $this->var_replace( $condition, $tag_left_delimiter = null, $tag_right_delimiter = null, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level );
+
+                               //if code
+                               $compiled_code .=   "<?php if( $parsed_condition ){ ?>";
+
+                       }
+
+                       //elseif
+                       elseif( preg_match( '/\{elseif(?: condition){0,1}="([^"]*)"\}/', $html, $code ) ){
+
+                               //tag
+                               $tag = $code[ 0 ];
+
+                               //condition attribute
+                               $condition = $code[ 1 ];
+
+                               //variable substitution into condition (no delimiter into the condition)
+                               $parsed_condition = $this->var_replace( $condition, $tag_left_delimiter = null, $tag_right_delimiter = null, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level );
+
+                               //elseif code
+                               $compiled_code .=   "<?php }elseif( $parsed_condition ){ ?>";
+                       }
+
+                       //else
+                       elseif( strpos( $html, '{else}' ) !== FALSE ) {
+
+                               //else code
+                               $compiled_code .=   '<?php }else{ ?>';
+
+                       }
+
+                       //close if tag
+                       elseif( strpos( $html, '{/if}' ) !== FALSE ) {
+
+                               //decrease if counter
+                               $open_if--;
+
+                               // close if code
+                               $compiled_code .=   '<?php } ?>';
+
+                       }
+
+                       //function
+                       elseif( preg_match( '/\{function="(\w*)(.*?)"\}/', $html, $code ) ){
+
+                               //tag
+                               $tag = $code[ 0 ];
+
+                               //function
+                               $function = $code[ 1 ];
+
+                               // check if there's any function disabled by black_list
+                               $this->function_check( $tag );
+
+                               if( empty( $code[ 2 ] ) )
+                                       $parsed_function = $function . "()";
+                               else
+                                       // parse the function
+                                       $parsed_function = $function . $this->var_replace( $code[ 2 ], $tag_left_delimiter = null, $tag_right_delimiter = null, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level );
+                               
+                               //if code
+                               $compiled_code .=   "<?php echo $parsed_function; ?>";
+                       }
+
+                       // show all vars
+                       elseif ( strpos( $html, '{$template_info}' ) !== FALSE ) {
+
+                               //tag
+                               $tag  = '{$template_info}';
+
+                               //if code
+                               $compiled_code .=   '<?php echo "<pre>"; print_r( $this->var ); echo "</pre>"; ?>';
+                       }
+
+
+                       //all html code
+                       else{
+
+                               //variables substitution (es. {$title})
+                               $html = $this->var_replace( $html, $left_delimiter = '\{', $right_delimiter = '\}', $php_left_delimiter = '<?php ', $php_right_delimiter = ';?>', $loop_level, $echo = true );
+                               //const substitution (es. {#CONST#})
+                               $html = $this->const_replace( $html, $left_delimiter = '\{', $right_delimiter = '\}', $php_left_delimiter = '<?php ', $php_right_delimiter = ';?>', $loop_level, $echo = true );
+                               //functions substitution (es. {"string"|functions})
+                               $compiled_code .= $this->func_replace( $html, $left_delimiter = '\{', $right_delimiter = '\}', $php_left_delimiter = '<?php ', $php_right_delimiter = ';?>', $loop_level, $echo = true );
+                       }
+               }
+
+               if( $open_if > 0 ) {
+                       $e = new RainTpl_SyntaxException('Error! You need to close an {if} tag in ' . $this->tpl['tpl_filename'] . ' template');
+                       throw $e->setTemplateFile($this->tpl['tpl_filename']);
+               }
+               return $compiled_code;
+       }
+       
+       
+       /**
+        * Reduce a path, eg. www/library/../filepath//file => www/filepath/file
+        * @param type $path
+        * @return type
+        */
+       protected function reduce_path( $path ){
+               $path = str_replace( "://", "@not_replace@", $path );
+               $path = str_replace( "//", "/", $path );
+               $path = str_replace( "@not_replace@", "://", $path );
+               return preg_replace('/\w+\/\.\.\//', '', $path );
+       }
+
+
+
+       /**
+        * replace the path of image src, link href and a href.
+        * url => template_dir/url
+        * url# => url
+        * http://url => http://url
+        *
+        * @param string $html
+        * @return string html sostituito
+        */
+       protected function path_replace( $html, $tpl_basedir ){
+
+               if( self::$path_replace ){
+
+                       $tpl_dir = self::$base_url . self::$tpl_dir . $tpl_basedir;
+                       
+                       // reduce the path
+                       $path = $this->reduce_path($tpl_dir);
+
+                       $exp = $sub = array();
+
+                       if( in_array( "img", self::$path_replace_list ) ){
+                               $exp = array( '/<img(.*?)src=(?:")(http|https)\:\/\/([^"]+?)(?:")/i', '/<img(.*?)src=(?:")([^"]+?)#(?:")/i', '/<img(.*?)src="(.*?)"/', '/<img(.*?)src=(?:\@)([^"]+?)(?:\@)/i' );
+                               $sub = array( '<img$1src=@$2://$3@', '<img$1src=@$2@', '<img$1src="' . $path . '$2"', '<img$1src="$2"' );
+                       }
+
+                       if( in_array( "script", self::$path_replace_list ) ){
+                               $exp = array_merge( $exp , array( '/<script(.*?)src=(?:")(http|https)\:\/\/([^"]+?)(?:")/i', '/<script(.*?)src=(?:")([^"]+?)#(?:")/i', '/<script(.*?)src="(.*?)"/', '/<script(.*?)src=(?:\@)([^"]+?)(?:\@)/i' ) );
+                               $sub = array_merge( $sub , array( '<script$1src=@$2://$3@', '<script$1src=@$2@', '<script$1src="' . $path . '$2"', '<script$1src="$2"' ) );
+                       }
+
+                       if( in_array( "link", self::$path_replace_list ) ){
+                               $exp = array_merge( $exp , array( '/<link(.*?)href=(?:")(http|https)\:\/\/([^"]+?)(?:")/i', '/<link(.*?)href=(?:")([^"]+?)#(?:")/i', '/<link(.*?)href="(.*?)"/', '/<link(.*?)href=(?:\@)([^"]+?)(?:\@)/i' ) );
+                               $sub = array_merge( $sub , array( '<link$1href=@$2://$3@', '<link$1href=@$2@' , '<link$1href="' . $path . '$2"', '<link$1href="$2"' ) );
+                       }
+
+                       if( in_array( "a", self::$path_replace_list ) ){
+                               $exp = array_merge( $exp , array( '/<a(.*?)href=(?:")(http\:\/\/|https\:\/\/|javascript:)([^"]+?)(?:")/i', '/<a(.*?)href="(.*?)"/', '/<a(.*?)href=(?:\@)([^"]+?)(?:\@)/i'  ) );
+                               $sub = array_merge( $sub , array( '<a$1href=@$2$3@', '<a$1href="' . self::$base_url . '$2"', '<a$1href="$2"' ) );
+                       }
+
+                       if( in_array( "input", self::$path_replace_list ) ){
+                               $exp = array_merge( $exp , array( '/<input(.*?)src=(?:")(http|https)\:\/\/([^"]+?)(?:")/i', '/<input(.*?)src=(?:")([^"]+?)#(?:")/i', '/<input(.*?)src="(.*?)"/', '/<input(.*?)src=(?:\@)([^"]+?)(?:\@)/i' ) );
+                               $sub = array_merge( $sub , array( '<input$1src=@$2://$3@', '<input$1src=@$2@', '<input$1src="' . $path . '$2"', '<input$1src="$2"' ) );
+                       }
+
+                       return preg_replace( $exp, $sub, $html );
+
+               }
+               else
+                       return $html;
+
+       }
+
+
+
+
+
+       // replace const
+       function const_replace( $html, $tag_left_delimiter, $tag_right_delimiter, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level = null, $echo = null ){
+               // const
+               return preg_replace( '/\{\#(\w+)\#{0,1}\}/', $php_left_delimiter . ( $echo ? " echo " : null ) . '\\1' . $php_right_delimiter, $html );
+       }
+
+
+
+       // replace functions/modifiers on constants and strings
+       function func_replace( $html, $tag_left_delimiter, $tag_right_delimiter, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level = null, $echo = null ){
+
+               preg_match_all( '/' . '\{\#{0,1}(\"{0,1}.*?\"{0,1})(\|\w.*?)\#{0,1}\}' . '/', $html, $matches );
+
+               for( $i=0, $n=count($matches[0]); $i<$n; $i++ ){
+
+                       //complete tag ex: {$news.title|substr:0,100}
+                       $tag = $matches[ 0 ][ $i ];
+
+                       //variable name ex: news.title
+                       $var = $matches[ 1 ][ $i ];
+
+                       //function and parameters associate to the variable ex: substr:0,100
+                       $extra_var = $matches[ 2 ][ $i ];
+
+                       // check if there's any function disabled by black_list
+                       $this->function_check( $tag );
+
+                       $extra_var = $this->var_replace( $extra_var, null, null, null, null, $loop_level );
+            
+
+                       // check if there's an operator = in the variable tags, if there's this is an initialization so it will not output any value
+                       $is_init_variable = preg_match( "/^(\s*?)\=[^=](.*?)$/", $extra_var );
+
+                       //function associate to variable
+                       $function_var = ( $extra_var and $extra_var[0] == '|') ? substr( $extra_var, 1 ) : null;
+
+                       //variable path split array (ex. $news.title o $news[title]) or object (ex. $news->title)
+                       $temp = preg_split( "/\.|\[|\-\>/", $var );
+
+                       //variable name
+                       $var_name = $temp[ 0 ];
+
+                       //variable path
+                       $variable_path = substr( $var, strlen( $var_name ) );
+
+                       //parentesis transform [ e ] in [" e in "]
+                       $variable_path = str_replace( '[', '["', $variable_path );
+                       $variable_path = str_replace( ']', '"]', $variable_path );
+
+                       //transform .$variable in ["$variable"]
+                       $variable_path = preg_replace('/\.\$(\w+)/', '["$\\1"]', $variable_path );
+
+                       //transform [variable] in ["variable"]
+                       $variable_path = preg_replace('/\.(\w+)/', '["\\1"]', $variable_path );
+
+                       //if there's a function
+                       if( $function_var ){
+                
+                // check if there's a function or a static method and separate, function by parameters
+                               $function_var = str_replace("::", "@double_dot@", $function_var );
+
+                // get the position of the first :
+                if( $dot_position = strpos( $function_var, ":" ) ){
+
+                    // get the function and the parameters
+                    $function = substr( $function_var, 0, $dot_position );
+                    $params = substr( $function_var, $dot_position+1 );
+
+                }
+                else{
+
+                    //get the function
+                    $function = str_replace( "@double_dot@", "::", $function_var );
+                    $params = null;
+
+                }
+
+                // replace back the @double_dot@ with ::
+                $function = str_replace( "@double_dot@", "::", $function );
+                $params = str_replace( "@double_dot@", "::", $params );
+
+
+                       }
+                       else
+                               $function = $params = null;
+
+                       $php_var = $var_name . $variable_path;
+
+                       // compile the variable for php
+                       if( isset( $function ) ){
+                               if( $php_var )
+                                       $php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . ( $params ? "( $function( $php_var, $params ) )" : "$function( $php_var )" ) . $php_right_delimiter;
+                               else
+                                       $php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . ( $params ? "( $function( $params ) )" : "$function()" ) . $php_right_delimiter;
+                       }
+                       else
+                               $php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . $php_var . $extra_var . $php_right_delimiter;
+
+                       $html = str_replace( $tag, $php_var, $html );
+
+               }
+
+               return $html;
+
+       }
+
+
+
+       function var_replace( $html, $tag_left_delimiter, $tag_right_delimiter, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level = null, $echo = null ){
+
+               //all variables
+               if( preg_match_all( '/' . $tag_left_delimiter . '\$(\w+(?:\.\${0,1}[A-Za-z0-9_]+)*(?:(?:\[\${0,1}[A-Za-z0-9_]+\])|(?:\-\>\${0,1}[A-Za-z0-9_]+))*)(.*?)' . $tag_right_delimiter . '/', $html, $matches ) ){
+
+                    for( $parsed=array(), $i=0, $n=count($matches[0]); $i<$n; $i++ )
+                        $parsed[$matches[0][$i]] = array('var'=>$matches[1][$i],'extra_var'=>$matches[2][$i]);
+
+                    foreach( $parsed as $tag => $array ){
+
+                            //variable name ex: news.title
+                            $var = $array['var'];
+
+                            //function and parameters associate to the variable ex: substr:0,100
+                            $extra_var = $array['extra_var'];
+
+                            // check if there's any function disabled by black_list
+                            $this->function_check( $tag );
+
+                            $extra_var = $this->var_replace( $extra_var, null, null, null, null, $loop_level );
+
+                            // check if there's an operator = in the variable tags, if there's this is an initialization so it will not output any value
+                            $is_init_variable = preg_match( "/^[a-z_A-Z\.\[\](\-\>)]*=[^=]*$/", $extra_var );
+                            
+                            //function associate to variable
+                            $function_var = ( $extra_var and $extra_var[0] == '|') ? substr( $extra_var, 1 ) : null;
+
+                            //variable path split array (ex. $news.title o $news[title]) or object (ex. $news->title)
+                            $temp = preg_split( "/\.|\[|\-\>/", $var );
+
+                            //variable name
+                            $var_name = $temp[ 0 ];
+
+                            //variable path
+                            $variable_path = substr( $var, strlen( $var_name ) );
+
+                            //parentesis transform [ e ] in [" e in "]
+                            $variable_path = str_replace( '[', '["', $variable_path );
+                            $variable_path = str_replace( ']', '"]', $variable_path );
+
+                            //transform .$variable in ["$variable"] and .variable in ["variable"]
+                            $variable_path = preg_replace('/\.(\${0,1}\w+)/', '["\\1"]', $variable_path );
+                            
+                            // if is an assignment also assign the variable to $this->var['value']
+                            if( $is_init_variable )
+                                $extra_var = "=\$this->var['{$var_name}']{$variable_path}" . $extra_var;
+
+                                
+
+                            //if there's a function
+                            if( $function_var ){
+                                
+                                    // check if there's a function or a static method and separate, function by parameters
+                                    $function_var = str_replace("::", "@double_dot@", $function_var );
+
+
+                                    // get the position of the first :
+                                    if( $dot_position = strpos( $function_var, ":" ) ){
+
+                                        // get the function and the parameters
+                                        $function = substr( $function_var, 0, $dot_position );
+                                        $params = substr( $function_var, $dot_position+1 );
+
+                                    }
+                                    else{
+
+                                        //get the function
+                                        $function = str_replace( "@double_dot@", "::", $function_var );
+                                        $params = null;
+
+                                    }
+
+                                    // replace back the @double_dot@ with ::
+                                    $function = str_replace( "@double_dot@", "::", $function );
+                                    $params = str_replace( "@double_dot@", "::", $params );
+                            }
+                            else
+                                    $function = $params = null;
+
+                            //if it is inside a loop
+                            if( $loop_level ){
+                                    //verify the variable name
+                                    if( $var_name == 'key' )
+                                            $php_var = '$key' . $loop_level;
+                                    elseif( $var_name == 'value' )
+                                            $php_var = '$value' . $loop_level . $variable_path;
+                                    elseif( $var_name == 'counter' )
+                                            $php_var = '$counter' . $loop_level;
+                                    else
+                                            $php_var = '$' . $var_name . $variable_path;
+                            }else
+                                    $php_var = '$' . $var_name . $variable_path;
+                            
+                            // compile the variable for php
+                            if( isset( $function ) )
+                                    $php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . ( $params ? "( $function( $php_var, $params ) )" : "$function( $php_var )" ) . $php_right_delimiter;
+                            else
+                                    $php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . $php_var . $extra_var . $php_right_delimiter;
+                            
+                            $html = str_replace( $tag, $php_var, $html );
+
+
+                    }
+                }
+
+               return $html;
+       }
+
+
+
+       /**
+        * Check if function is in black list (sandbox)
+        *
+        * @param string $code
+        * @param string $tag
+        */
+       protected function function_check( $code ){
+
+               $preg = '#(\W|\s)' . implode( '(\W|\s)|(\W|\s)', self::$black_list ) . '(\W|\s)#';
+
+               // check if the function is in the black list (or not in white list)
+               if( count(self::$black_list) && preg_match( $preg, $code, $match ) ){
+
+                       // find the line of the error
+                       $line = 0;
+                       $rows=explode("\n",$this->tpl['source']);
+                       while( !strpos($rows[$line],$code) )
+                               $line++;
+
+                       // stop the execution of the script
+                       $e = new RainTpl_SyntaxException('Unallowed syntax in ' . $this->tpl['tpl_filename'] . ' template');
+                       throw $e->setTemplateFile($this->tpl['tpl_filename'])
+                               ->setTag($code)
+                               ->setTemplateLine($line);
+               }
+
+       }
+
+       /**
+        * Prints debug info about exception or passes it further if debug is disabled.
+        *
+        * @param RainTpl_Exception $e
+        * @return string
+        */
+       protected function printDebug(RainTpl_Exception $e){
+               if (!self::$debug) {
+                       throw $e;
+               }
+               $output = sprintf('<h2>Exception: %s</h2><h3>%s</h3><p>template: %s</p>',
+                       get_class($e),
+                       $e->getMessage(),
+                       $e->getTemplateFile()
+               );
+               if ($e instanceof RainTpl_SyntaxException) {
+                       if (null != $e->getTemplateLine()) {
+                               $output .= '<p>line: ' . $e->getTemplateLine() . '</p>';
+                       }
+                       if (null != $e->getTag()) {
+                               $output .= '<p>in tag: ' . htmlspecialchars($e->getTag()) . '</p>';
+                       }
+                       if (null != $e->getTemplateLine() && null != $e->getTag()) {
+                               $rows=explode("\n",  htmlspecialchars($this->tpl['source']));
+                               $rows[$e->getTemplateLine()] = '<font color=red>' . $rows[$e->getTemplateLine()] . '</font>';
+                               $output .= '<h3>template code</h3>' . implode('<br />', $rows) . '</pre>';
+                       }
+               }
+               $output .= sprintf('<h3>trace</h3><p>In %s on line %d</p><pre>%s</pre>',
+                       $e->getFile(), $e->getLine(),
+                       nl2br(htmlspecialchars($e->getTraceAsString()))
+               );
+               return $output;
+       }
+}
+
+
+/**
+ * Basic Rain tpl exception.
+ */
+class RainTpl_Exception extends Exception{
+       /**
+        * Path of template file with error.
+        */
+       protected $templateFile = '';
+
+       /**
+        * Returns path of template file with error.
+        *
+        * @return string
+        */
+       public function getTemplateFile()
+       {
+               return $this->templateFile;
+       }
+
+       /**
+        * Sets path of template file with error.
+        *
+        * @param string $templateFile
+        * @return RainTpl_Exception
+        */
+       public function setTemplateFile($templateFile)
+       {
+               $this->templateFile = (string) $templateFile;
+               return $this;
+       }
+}
+
+/**
+ * Exception thrown when template file does not exists.
+ */
+class RainTpl_NotFoundException extends RainTpl_Exception{
+}
+
+/**
+ * Exception thrown when syntax error occurs.
+ */
+class RainTpl_SyntaxException extends RainTpl_Exception{
+       /**
+        * Line in template file where error has occured.
+        *
+        * @var int | null
+        */
+       protected $templateLine = null;
+
+       /**
+        * Tag which caused an error.
+        *
+        * @var string | null
+        */
+       protected $tag = null;
+
+       /**
+        * Returns line in template file where error has occured
+        * or null if line is not defined.
+        *
+        * @return int | null
+        */
+       public function getTemplateLine()
+       {
+               return $this->templateLine;
+       }
+
+       /**
+        * Sets  line in template file where error has occured.
+        *
+        * @param int $templateLine
+        * @return RainTpl_SyntaxException
+        */
+       public function setTemplateLine($templateLine)
+       {
+               $this->templateLine = (int) $templateLine;
+               return $this;
+       }
+
+       /**
+        * Returns tag which caused an error.
+        *
+        * @return string
+        */
+       public function getTag()
+       {
+               return $this->tag;
+       }
+
+       /**
+        * Sets tag which caused an error.
+        *
+        * @param string $tag
+        * @return RainTpl_SyntaxException
+        */
+       public function setTag($tag)
+       {
+               $this->tag = (string) $tag;
+               return $this;
+       }
+}
+
+// -- end
diff --git a/index.php b/index.php
new file mode 100755 (executable)
index 0000000..8861d31
--- /dev/null
+++ b/index.php
@@ -0,0 +1,97 @@
+<?php
+/**
+ * poche, a read it later open source system
+ *
+ * @category   poche
+ * @author     Nicolas Lœuillet <nicolas@loeuillet.org>
+ * @copyright  2013
+ * @license    http://www.wtfpl.net/ see COPYING file
+ */
+
+/**
+ * TODO
+ * gestion des erreurs sqlite (duplicate tout ça)
+ * gérer si url vide
+ * traiter les variables passées en get
+ * récupérer le titre de la page pochée (cf readityourself.php)
+ * actions archive, fav et delete à traiter
+ * bookmarklet
+ * améliorer présentation des liens
+ * améliorer présentation d'un article
+ * aligner verticalement les icones d'action
+ * afficher liens mis en favoris et archivés
+ * tri des liens
+ */
+
+try
+{
+    $db_handle = new PDO('sqlite:poche.sqlite');
+    $db_handle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+}
+catch (Exception $e)
+{
+    die('error : '.$e->getMessage());
+}
+
+$action = (isset ($_GET['action'])) ? htmlspecialchars($_GET['action']) : '';
+
+switch ($action) {
+    case 'add':
+        $url = (isset ($_GET['url'])) ? htmlspecialchars($_GET['url']) : '';
+        $title = $url;
+        $query = $db_handle->prepare('INSERT INTO entries ( url, title ) VALUES (?, ?)');
+        $query->execute(array($url, $title));
+        break;
+    case 'archive':
+        break;
+    case 'fav' :
+        break;
+    case 'delete':
+        break;
+    default:
+        break;
+}
+?>
+<!DOCTYPE html>
+<!--[if lte IE 6]> <html class="no-js ie6 ie67 ie678" lang="en"> <![endif]-->
+<!--[if lte IE 7]> <html class="no-js ie7 ie67 ie678" lang="en"> <![endif]-->
+<!--[if IE 8]> <html class="no-js ie8 ie678" lang="en"> <![endif]-->
+<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
+<html>
+    <head>
+        <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
+        <meta charset="utf-8">
+        <meta http-equiv="X-UA-Compatible" content="IE=10">
+        <title>poche : queue</title>
+        <link rel="stylesheet" href="css/knacss.css" media="all">
+        <link rel="stylesheet" href="css/style.css" media="all">
+    </head>
+    <body>
+       <header>
+                       <h1>poche, a read it later open source system</h1>
+               </header>
+               <div id="main" class="w800p">
+                       <ul id="links">
+                               <li><a href="index.php">home</a></li>
+                               <li><a href="#">favorites</a></li>
+                               <li><a href="#">archive</a></li>
+                <li><a href="javascript:(function(){var%20url%20=%20location.href;var%20title%20=%20document.title%20||%20url;window.open('http://localhost/poche/index.php?action=add&url='%20+%20encodeURIComponent(url),'_self');})();">bookmarklet</a></li>
+                       </ul>
+               <?php
+                       $query = $db_handle->prepare("SELECT * FROM entries WHERE read=?");
+                       $query->execute(array('FALSE'));
+                       $entries = $query->fetchAll();
+               ?>
+                       <ul id="entries">
+                               <?php
+                               foreach ($entries as $entry) {
+                                       echo '<li><a href="readityourself.php?url='.urlencode($entry['url']).'">' . $entry['title'] . '</a> <a href="#" title="toggle delete" class="tool">&#10003;</a> <a href="#" title="toggle favorite" class="tool">&#9734;</a> <a href="#" title="toggle mark as read" class="tool">&#10799;</a></li>';
+                               }
+                               ?>
+                       </ul>
+               </div>
+               <footer class="mr2 mt3">
+            <p class="smaller">poche is a read it later open source system, based on <a href="http://www.memiks.fr/readityourself/">ReadItYourself</a>. poche is developed by <a href="http://nicolas.loeuillet.org">Nicolas Lœuillet</a> under the <a href="http://www.wtfpl.net/">Do What the Fuck You Want to Public License</a></p>
+        </footer>
+       </body>
+</html>
\ No newline at end of file
diff --git a/poche.sqlite b/poche.sqlite
new file mode 100755 (executable)
index 0000000..0eea873
Binary files /dev/null and b/poche.sqlite differ
diff --git a/readityourself.php b/readityourself.php
new file mode 100755 (executable)
index 0000000..4a4661c
--- /dev/null
@@ -0,0 +1,212 @@
+<?php
+
+define("VERSION", "0.0.3");
+
+header('Content-type:text/html; charset=utf-8');
+// Set locale to French
+setlocale(LC_ALL, 'fr_FR');
+
+// set timezone to Europe/Paris
+date_default_timezone_set('Europe/Paris');
+
+// set charset to utf-8 important since all pages will be transform to utf-8
+header('Content-Type: text/html;charset=utf-8');
+
+// get readability library
+require_once dirname(__FILE__).'/inc/Readability.php';
+
+// get Encoding library.
+require_once dirname(__FILE__).'/inc/Encoding.php';
+
+// appel de la libraire RainTPL.
+require_once dirname(__FILE__).'/inc/rain.tpl.class.php';
+
+// FUNCTIONS BEGIN
+
+
+
+function url(){
+  $protocol = ($_SERVER['HTTPS'] && $_SERVER['HTTPS'] != "off") ? "https" : "http";
+  return $protocol . "://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
+}
+
+function generate_page($url,$title,$content) {
+       raintpl::$tpl_dir = './tpl/'; // template directory
+       raintpl::$cache_dir = "./cache/"; // cache directory
+       raintpl::$base_url = url(); // base URL of blog
+       raintpl::configure( 'path_replace', false );
+       raintpl::configure('debug', false); 
+
+       $tpl = new raintpl(); //include Rain TPL
+
+       $tpl->assign( "url", $url);
+       $tpl->assign( "title", $title);
+       $tpl->assign( "content", $content);
+       
+       $tpl->assign( "version", VERSION);
+       
+       $tpl->draw( "index"); // draw the template
+}
+
+// function define to retrieve url content
+function get_external_file($url, $timeout) {
+       // spoofing FireFox 18.0
+       $useragent="Mozilla/5.0 (Windows NT 5.1; rv:18.0) Gecko/20100101 Firefox/18.0";
+
+       if  (in_array  ('curl', get_loaded_extensions())) {     
+               // Fetch feed from URL
+               $curl = curl_init();
+               curl_setopt($curl, CURLOPT_URL, $url);
+               curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
+               curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
+               curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+               curl_setopt($curl, CURLOPT_HEADER, false);
+                
+               // FeedBurner requires a proper USER-AGENT...
+               curl_setopt($curl, CURL_HTTP_VERSION_1_1, true);
+               curl_setopt($curl, CURLOPT_ENCODING, "gzip, deflate");
+               curl_setopt($curl, CURLOPT_USERAGENT, $useragent);
+
+               $data = curl_exec($curl);
+               
+               $httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
+               
+               $httpcodeOK = isset($httpcode) and ($httpcode == 200 or $httpcode == 301);
+               
+               curl_close($curl);
+       } else {
+
+               // create http context and add timeout and user-agent
+               $context = stream_context_create(array('http'=>array('timeout' => $timeout, // Timeout : time until we stop waiting for the response.
+                                                                                                                                                                       'header'=> "User-Agent: ".$useragent, // spoot Mozilla Firefox
+                                                                                                                                                                       'follow_location' => true
+                                                                                                               )));
+
+               // only download page lesser than 4MB
+               $data = @file_get_contents($url, false, $context, -1, 4000000); // We download at most 4 MB from source.
+               //      echo "<pre>http_response_header : ".print_r($http_response_header);
+               
+               if(isset($http_response_header) and isset($http_response_header[0])) {
+                       $httpcodeOK = isset($http_response_header) and isset($http_response_header[0]) and ((strpos($http_response_header[0], '200 OK') !== FALSE) or (strpos($http_response_header[0], '301 Moved Permanently') !== FALSE));
+               }
+       }
+
+       // if response is not empty and response is OK
+       if (isset($data) and isset($httpcodeOK) and httpcodeOK ) {
+
+               // take charset of page and get it
+               preg_match('#<meta .*charset=.*>#Usi', $data, $meta);
+
+               // if meta tag is found
+               if (!empty($meta[0])) {
+                       // retrieve encoding in $enc
+                       preg_match('#charset="?(.*)"#si', $meta[0], $enc);
+
+                       // if charset is found set it otherwise, set it to utf-8
+                       $html_charset = (!empty($enc[1])) ? strtolower($enc[1]) : 'utf-8';
+
+               } else { 
+                       $html_charset = 'utf-8';
+                       $enc[1] = '';
+               }
+
+               // replace charset of url to charset of page
+               $data = str_replace('charset='.$enc[1], 'charset='.$html_charset, $data);
+
+               return $data;
+       }
+       else {
+               return FALSE;
+       }
+}
+
+function rel2abs($rel, $base)
+{
+    /* return if already absolute URL */
+    if (parse_url($rel, PHP_URL_SCHEME) != '') return $rel;
+
+    /* queries and anchors */
+    if ($rel[0]=='#' || $rel[0]=='?') return $base.$rel;
+
+    /* parse base URL and convert to local variables:
+       $scheme, $host, $path */
+    extract(parse_url($base));
+
+    /* remove non-directory element from path */
+    $path = preg_replace('#/[^/]*$#', '', $path);
+
+    /* destroy path if relative url points to root */
+    if ($rel[0] == '/') $path = '';
+
+    /* dirty absolute URL */
+    $abs = "$host$path/$rel";
+
+    /* replace '//' or '/./' or '/foo/../' with '/' */
+    $re = array('#(/\.?/)#', '#/(?!\.\.)[^/]+/\.\./#');
+    for($n=1; $n>0; $abs=preg_replace($re, '/', $abs, -1, $n)) {}
+
+    /* absolute URL is ready! */
+    return $scheme.'://'.$abs;
+}
+
+// $str=preg_replace('#(href|src)="([^:"]*)("|(?:(?:%20|\s|\+)[^"]*"))#','$1="http://wintermute.com.au/$2$3',$str);
+
+function absolutes_links($data, $base) {
+       // cherche les balises 'a' qui contiennent un href
+       $matches = array();
+       preg_match_all('#(href|src)="([^:"]*)("|(?:(?:%20|\s|\+)[^"]*"))#Si', $data, $matches, PREG_SET_ORDER);
+
+       // ne conserve que les liens ne commençant pas par un protocole « protocole:// » ni par une ancre « # »
+       foreach($matches as $i => $link) {
+               $link[1] = trim($link[1]);
+
+               if (!preg_match('#^(([a-z]+://)|(\#))#', $link[1]) ) {
+
+                       $absolutePath=rel2abs($link[2],$base);
+
+                       $data = str_replace($matches[$i][2], $absolutePath, $data);
+               }
+
+       }
+       return $data;
+}
+
+
+// FUNCTIONS END
+
+// EXUCUTION CODE
+
+
+if(isset($_GET['url']) && $_GET['url'] != null && trim($_GET['url']) != "") {
+       // get url link
+       if(strlen(trim($_GET['url'])) > 2048) {
+               echo "Error URL is too large !!";
+       } else {
+               $url = trim($_GET['url']);
+
+               // decode it
+               $url = html_entity_decode($url);
+               
+               // if url use https protocol change it to http
+               if (!preg_match('!^https?://!i', $url)) $url = 'http://'.$url;
+               
+               // convert page to utf-8
+               $html = Encoding::toUTF8(get_external_file($url,15));
+               
+               if(isset($html) and strlen($html) > 0) {
+               
+                       // send result to readability library
+                       $r = new Readability($html, $url);
+
+                       if($r->init()) {
+                               generate_page($url,$r->articleTitle->innerHTML,$r->articleContent->innerHTML);
+                       } else {
+                               // return data into an iframe
+                               echo "<iframe id='readabilityframe'>".$html."</iframe>";
+                       }
+               } else {
+                       echo "Error unable to get link : ".$url;
+               }
+       }
+}
+?>
diff --git a/tpl/footer.html b/tpl/footer.html
new file mode 100755 (executable)
index 0000000..8385b96
--- /dev/null
@@ -0,0 +1,7 @@
+<footer>
+       <div>  
+       Copyright &copy; <a href="http://www.memiks.fr/">memiks.fr</a> | <a href="http://shaarli.memiks.fr/">Liens</a> / <a href="http://rss.memiks.fr/">RSS</a> / <a href="http://wiki.memiks.fr/">Wiki</a>  / <a href="mailto:&#109;&#101;&#109;&#105;&#107;&#115;&#064;&#109;&#101;&#109;&#105;&#107;&#115;&#046;&#102;&#114;">Contact</a><br>
+                       Licence: WTF Licence<br>
+                       More information HERE: <a href="http://www.memiks.fr/readityourself/">http://www.memiks.fr/readityourself/</a> Version : <span class="version">{$version}</span>
+       </div>
+</footer>
diff --git a/tpl/index.html b/tpl/index.html
new file mode 100755 (executable)
index 0000000..b4aba16
--- /dev/null
@@ -0,0 +1,18 @@
+<html>
+       <head>
+               <link rel='stylesheet' href='./css/reset.css' type='text/css' media='all' />
+               <link rel='stylesheet' href='./css/typography.css' type='text/css' media='all' />
+       
+               <title>{$title}</title>
+       </head>
+       <body>
+               <article>
+                       <h1><a href="{$url}">{$title}</a></h1>
+                       <div id="readityourselfcontent">
+                               {$content}
+                       </div>
+                       <span class="comeFrom">Come From : <a href="{$url}">{$url}</a>
+               </article>
+               {include="footer"}
+       </body>
+</html>