RSS330-Zend

== Introduction ==
RSS330 is a very fast, rapid and efficient script inworld (+ external php + Zend framework) for displaying RSS feeds inworld or using a HUD.
It is here available under the following license:
http://creativecommons.org/licenses/by-nc-sa/3.0/
CC Creative Commons 
by Salahzar Stenvaag
nc Not commercial
sa Share alike derivatives works
It takes advantage of the following technologies:
* XyText generic engine for displaying character (see: )
* UTF-8 character displaying (see: )
* PHP linking to an external program exploiting Zend Framework (available under a free OpenSource license BSD)
You can find it free at xstreet: RSS Zend UTF8
== How to use it ==
This RSS reader is *fast* and easy to use and it is *opensource*. It can be adapted to various non English languages LTR if they are
available in utf8 font. It can also be used ot read tweet or anything providing some rss feed.
Current version is distributed with pre-defined languages "portuguese" and "esperanto", they should work however well for Italian
French, German. If you have other languages you have to produce your texture using instructions found in this page: http://wiki.secondlife.com/wiki/XyText-UTF8.
=== How to select a feed ===
* Just grab the RSS link from the page you want to be blogged in world (right click the RSS icon and then copy link location)
* Open the content of this Feeder the _RSS330 ZEND script
* Paste the address in the line where you read feed="http://web.site/rss.xml"; be sure to not delete the " " and the ending ;
é Remember to change the title=" "; with the title of this blog
* That's all the board will refresh instantly with new feed
=== How to use the board ===
* Use the black arrows on the top line to scroll on older news and back on various pages
* When you are interested in a news just click on that row and the news will be expanded over the board
* Click on the board to open up the browser with the full news
* Click on the title to go back on the title listing
* Board will autorefresh every 10 minutes (change refreshminutes=10; in the script to another value to change this)
If you are interested in NON ENGLISH feeds you will probably need to tweak also the utf8=1 flag. Put it to other values, such as "ISO-8859-1" to read other character sets correctly.
To change the texture for other languages open the Init Cells - Language. There are already the settings for portuguese and esperanto, but we can add more.
== You need to have an "empty board" with arrows to use as basis ==
It is available here on xstreet (0L$): 
== The init cell ==
Only needed if you need to display European or not English characters
<lsl>
list decode; string texture;
string language="portuguese";
initCells()
{
 
 if(language=="portuguese")
 {
 setPortuguese();
 } 
 else if(language=="esperanto")
 {
 setEsperanto();
 }
 // set esperanto texture and decoding texture being produced by PythonFu for GIMP
 float dy=-0.005;
 llMessageLinked(LINK_SET, 204005, 
 llList2CSV( [ 
 10, // knum number of characters per row
 <-0.44,0.1,0>, // offset multiplier for cols
 <0.422,-0.05,0>, // offset multiplier for rows
 // change the first two in each row to change multiplier for zooming chars
 <0.15, 0.05, 0>,
 <0.06, 0.05, 0>, 
 <-0.86, 0.05, 0>,
 <0.06, 0.05, 0>, 
 <0.15, 0.05, 0>, 
 // change the first two x and y in each row to "move characters along x,y axis
 <0.035, 0+dy, 0>,
 <-0.012,0+dy,0>,
 <-0.298, 0+dy, 0>,
 <-0.012,0+dy,0>,
 <-0.055, 0+dy, 0>
 ]), texture);
 llMessageLinked(LINK_SET, 204006, llList2CSV(decode),NULL_KEY);
 
}
setPortuguese()
{
 texture="db6664f6-057f-becf-bb1e-924255c2c7fd";
 
 // special UTF-8 chars for European languages
 // these 80 chars correspond to the following chars in CP850 codepage: (some are not viewable in editor)
 
 // Ç ü é â ä à å ç ê ë
 decode= [ "%C3%87", "%C3%BC", "%C3%A9", "%C3%A2", "%C3%A4", "%C3%A0", "%C3%A5", "%C3%A7", "%C3%AA", "%C3%AB",
 // è ï î ì Ä Å É æ Æ BLACK RIGHT-POINTING TRIANGLE
 "%C3%A8", "%C3%AF", "%C3%AE", "%C3%AC", "%C3%84", "%C3%85", "%C3%89", "%C3%A6", "%C3%AE", "%E2%96%B6",
 // ö ò û ù ÿ Ö Ü ¢ £ ¥
 "%C3%B6", "%C3%B2", "%C3%BB", "%C3%B9", "%C3%BF", "%C3%96", "%C3%9C", "%C2%A2", "%C2%A3", "%C2%A5",
 // A^ copyright á í ó ú ñ Ñ ª º"
 "%C3%82", "%C2%A9", "%C3%A1", "%C3%AD", "%C3%B3", "%C3%BA", "%C3%B1", "%C3%91", "%C2%AA", "%C2%BA",
 // ¿ O^ ¬ ½ ¼ ¡ « » alfa ß"
 "%C2%BF", "%C3%94", "%C2%AC", "%C2%BD", "%C2%BC", "%C2%A1", "%C2%AB", "%C2%BB", "%CE%B1", "%C3%9F",
 // gamma pi bigsigma smsigma mu tau BIGfi theta omega delta 
 "%CE%93", "%CF%80", "%CE%A3", "%CF%83", "%C2%B5", "%CF%84", "%CE%A6", "%CE%98", "%CE%A9", "%CE%B4",
 // Uu uu EPS INTERS 3bars +- <= >= INTEGRUP INTEGRDOWN
 "%C5%AC", "%C5%AD", "%CE%B5", "%E2%88%A9", "%E2%89%A1", "%C2%B1", "%E2%89%A5", "%E2%89%A4", "%E2%8C%A0", "%E2%8C%A1",
 // A/ A\ a~ A~ E^ I/ O/ o~ O~ o^
 "%C3%81", "%C3%80", "%C3%A3", "%C3%83", "%C3%8A", "%C3%8D", "%C3%93", "%C3%B5", "%C3%95", "%C3%B4" ];
 
 
}
setEsperanto()
{
 texture="1f490434-2c70-d56e-97a7-52c613a0c814";
 // Ç ü é â ä à å ç ê ë
 decode= [ "%C3%87", "%C3%BC", "%C3%A9", "%C3%A2", "%C3%A4", "%C3%A0", "%C3%A5", "%C3%A7", "%C3%AA", "%C3%AB",
 // è ï î ì Ä Å É æ Æ BLACK RIGHT-POINTING TRIANGLE
 "%C3%A8", "%C3%AF", "%C3%AE", "%C3%AC", "%C3%84", "%C3%85", "%C3%89", "%C3%A6", "%C3%AE", "%E2%96%B6",
 // ö ò û ù ÿ Ö Ü ¢ £ ¥
 "%C3%B6", "%C3%B2", "%C3%BB", "%C3%B9", "%C3%BF", "%C3%96", "%C3%9C", "%C2%A2", "%C2%A3", "%C2%A5",
 // A^ copyright á í ó ú ñ Ñ ª º"
 "%C3%82", "%C2%A9", "%C3%A1", "%C3%AD", "%C3%B3", "%C3%BA", "%C3%B1", "%C3%91", "%C2%AA", "%C2%BA",
 // ¿ O^ ¬ ½ ¼ ¡ « » alfa ß"
 "%C2%BF", "%C3%94", "%C2%AC", "%C2%BD", "%C2%BC", "%C2%A1", "%C2%AB", "%C2%BB", "%CE%B1", "%C3%9F",
 // gamma pi bigsigma smsigma mu tau BIGfi theta omega delta 
 "%CE%93", "%CF%80", "%CE%A3", "%CF%83", "%C2%B5", "%CF%84", "%CE%A6", "%CE%98", "%CE%A9", "%CE%B4",
 // Uu uu EPS INTERS 3bars +- <= >= INTEGRUP INTEGRDOWN
 "%C5%AC", "%C5%AD", "%CE%B5", "%E2%88%A9", "%E2%89%A1", "%C2%B1", "%E2%89%A5", "%E2%89%A4", "%E2%8C%A0", "%E2%8C%A1",
 // C^ c^ G^ g^ H^ h^ J^ j^ S^ s^
 "%C4%88", "%C4%89", "%C4%9C", "%C4%9D", "%C4%A4", "%C4%A5", "%C4%B4", "%C4%B5", "%C5%9C", "%C5%9D" ];
 
 
}
default
{
 state_entry()
 {
 initCells(); 
 }
 on_rez(integer number)
 {
 //initCells();
 }
}
</lsl>
== The lsl program ==
Remember to customize the feed, url, titl, utf8 variables at beginning:
<lsl>
//
// RSS Reader RSS 330
// August 2009 by Salahzar Stenvaag
// Using xytext engine cell 1.2 
// using UTF8 parametrization
//
//string feed="http://tralafenestro.wordpress.com/feed/";
//string feed="http://twitter.com/statuses/user_timeline/53944252.rss";
//string feed="http://feeds.feedburner.com/blogspot/hJyX?format=xml";
string feed="http://www.repubblica.it/rss/homepage/rss2.0.xml";
string url="http://opensimita.org/lsl/rss2009.php?";
string title="La repubblica";
integer utf8=1; // set it to 1 for utf-8 or other character set es. iso-8859-1
integer refreshminutes=10; // every 10 minutes refresh the blog
// don't modify hereafter unless you really know !!!
// set this to 1 to have debug information at llOwnerSay
// remember to remove when finished with debugging
integer DEBUG=0;
// will hold the titles
list titles=[];
integer start;
displayPage()
{
 integer numtitles=llGetListLength(titles);
 integer i; setText("Page "+(string)(start/10+1)+" / "+ (string)(numtitles/10+1));
 show(title,-1);
 for(i=start;i<start+10;i++)
 {
 if(i<numtitles)
 {
 show(">"+llList2String(titles,i),i-start);
 }
 else show(" ",i-start);
 } 
}
setText(string str)
{
 llMessageLinked(LINK_ALL_OTHERS,9999,str,NULL_KEY);
}
string str1;
string str2;
string str3;
string str4;
string str5;
string str6;
string str7;
string str8;
show(string str, integer row)
{
 
 str1=llGetSubString(str,0,4);
 str2=llGetSubString(str,5,9);
 str3=llGetSubString(str,10,14);
 str4=llGetSubString(str,15,19);
 str5=llGetSubString(str,20,24);
 str6=llGetSubString(str,25,29);
 str7=llGetSubString(str,30,34);
 str8=llGetSubString(str,35,39);
 
 integer ch;
 if(row==-1) ch=20000;
 else ch=(row+1)*1000; 
 
 //llSay(0,"Displaying "+str+" on row "+(string)row+ "channel: "+(string)ch);
 
 llMessageLinked(LINK_SET,ch,str1,"");
 llMessageLinked(LINK_SET,ch+1,str2,"");
 llMessageLinked(LINK_SET,ch+2,str3,"");
 llMessageLinked(LINK_SET,ch+3,str4,"");
 llMessageLinked(LINK_SET,ch+4,str5,"");
 llMessageLinked(LINK_SET,ch+5,str6,"");
 llMessageLinked(LINK_SET,ch+6,str7,"");
 llMessageLinked(LINK_SET,ch+7,str8,"");
 //llSleep(0.1);
 
 
}
// be sure the whiteboard is clean now
clean(){
 setText("Cleaning up");
/* integer i;
 for(i=-1;i<10;i++){
 show(" ",i);
 llSleep(0.2); // don't clean too fast
 }
*/
}
readTitles()
{
 start=0; clean(); gourl=""; curpos=-1;
 
 ktitles=llHTTPRequest(url+"feed="+llEscapeURL(feed)+"&headers=1&utf8="+(string)utf8,[],""); 
}
integer wbline;
showMultiLines(string str)
{
 while (llStringLength(str)>0 && wbline<10)
 {
 if(llStringLength(str)>40)
 {
 show(llGetSubString(str,0,39),wbline++);
 str = llGetSubString(str,40,-1);
 } 
 else 
 {
 show(str,wbline++);
 str="";
 }
 }
 
}
hideArrows(integer x)
{
 llSetLinkAlpha(3,1-x,ALL_SIDES);
 llSetLinkAlpha(2,1-x,ALL_SIDES);
}
string gourl;
integer curpos;
key ktitles; key knews;
default
{
 state_entry()
 {
 //initCells(); 
 llSleep(3);
 readTitles(); hideArrows(0);
 llSetTimerEvent(refreshminutes*60);
 }
 timer()
 {
 readTitles(); hideArrows(0);
 }
 touch_start(integer count)
 {
 //llSay(0,(string)llDetectedLinkNumber(0));
 string touchedlink=llGetLinkName(llDetectedLinkNumber(0));
 //llSay(0,"touchedlink: "+touchedlink+" curpos: "+(string)curpos+" start: "+(string)start);
 if(touchedlink=="PREV" && curpos<0 && (start >= 10))
 {
 start-=10;
 if(start<0) start=0;
 displayPage();
 return;
 }
 if(touchedlink=="NEXT" && curpos<0 && ((start+10) < llGetListLength(titles)))
 {
 start+=10;
 displayPage();
 return;
 }
 
 
 integer row= (integer)touchedlink/1000;
 
 // touched the title and we were in detail 
 if(row>10 && curpos>=0)
 {
 hideArrows(0);
 displayPage(); gourl="";
 curpos=-1;
 setText("");
 return;
 }
 // touched on a row and we were in headers
 if(row>0 && curpos<0)
 {
 hideArrows(1);
 curpos= row - 1 + start;
 string http=url+"feed="+llEscapeURL(feed)+"&pos="+(string)curpos+"&utf8="+(string)utf8;
 
 knews=llHTTPRequest(http,[],"");
 return;
 }
 if(row>0 && gourl!="")
 {
 llLoadURL(llDetectedKey(0),llList2String(titles,curpos),gourl);
 return;
 }
 }
 http_response(key reqid, integer status, list metadata, string body)
 {
 if(reqid==ktitles)
 {
 titles=llParseStringKeepNulls(body,["\n"],[]);
 //llSay(0,llList2CSV(titles));
 displayPage();
 curpos=-1;
 }
 if(reqid==knews)
 {
 list news=llParseStringKeepNulls(body,["\n"],[]);
 show(llList2String(titles,curpos),-1);
 integer i;
 show(llList2String(news,0),0); wbline=1;
 showMultiLines(llList2String(news,1));
 gourl=llList2String(news,2);
 showMultiLines(llList2String(news,3)); while(wbline<10) show(" ",wbline++);
 setText("Touch Title to go back to titles, screen to go to the url");
 }
 }
 on_rez(integer number)
 {
 llResetScript();
 }
}
</lsl>
== The php program ==
You will need it if want to host on your own website (php compliant)
<php>
<?
function clean($str,$codeset)
{
 
 // fix a "bug" in html_entity_decode not handling '
 $s=str_replace(''', "'", html_entity_decode($str,ENT_QUOTES,$codeset));
 $s=str_replace(''," ",$s); // line breaks substituted with a space
 // be sure not having html tags any more
 return strip_tags($s);
}
$pos=$_GET['pos']; $feed=$_GET['feed']; $headers=$_GET['headers']; $utf8=$_GET['utf8'];
if($utf8=="1") 
{
 header ('Content-type: text/html; charset=utf-8');
 $name="utf-8";
}
else
{
 $name=$utf8;
}
 require_once 'Zend/Loader.php';
 Zend_Loader::loadClass('Zend_Feed');
// Fetch the latest Slashdot headlines
try {
 $slashdotRss =
 //http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/front_page/rss.xml
 //Zend_Feed::import('http://rss.slashdot.org/Slashdot/slashdot');
 Zend_Feed::import($feed); // 'http://www.repubblica.it/rss/homepage/rss2.0.xml');
} catch (Zend_Feed_Exception $e) {
 // feed import failed
 echo "Exception caught importing feed: {$e->getMessage()}\n";
 exit;
}
// Loop over each channel item and store relevant data
$i=0;
foreach ($slashdotRss as $item) {
 if($headers!="")
 {
 echo clean($item->title(),$name)."\n";
 }
 else
 if($i==$pos)
 {
 	echo $item->pubDate()."\n";
 	echo clean($item->title(),$name)."\n";
 	echo strip_tags($item->link())."\n";
 	echo clean($item->description(), $name);
 return;
 }
 $i++;
}
echo "EOF";
?>
</php>
<lsl>//so the LSL is properly colored</lsl>