<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><!-- generator="wordpress/2.3.3" --><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>ProDevTips - dev notes and tutorials</title>
	<link>http://www.prodevtips.com</link>
	<description>Dev related notes, tutorials and anecdotes</description>
	<pubDate>Tue, 09 Mar 2010 12:47:47 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.3.3</generator>
	<language>en</language>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/prodevtips/LVkG" /><feedburner:info uri="prodevtips/lvkg" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license><feedburner:emailServiceId>prodevtips/LVkG</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item>
		<title>jQuery Drag and Drop to sort Tree</title>
		<link>http://feedproxy.google.com/~r/prodevtips/LVkG/~3/d04RxGZherg/</link>
		<comments>http://www.prodevtips.com/2010/03/07/jquery-drag-and-drop-to-sort-tree/#comments</comments>
		<pubDate>Sun, 07 Mar 2010 15:21:27 +0000</pubDate>
		<dc:creator>Henrik</dc:creator>
		
		<category><![CDATA[Ajax]]></category>

		<category><![CDATA[jQuery]]></category>

		<category><![CDATA[ajax]]></category>

		<category><![CDATA[Javascript]]></category>

		<category><![CDATA[jquery]]></category>

		<category><![CDATA[json]]></category>

		<category><![CDATA[tree]]></category>

		<guid isPermaLink="false">http://www.prodevtips.com/2010/03/07/jquery-drag-and-drop-to-sort-tree/</guid>
		<description><![CDATA[Tutorial on how to sort a tree using jQuery droppable and draggable.]]></description>
			<content:encoded><![CDATA[Copyright © 2010 <a href="http://www.prodevtips.com">http://www.prodevtips.com</a>. Visit the original article at <a href="http://www.prodevtips.com/2010/03/07/jquery-drag-and-drop-to-sort-tree/">http://www.prodevtips.com/2010/03/07/jquery-drag-and-drop-to-sort-tree/</a>.<br /><p><img src='http://www.prodevtips.com/wp-content/uploads/2010/03/jquery_drag_and_drop.png' alt='jquery_drag_and_drop.png' />
<div class="image_right">
<script type="text/javascript"><!--
      google_ad_client = "pub-4780703337538969";
      google_alternate_color = "dedcdc";
      google_ad_width = 250;
      google_ad_height = 250;
      google_ad_format = "250x250_as";
      google_ad_type = "text_image";
      google_color_border = "dedcdc";
      google_color_link = "993333";
      google_color_bg = "dedcdc";
      google_color_text = "000000";
      google_color_url = "003366";
      //-->
   </script><br />
  <script type="text/javascript"
    src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
  </script>
</div>
<p>I just finished off a nice interface where an arbitrary amount of nested lists are used to represent a tree. Any item can be dragged and dropped on any other item as a way of moving them and placing them as children beneath another item/branch. The functionality mimics that of any file browser that can display folder structures as a tree.</p>
<p>Check out the <a href="http://www.prodevtips.com/demos/drag_drop_tree/">demo here</a>, drag and drop texts on other texts. The goal here is to sort various tags in an arbitrary hierarchy, and then save it to a database by way of <a href="http://www.prodevtips.com/2008/08/15/jquery-json-with-php-json_encode-and-json_decode/">Ajax and jQuery JSON</a>. In order to do that we have to loop through the whole tree in a recursive manner, more on that after the code listing.</p>
<p>I&#8217;ve taken the basic functionality from the <a href="http://interface.eyecon.ro/">Interface</a> <a href="http://interface.eyecon.ro/demos/drag_drop_tree.html">drag and drop tree</a>. Note how their interface is a lot more complicated as it resembles a real file browser. Below all of that has been ripped out as we only want the basic sorting here. I&#8217;m also using the latest version of the jQuery UI components whereas they&#8217;re using somewhat dated versions.</p>
<p>Note that I&#8217;m also making use of the <a href="http://www.prodevtips.com/2009/07/11/jquery-debug-plugin-print_r-style-output/">print_r jQuery plugin</a> in the demo.</p>
<pre><code class="javascript">function parseTree(ul){
	var tags = [];
	ul.children("li").each(function(){
		var subtree =	$(this).children("ul");
		if(subtree.size() &gt; 0)
			tags.push([$(this).attr("id"), parseTree(subtree)]);
		else
			tags.push($(this).attr("id"));
	});
	return tags;
}

$(document).ready(function(){
		
	$("li.tree_item span").droppable({
		tolerance		: "pointer",
		hoverClass		: "tree_hover",
		drop			: function(event, ui){
			var dropped = ui.draggable;
			dropped.css({top: 0, left: 0});
			var me = $(this).parent();
			if(me == dropped)
				return;
			var subbranch = $(me).children("ul");
			if(subbranch.size() == 0) {
				me.find("span").after("&lt;ul&gt;&lt;/ul&gt;");
				subbranch = me.find("ul");
			}
			var oldParent = dropped.parent();
			subbranch.eq(0).append(dropped);
			var oldBranches = $("li", oldParent);
			if (oldBranches.size() == 0) { $(oldParent).remove(); }
		}
	});
	
	$("li.tree_item").draggable({
		opacity: 0.5,
		revert: true
	});
	
	$("#save").click(function(){
		/*
		var tree = $.toJSON(parseTree($("#tag_tree")));
		$.post("@saveTags", {tags: tree}, function(res){
			$("#printOut").html(res);
		});
		*/
		$.debug.print_r(parseTree($("#tag_tree")), "printOut", false);
	});
});</code></pre>
<p>Let&#8217;s walk the droppable code first as it&#8217;s the most complicated:</p>
<div class="image_right">
<script type="text/javascript"><!--
      google_ad_client = "pub-4780703337538969";
      google_alternate_color = "dedcdc";
      google_ad_width = 250;
      google_ad_height = 250;
      google_ad_format = "250x250_as";
      google_ad_type = "text_image";
      google_color_border = "dedcdc";
      google_color_link = "993333";
      google_color_bg = "dedcdc";
      google_color_text = "000000";
      google_color_url = "003366";
      //-->
   </script><br />
  <script type="text/javascript"
    src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
  </script>
</div>
<p>1.) We begin by setting two options (<strong>tolerance</strong> and <strong>hoverClass</strong>) and the callback (<strong>drop</strong>). Tolerance -> pointer will result in a properly set drop condition if the mouse pointer hovers over the drop target while we drag something, a nice hover class is good to have too that will be assigned to the drop target to indicate that yes we can drop now.</p>
<p>2.) The callback will first set top to 0 and left to 0 on the dropped element, I don&#8217;t know why I have to do this but it didn&#8217;t work properly without that line, the jQuery UI code assigned these two properties to any moved element making them end up in the strangest of places.</p>
<p>3.) Since we are in effect dropping on only the spanned text elements, not the list elements themselves (doing that would create unresolvable ambiguities), we have to get at the parent list element of the text in question. That would be the parent().</p>
<p>4.) I&#8217;m not sure we need that test to check for self-drops, couldn&#8217;t hurt though.</p>
<p>5.) Next we check if we have a child ul element already, otherwise we create it, and append the dropped object to its inner html.</p>
<p>6.) We also save the prior parent (ul) of the dropped list. If it doesn&#8217;t contain any elements anymore it will be removed.</p>
<p>When the <strong>Save</strong> button is pressed we will loop through the whole tree recursively with the help of the <strong>parseTree</strong> function which will call itself whenever a list contains an ul element.</p>
<p>Finally we could convert the resultant array to a JSON string and send it to the server by way of Ajax which is done in the commented out code here. Instead we use the print_r function to output the whole structure for inspection.<br />
<h3>Related Posts</h3>
<ul class="related_post">
<li><a href="http://www.prodevtips.com/2009/12/09/multiple-select-lists-with-jquery-and-json/" title="Multiple select lists with jQuery and JSON">Multiple select lists with jQuery and JSON</a></li>
<li><a href="http://www.prodevtips.com/2008/08/25/adding-search-with-jquery-and-check-boxes/" title="Adding search with jQuery and Check Boxes">Adding search with jQuery and Check Boxes</a></li>
<li><a href="http://www.prodevtips.com/2010/01/10/simple-jquery-and-php-crud-interface/" title="The basic C(R)UD">The basic C(R)UD</a></li>
<li><a href="http://www.prodevtips.com/2009/12/05/shortening-multiple-urls-with-jquery-php-picolisp-and-bitly/" title="Shortening multiple URLs with jQuery, PHP, picolisp and bit.ly">Shortening multiple URLs with jQuery, PHP, picolisp and bit.ly</a></li>
<li><a href="http://www.prodevtips.com/2009/08/27/adding-a-facebook-style-information-box-with-jquery/" title="Facebook style information box with jQuery">Facebook style information box with jQuery</a></li>
</ul>

<p><a href="http://feedads.g.doubleclick.net/~a/fOJ5dQtIGX4m1bYly3jppueBZV4/0/da"><img src="http://feedads.g.doubleclick.net/~a/fOJ5dQtIGX4m1bYly3jppueBZV4/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/fOJ5dQtIGX4m1bYly3jppueBZV4/1/da"><img src="http://feedads.g.doubleclick.net/~a/fOJ5dQtIGX4m1bYly3jppueBZV4/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=d04RxGZherg:Js6VPqrQrgQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=d04RxGZherg:Js6VPqrQrgQ:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=d04RxGZherg:Js6VPqrQrgQ:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=d04RxGZherg:Js6VPqrQrgQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=d04RxGZherg:Js6VPqrQrgQ:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=d04RxGZherg:Js6VPqrQrgQ:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=d04RxGZherg:Js6VPqrQrgQ:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=d04RxGZherg:Js6VPqrQrgQ:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=d04RxGZherg:Js6VPqrQrgQ:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=YwkR-u9nhCs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=d04RxGZherg:Js6VPqrQrgQ:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=d04RxGZherg:Js6VPqrQrgQ:D7DqB2pKExk" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.prodevtips.com/2010/03/07/jquery-drag-and-drop-to-sort-tree/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.prodevtips.com/2010/03/07/jquery-drag-and-drop-to-sort-tree/</feedburner:origLink></item>
		<item>
		<title>Thumb Banner Rotator in ActionScript 3</title>
		<link>http://feedproxy.google.com/~r/prodevtips/LVkG/~3/o40k1EBLEsg/</link>
		<comments>http://www.prodevtips.com/2010/02/19/thumb-banner-rotator-in-actionscript3/#comments</comments>
		<pubDate>Fri, 19 Feb 2010 11:07:43 +0000</pubDate>
		<dc:creator>Henrik</dc:creator>
		
		<category><![CDATA[Flex, Flash and AMFPHP]]></category>

		<category><![CDATA[actionscript3]]></category>

		<category><![CDATA[AS3]]></category>

		<category><![CDATA[banner]]></category>

		<category><![CDATA[flash]]></category>

		<guid isPermaLink="false">http://www.prodevtips.com/2010/02/19/thumb-banner-rotator-in-actionscript3/</guid>
		<description><![CDATA[Tutorial on how to program a thumbnail banner rotator in ActionScript 3 / AS3.]]></description>
			<content:encoded><![CDATA[<div class='series_toc'><h3><a href="#">Table of Contents for ActionScript 3 in Flash CS3</a></h3><ol><li><a href='http://www.prodevtips.com/2008/12/23/menu-and-banner-from-xml-with-as3-and-flash-cs3/' title='Menu and Banner from XML with AS3 and Flash CS3'>Menu and Banner from XML with AS3 and Flash CS3</a></li><li><a href='http://www.prodevtips.com/2008/07/28/amfphp-in-flash-cs3-with-as3-jquerypost-style/' title='AMFPHP in Flash CS3 with AS3 - jQuery.post style'>AMFPHP in Flash CS3 with AS3 - jQuery.post style</a></li><li><a href='http://www.prodevtips.com/2009/01/19/creating-help-with-flash-and-actionscript3/' title='Creating Help with Flash and ActionScript3'>Creating Help with Flash and ActionScript3</a></li><li><a href='http://www.prodevtips.com/2009/01/23/detecting-parent-page-with-as3-and-jquery-redux/' title='Detecting parent URL with AS3 and jQuery - redux'>Detecting parent URL with AS3 and jQuery - redux</a></li><li>Thumb Banner Rotator in ActionScript 3</li></ol></div> Copyright © 2010 <a href="http://www.prodevtips.com">http://www.prodevtips.com</a>. Visit the original article at <a href="http://www.prodevtips.com/2010/02/19/thumb-banner-rotator-in-actionscript3/">http://www.prodevtips.com/2010/02/19/thumb-banner-rotator-in-actionscript3/</a>.<br /><p>The goal here is to rewrite an existing thumb banner rotator that we were using at first on <a href="http://www.cardlovers.com/">Cardlovers.com, a poker community</a> (click the link or the image to see the final result). It was working OK when only loading images but something went wrong when we started loading shockwaves in it.<br />
<a href="http://www.cartoonsmart.com/" alt="Cartoonsmart Flash Tutorials" title="Cartoonsmart Flash Tutorials">
<div id="cartoonsmart" class="cartoonsmart"></div>
<p></a><br />
For some reason they wouldn&#8217;t unload properly, it could be the result of bad programming but the reason might also lie in the fact that the original is written in AS2 for player version 8.</p>
<p>Anyway the end result was that after a few rotations the banner would hog 100% of CPU, hence the decision to rewrite the whole thing from scratch using AS3. It worked, the hogging is gone, the final result can be seen on <a href="http://www.cardlovers.com">Cardlovers</a>.</p>
<p>If the discussion is a bit hard to follow here you might want to check out first of all <a href="http://www.prodevtips.com/2008/12/23/menu-and-banner-from-xml-with-as3-and-flash-cs3/">the xml flash banner tutorial</a>, the <a href="http://www.prodevtips.com/2008/10/31/flash-10-and-jquery-multi-file-uploader/">flash uploader tutorial</a> might also shed some light on how the external interface works because I will not repeat myself here.</p>
<p><a href='http://www.cardlovers.com'  title='flash_banner_rotator.png'><img src='http://www.prodevtips.com/wp-content/uploads/2010/02/flash_banner_rotator.png' alt='flash_banner_rotator.png' /></a></p>
<p><strong>Update</strong>: I just changed the behavior in <strong>switchMain</strong>(). Instead of fetching a random banner all the time only the first fetch is random, after that banners are fetched in order from top to bottom, here&#8217;s the function that manages that:</p>
<pre><code class="javascript">function getCurNum(){
	if(isNaN(this.prevMenuNum))
		return this.getRandItemNum();
	else if(this.prevMenuNum == this.menuList.length - 1)
		return 0;
	else
		return this.prevMenuNum + 1;
}</code></pre>
<p>So now you call getCurNum instead of getRandItemNum in switchMain.</p>
<p><strong>End update</strong>.</p>
<p>Let&#8217;s walk the code, first banner.fla:</p>
<pre><code class="javascript">import flash.external.*; 
import flash.net.*; 
var loader:XMLLoader = new XMLLoader(); 
var theStage = this;

loader.getXML(xmlSource, function(res){ 
	var banner = new BannerHandler(res, theStage);
});</code></pre>
<p>The XMLLoader class that is loading the configuration data is described in the above mentioned <a href="http://www.prodevtips.com/2008/12/23/menu-and-banner-from-xml-with-as3-and-flash-cs3/">flash banner tutorial</a>. And the BannerHandler class is below:</p>
<pre><code class="javascript">package{ 
    import flash.utils.*; 
    import flash.display.*; 
    import flash.text.*; 
	import flash.events.*; 
    import flash.net.*;
	import flash.geom.*;
     
    public class BannerHandler extends MovieClip{ 
         
		var bannerXml:XML;
		var menuItems:Object;
		var menuList:Array;
		var menuLoaded:Boolean;
		var p:MovieClip;
		var fCnt:Number;
		var delayTime:Number;
		var switching:Boolean;
		var prevMainLoader:String;
		var prevMenuNum:Number;
		var manualSwitch:Boolean;
		var moveMenu:Number;
		
		function BannerHandler(bannerXml:XML, p:MovieClip){
			this.bannerXml = bannerXml;
			this.menuItems = new Object();
			this.menuList = new Array();
			this.menuLoaded = false;
			this.p = p;
			this.fCnt = 0;
			this.delayTime = int(this.bannerXml.delayTime);
			this.switching = false;
			this.prevMainLoader = '';
			this.prevMenuNum = NaN;
			this.manualSwitch = false;
			this.moveMenu = 0;
			this.buildMenu();
		}</code></pre>
<p>Let&#8217;s go through the variables:</p>
<p><strong>bannerXml</strong> Is the XML structure that we load to configure the banner.</p>
<p><strong>menuItems</strong> Is an object that will map some configurations to various thumbnails in the banner.</p>
<p><strong>menuList</strong> Is an array that is mainly used to keep track of the position of a certain menu in the menu.</p>
<p><strong>menuLoaded</strong> Keeps track of whether all thumbnails have loaded or not.</p>
<p><strong>p</strong> The parent time line.</p>
<p><strong>fCnt</strong> The frame count, there might already be some global for this but some things are quicker doing manually than scouring the manual for the proper solution.</p>
<p><strong>delayTime</strong> The time in seconds that has to pass before we rotate the banner, loaded from the XML.</p>
<p><strong>switching</strong> Controls whether we are to switch banner or not.</p>
<p><strong>prevMainLoader</strong> Will keep track of the prior banner in order for us to be able to fade it out when the new one fades in.</p>
<p><strong>prevMenuNum</strong> Keeps track of the previous thumbnail that had focus, similar in functionality to prevMainLoader.</p>
<p><strong>manualSwitch</strong> If the user starts interacting with the thumbnails (menu items) we need to stop the auto rotating behavior, this is the one that does that.</p>
<p><strong>moveMenu</strong> An integer that constantly moves the menu, will be 0 most of the time. If positive we move the menu downwards, and if negative upwards; this is due to the fact that the flash coordinate system is the fourth quadrant.</p>
<p>As you can see we call <strong>buildMenu</strong>() in the constructor, let&#8217;s jump there:</p>
<pre><code class="javascript">function buildMenu(){
	var itemHeight = this.bannerXml.menuItemHeight;
	var curY = 0;
	for each (var item:XML in this.bannerXml.item){
		this.menuItems[item.thumb] = {bigUrl: item.img, loadedOk: false};
		this.menuList.push(item.thumb);
		loadMenuItem(item.thumb, curY);
		curY += int(itemHeight);
	}
	this.menuLoaded = true;
}</code></pre>
<p>We build <strong>menuItems</strong> and <strong>menuList</strong>, mainly saving the paths to the resources, these paths will later be used as ids/names for the containing movie clips. Note how easily we can access various parts of the XML structure in AS3. I lied a little above when I said that <strong>menuLoaded</strong> will keep track of whether the menu has loaded completely or not, it will simply keep track of whether the <strong>buildMenu</strong> method has been called or not.</p>
<p>Let&#8217;s move over to <strong>loadMenuItem</strong>():</p>
<pre><code class="javascript">function loadMenuItem(curUrl:String, yPos:Number){
	var pClip 		= new MenuItem();
	pClip.y			= yPos;
	p.MainMenu.addChild(pClip).name = curUrl;
	var mItem     	= new Loader(); 
	var urlReq    	= new URLRequest(curUrl); 
	mItem.load(urlReq); 
	pClip.addChild(mItem);
	mItem.contentLoaderInfo.addEventListener(Event.COMPLETE, this.menuIsLoaded); 
}</code></pre>
<p>We begin with creating <strong>pClip</strong> (abbreviation of parent movie clip, as in the parent that will contain the bitmap), note that pClip is an instance of <strong>MenuItem</strong> which in turn is an empty movie clip that has been assigned a dummy class. This can be done by right clicking the clip in the library and selecting properties.</p>
<p>MainMenu is another empty clip that has been placed on the stage, as you can see it will contain the menu items/thumbs. Next we do the whole Loader -> URLRequest -> Event.COMPLETE routine in order to load the thumbnail jpeg correctly.</p>
<p>Let&#8217;s take a look at the callback <strong>menuIsLoaded</strong>():</p>
<pre><code class="javascript">function menuIsLoaded(event:Event){
	
	var pClip = event.target.loader.parent;
	
	pClip.addEventListener(MouseEvent.ROLL_OVER, this.mouseOverHandler);
	pClip.addEventListener(MouseEvent.ROLL_OUT, this.mouseOutHandler);
	pClip.addEventListener(MouseEvent.CLICK, this.menuClick);
	
	pClip.alpha = 0.7;
	this.menuItems[pClip.name].loadedOk = true;
	
	if(this.menuLoaded == false)
		return false;
	for each (var item:XML in this.bannerXml.item){
		if(this.menuItems[item.thumb].loadedOk == false)
			return false;
	}
	
	this.p.addEventListener(Event.ENTER_FRAME, this.everyFrame);
	this.p.addEventListener(MouseEvent.MOUSE_MOVE, this.mouseMoveHandler);
}</code></pre>
<p>So after the graphic has loaded we assign various callbacks to the parent and the stage, as you can see the stage stuff won&#8217;t happen though until all the menu items/thumbs have loaded. Anyway the callbacks are:</p>
<p><strong>mouseOverHandler</strong> Controls what happens to a menu item when the cursor enters its area.</p>
<p><strong>mouseOutHandler</strong> Controls what happens to a menu item when the mouse cursor leaves its area.</p>
<p><strong>menuClick</strong> Controls what happens when a menu item is clicked.</p>
<p><strong>everyFrame</strong> This is the main loop which will not start until the whole menu has loaded.</p>
<p><strong>mouseMoveHandler</strong> This one checks whether the mouse cursor is in certain areas and will initiate menu movement if need be (more on that later).</p>
<p>Lets begin with the main loop, <strong>everyFrame</strong>():</p>
<pre><code class="javascript">function globalY(clip){
	var tPoint = new Point(clip.x, clip.y);
	var gPoint = clip.localToGlobal(tPoint);
	return gPoint.y;
}

function switchMain(){
	if(this.getSecs() % this.delayTime == 0 &amp;&amp; this.switching == false){
		var curNum = this.getRandItemNum();
		var bigUrl = this.getItemConf(curNum).bigUrl;
		
		var curItem = this.getItem(curNum);
		curItem.addEventListener(Event.ENTER_FRAME, this.menuFadeIn);
		if(this.globalY(curItem) + curItem.height &gt; 275)
			this.moveMenu = -3;
		else if(this.globalY(curItem) &lt; 0)
			this.moveMenu = 3;
		else
			this.moveMenu = 0;
			
		this.fadeOutOthers(curItem);
		
		this.loadMainPic(bigUrl);
		this.switching = true;
		this.prevMenuNum = curNum;
	}else if(this.getSecs() % this.delayTime != 0)
		this.switching = false;
}

function everyFrame(event:Event){
	this.moveMenuHandler();
	if(this.manualSwitch == false)
		switchMain();
	this.fCnt++;
}</code></pre>
<p>We move the menu, rotate banners if the manual switching mode is off and increase the frame count.</p>
<p>If manual switching mode is off we:</p>
<p>1.) Check whether it&#8217;s actually time to switch or not, and if it is:</p>
<p>2.)   We get the number of the menu item to switch to in a random fashion, well not completely, two in a row is not possible, it would look stupid.</p>
<p>3.)   We get the url of the banner to load with the help of the menu item number.</p>
<p>4.)   We get the menu item in question and fade it in by applying the menuFadeIn method as its enter frame callback.</p>
<p>5.)   Next we check the global y position of the menu item in question, if it&#8217;s outside of the stage the menu will move enough up or down in order to show it.</p>
<p>6.)   We fade out all other menu items and load the banner which has been mapped to the current menu item.</p>
<p>7.)   Since we can&#8217;t switch right away; we have to wait for the stipulated delay time as it has been specified in the XML file we will set the switching variable to true to disable rotation for now.</p>
<p>1.5.) If it&#8217;s not time to switch we simply check if it is time to start rotating and if it is we set switching to false in order to enable rotation.</p>
<p>Let&#8217;s get back to the other callbacks:</p>
<pre><code class="javascript">function mouseOverHandler(event:MouseEvent){
	var clip = event.target;
	clip.alpha = 1;
	clip.transform.colorTransform =  this.setColor(clip.transform.colorTransform, 0.5);
}

function mouseOutHandler(event:MouseEvent){
	var clip = event.target;
	clip.alpha = 0.7;
	clip.transform.colorTransform =  this.setColor(clip.transform.colorTransform, -0.5);
}

function menuClick(event:MouseEvent){
	this.loadMainPic( this.menuItems[ event.currentTarget.name ].bigUrl );
}

function mouseMoveHandler(event:MouseEvent){
	var xpos = event.stageX;
	var ypos = event.stageY;
	var menu = this.p.MainMenu;
	if(xpos &lt; 150 &amp;&amp; ypos &lt; 50 &amp;&amp; menu.y &lt; 0)
		this.moveMenu = 2;
	else if(xpos &lt; 150 &amp;&amp; ypos &gt; (274 - 50) &amp;&amp; !this.menuCheckUp(menu))
		this.moveMenu = -2;
	else if(xpos &lt; 150){
		this.manualSwitch = true;
		this.moveMenu = 0;
	}else{
		this.manualSwitch = false;
		this.moveMenu = 0;
	}
}

function setColor(colTr, val){
	colTr.greenMultiplier += val;
	colTr.redMultiplier += val;
	colTr.blueMultiplier += val;
	return colTr;
}</code></pre>
<p>When we roll over a menu item we set the alpha to 1 and increase all color multipliers in order to make the menu lighter overall, mouseOutHandler will of course do the reverse, menuClick will load the &#8220;attached&#8221; banner.</p>
<p>The mouse move handler is the real biggie in this neighborhood. We basically check if the mouse pointer is in the top left or bottom left corner, if top then we move the menu down, if bottom we move it up. Note also the manual switch, we don&#8217;t want the &#8220;slideshow&#8221; to go on at the same time so we turn it of by way of <strong>manualSwitch</strong>.</p>
<p>Over to the banner loading part:</p>
<pre><code class="javascript">function getClip(nm:String){
	return this.p.MainImage.getChildByName(nm);
}

function loadMainPic(curUrl:String){
	
	if(this.prevMainLoader != '')
		this.getClip(this.prevMainLoader).addEventListener(Event.ENTER_FRAME, this.fadeOutHandler);
	
	var pClip 		= new MenuItem();

	p.MainImage.addChild(pClip).name = curUrl;
		
	var mItem     	= new Loader();
	mItem.alpha 	= 0;
	var urlReq    	= new URLRequest(curUrl);
	mItem.load(urlReq); 
	
	this.prevMainLoader = curUrl;
	pClip.addChild(mItem);
	pClip.addEventListener(MouseEvent.CLICK, this.mainClick);
	mItem.contentLoaderInfo.addEventListener(Event.COMPLETE, this.imageIsLoaded); 
}

function mainClick(event:MouseEvent){
	for each (var item:XML in this.bannerXml.item){
		if(item.img == event.currentTarget.name){
			navigateToURL(new URLRequest(item.imgLink), item.imgLinkTarget);
			return;
		}
	}
}</code></pre>
<p>This is a kind of synthesis of loadMenuItem and switchMain for the thumbs, but now we do the banners instead.</p>
<p>1.) We fade out the old banner.</p>
<p>2.) We add the parent clip to the MainImage clip (another static clip, just like MainMenu).</p>
<p>3.) We initiate the loader and set its alpha to 0.</p>
<p>4.) We add a mouse click event handler in order to go to jump to predefined URLs (from the XML).</p>
<p>5.) We ad the load complete handler in order to fade in the banner after it has finished loading.</p>
<p>At last some less important leftovers, I&#8217;ll leave it up to you to figure out where they are called in the code listings above and what they are doing.</p>
<pre><code class="javascript">function fadeInHandler(event:Event):void{ 
  event.currentTarget.alpha += 0.05;
  if(event.currentTarget.alpha &gt;= 1)
	event.currentTarget.removeEventListener(Event.ENTER_FRAME, this.fadeInHandler);
  
}

function fadeOutHandler(event:Event):void{
	var clip = event.currentTarget;
	clip.alpha -= 0.05;
	if(clip.alpha &lt;= 0){
		clip.removeEventListener(Event.ENTER_FRAME, this.fadeOutHandler);
		p.MainImage.removeChild(clip);
	}
}

function imageIsLoaded(event:Event){
	event.target.loader.addEventListener(Event.ENTER_FRAME, this.fadeInHandler);
}

function menuFadeIn(event:Event):void{
  var clip = event.currentTarget;
  clip.transform.colorTransform =  this.setColor(clip.transform.colorTransform, 0.05);
	
  clip.alpha += 0.05;
  if(clip.alpha &gt;= 1)
	clip.removeEventListener(Event.ENTER_FRAME, this.menuFadeIn);
  
}

function menuFadeOut(event:Event):void{
	var clip = event.currentTarget;
	if(clip.alpha &lt;= 0.7){
		clip.alpha = 0.7;
		clip.removeEventListener(Event.ENTER_FRAME, this.menuFadeOut);
	}else{
		clip.transform.colorTransform =  this.setColor(clip.transform.colorTransform, -0.05);
		clip.alpha -= 0.05;
	}
}

function fadeOutOthers(curClip){
	for(var i = 0; i &lt; this.menuList.length; i++){
		var tClip = this.getItem(i);
		if(tClip != curClip)
			tClip.addEventListener(Event.ENTER_FRAME, this.menuFadeOut);
	}
}

function getRandItemNum(){
	var num = Math.round(Math.random() * (this.menuList.length - 1));
	if(num == this.prevMenuNum)
		return this.getRandItemNum();
	else
		return num;
}

function menuCheckUp(menu){
	return menu.y + menu.height &lt;= 274;
}

function moveMenuHandler(){
	var menu = this.p.MainMenu;
	if(this.menuCheckUp(menu) &amp;&amp; this.moveMenu &lt; 0)
		this.moveMenu = 0;
	else if(menu.y &gt;= 0 &amp;&amp; this.moveMenu &gt; 0)
		this.moveMenu = 0;
	else
		menu.y += this.moveMenu;
}

function getSecs(){
	return Math.round(this.fCnt / this.p.MainMenu.stage.frameRate);
}

function getItem(num){
	return this.p.MainMenu.getChildByName( this.menuList[ num ] );
}

function getItemConf(num){
	return this.menuItems[ this.menuList[ num ] ];
}</code></pre>
<p></script><br />
    <script type="text/javascript"><!--
      google_ad_client = "pub-4780703337538969";
      google_alternate_color = "dedcdc";
      google_ad_width = 728;
      google_ad_height = 90;
      google_ad_format = "728x90_as";
      google_ad_type = "text_image";
      google_color_border = "dedcdc";
      google_color_link = "993333";
      google_color_bg = "dedcdc";
      google_color_text = "000000";
      google_color_url = "003366";
      //-->
   </script><br />
  <script type="text/javascript"
    src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
  </script></p>
<p><script type="text/javascript" src="http://www.prodevtips.com/jquery.flash.js"></script><br />
<script type="text/javascript"> 
$(document).ready(function(){  
  $("#cartoonsmart").flash({  
    src: "http://www.prodevtips.com/cartoonsmart.swf",  
    width: 250,  
    height: 250,
    wmode: "transparent"
  });
  $("#cartoonsmart").attr("class", "cartoonsmart"); 
}); 
  </script><br />
<h3>Related Posts</h3>
<ul class="related_post">
<li><a href="http://www.prodevtips.com/2009/01/19/creating-help-with-flash-and-actionscript3/" title="Creating Help with Flash and ActionScript3">Creating Help with Flash and ActionScript3</a></li>
<li><a href="http://www.prodevtips.com/2008/12/23/menu-and-banner-from-xml-with-as3-and-flash-cs3/" title="Menu and Banner from XML with AS3 and Flash CS3">Menu and Banner from XML with AS3 and Flash CS3</a></li>
<li><a href="http://www.prodevtips.com/2009/09/19/simple-timeline-graph-with-prefuse-flare/" title="Simple timeline graph with Prefuse Flare">Simple timeline graph with Prefuse Flare</a></li>
<li><a href="http://www.prodevtips.com/2009/01/23/detecting-parent-page-with-as3-and-jquery-redux/" title="Detecting parent URL with AS3 and jQuery - redux">Detecting parent URL with AS3 and jQuery - redux</a></li>
<li><a href="http://www.prodevtips.com/2008/07/28/amfphp-in-flash-cs3-with-as3-jquerypost-style/" title="AMFPHP in Flash CS3 with AS3 - jQuery.post style">AMFPHP in Flash CS3 with AS3 - jQuery.post style</a></li>
</ul>
 <div class='series_links'><a href='http://www.prodevtips.com/2009/01/23/detecting-parent-page-with-as3-and-jquery-redux/' title='Detecting parent URL with AS3 and jQuery - redux'>Previous in series</a> </div>
<p><a href="http://feedads.g.doubleclick.net/~a/QGKyBXJuzSK5qtcAmzPsdheJO-Q/0/da"><img src="http://feedads.g.doubleclick.net/~a/QGKyBXJuzSK5qtcAmzPsdheJO-Q/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/QGKyBXJuzSK5qtcAmzPsdheJO-Q/1/da"><img src="http://feedads.g.doubleclick.net/~a/QGKyBXJuzSK5qtcAmzPsdheJO-Q/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=o40k1EBLEsg:VOKGsoPGESA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=o40k1EBLEsg:VOKGsoPGESA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=o40k1EBLEsg:VOKGsoPGESA:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=o40k1EBLEsg:VOKGsoPGESA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=o40k1EBLEsg:VOKGsoPGESA:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=o40k1EBLEsg:VOKGsoPGESA:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=o40k1EBLEsg:VOKGsoPGESA:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=o40k1EBLEsg:VOKGsoPGESA:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=o40k1EBLEsg:VOKGsoPGESA:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=YwkR-u9nhCs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=o40k1EBLEsg:VOKGsoPGESA:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=o40k1EBLEsg:VOKGsoPGESA:D7DqB2pKExk" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.prodevtips.com/2010/02/19/thumb-banner-rotator-in-actionscript3/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.prodevtips.com/2010/02/19/thumb-banner-rotator-in-actionscript3/</feedburner:origLink></item>
		<item>
		<title>Logitech MX 1100 Cordless Laser Mouse review</title>
		<link>http://feedproxy.google.com/~r/prodevtips/LVkG/~3/GLwoOoMuOJA/</link>
		<comments>http://www.prodevtips.com/2010/02/15/logitech-mx-1100-cordless-laser-mouse-review/#comments</comments>
		<pubDate>Mon, 15 Feb 2010 13:35:04 +0000</pubDate>
		<dc:creator>Henrik</dc:creator>
		
		<category><![CDATA[Hardware]]></category>

		<category><![CDATA[Reviews]]></category>

		<category><![CDATA[logitech]]></category>

		<category><![CDATA[mx 1100]]></category>

		<category><![CDATA[nano vx]]></category>

		<category><![CDATA[v550]]></category>

		<guid isPermaLink="false">http://www.prodevtips.com/2010/02/15/logitech-mx-1100-cordless-laser-mouse-review/</guid>
		<description><![CDATA[Copyright © 2010 http://www.prodevtips.com. Visit the original article at http://www.prodevtips.com/2010/02/15/logitech-mx-1100-cordless-laser-mouse-review/.





So I just got my new MX 1100 and I think it&#8217;s a great mouse, the only gripe I have with it is that it isn&#8217;t laptop friendly. That however is not Logitech&#8217;s fault. It would simply be great if there was a model that looked [...]]]></description>
			<content:encoded><![CDATA[Copyright © 2010 <a href="http://www.prodevtips.com">http://www.prodevtips.com</a>. Visit the original article at <a href="http://www.prodevtips.com/2010/02/15/logitech-mx-1100-cordless-laser-mouse-review/">http://www.prodevtips.com/2010/02/15/logitech-mx-1100-cordless-laser-mouse-review/</a>.<br /><div class="image_right">
<iframe src="http://rcm.amazon.com/e/cm?t=pro01-20&#038;o=1&#038;p=8&#038;l=as1&#038;asins=B001DJ64C0&#038;fc1=000000&#038;IS2=1&#038;lt1=_blank&#038;m=amazon&#038;lc1=0000FF&#038;bc1=000000&#038;bg1=FFFFFF&#038;f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe>
</div>
<div style="float:left;">
<iframe src="http://rcm.amazon.com/e/cm?t=pro01-20&#038;o=1&#038;p=8&#038;l=as1&#038;asins=B000U75V02&#038;fc1=000000&#038;IS2=1&#038;lt1=_blank&#038;m=amazon&#038;lc1=0000FF&#038;bc1=000000&#038;bg1=FFFFFF&#038;f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe>
</div>
<p>So I just got my new <a href="http://www.amazon.com/dp/B001DJ64C0?tag=pro01-20&#038;camp=14573&#038;creative=327641&#038;linkCode=as1&#038;creativeASIN=B001DJ64C0&#038;adid=0MCCNJZWSVPAWHASB04Y&#038;">MX 1100</a> and I think it&#8217;s a great mouse, the only gripe I have with it is that it isn&#8217;t laptop friendly. That however is not Logitech&#8217;s fault. It would simply be great if there was a model that looked and felt like the MX 1100 but had the mini USB reciever and laptop snapping ability.</p>
<p>For you who are unfamiliar with this terminology the mini receiver is super small and you simply put it into a USB port and forget about it. Due to its minimal size you will never have to fear that it will break the port if/when the machine is handled roughly during transport. To get the mouse to snap to your laptop lid you glue a small spike to the lid which the mouse can latch on to through a small construction on its underside.</p>
<p>My love affair with Logitech started when I had my dad simply buy me a random mouse on his way back from work one day. He bought the <a href="http://www.amazon.com/dp/B001DJ7Y2O?tag=pro01-20&#038;camp=14573&#038;creative=327641&#038;linkCode=as1&#038;creativeASIN=B001DJ7Y2O&#038;adid=02J23ZQTDS94TN1KXCNH&#038;">Logitech V550</a> which has the features mentioned above; it also has the free spinning scroll wheel which I instantly came to love. Due to the fact that the wheel spins freely you simply flip it and it will scroll through huge documents without having to touch it again. It&#8217;s a massive time and energy saver whose lack of I consider to be a deal breaker for a mouse.</p>
<div class="image_right">
<iframe src="http://rcm.amazon.com/e/cm?t=pro01-20&#038;o=1&#038;p=8&#038;l=as1&#038;asins=B001DJ7Y2O&#038;fc1=000000&#038;IS2=1&#038;lt1=_blank&#038;m=amazon&#038;lc1=0000FF&#038;bc1=000000&#038;bg1=FFFFFF&#038;f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe>
</div>
<p>So what prompted me to buy the MX 1100 is the fact that it has more buttons than 2 (this is what the V550 has), I need more buttons than 2 so I can program them to do various things in different applications. The MX 1100 is also bigger and more ergonomical. However in hindsight given the importance of the mini USB and snapping I wish I had bought the <a href="http://www.amazon.com/dp/B000U75V02?tag=pro01-20&#038;camp=14573&#038;creative=327641&#038;linkCode=as1&#038;creativeASIN=B000U75V02&#038;adid=13ESY0P3JWSV0H708CFK&#038;">Logitech VX Nano</a> instead. It also has two extra buttons and a free spinning wheel plus the mini USB and the snapping ability.</p>
<p>The only thing the VX Nano doesn&#8217;t have that the MX 1100 has is the ergonomics, comfortable size and the ability to adjust pointer sensitivity <strong>on the mouse itself</strong>. However I can live without those two.<br />
<h3>Most Popular Posts</h3>
<ul class="related_post">
<li><a href="http://www.prodevtips.com/2007/10/18/joomla-advanced-registration/" title="Joomla 1.5 Extended Registration">Joomla 1.5 Extended Registration</a></li>
<li><a href="http://www.prodevtips.com/2008/01/29/sorting-with-jquery-sortable/" title="Sorting with jQuery sortable">Sorting with jQuery sortable</a></li>
<li><a href="http://www.prodevtips.com/2007/10/24/joomla-template-design-with-yaml/" title="Joomla 1.5 template design with YAML CSS Framework">Joomla 1.5 template design with YAML CSS Framework</a></li>
<li><a href="http://www.prodevtips.com/2008/02/13/jquery-grid-edit-in-place-with-ajax/" title="Grid edit in place with jQuery and Ajax">Grid edit in place with jQuery and Ajax</a></li>
<li><a href="http://www.prodevtips.com/2008/03/16/modx-and-yaml-from-zero-to-finished-site/" title="MODx and YAML - from zero to finished site">MODx and YAML - from zero to finished site</a></li>
</ul>

<p><a href="http://feedads.g.doubleclick.net/~a/bZugUsxBLBvHiuSeIxu10aZIKtk/0/da"><img src="http://feedads.g.doubleclick.net/~a/bZugUsxBLBvHiuSeIxu10aZIKtk/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/bZugUsxBLBvHiuSeIxu10aZIKtk/1/da"><img src="http://feedads.g.doubleclick.net/~a/bZugUsxBLBvHiuSeIxu10aZIKtk/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=GLwoOoMuOJA:I0T0wsdztiQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=GLwoOoMuOJA:I0T0wsdztiQ:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=GLwoOoMuOJA:I0T0wsdztiQ:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=GLwoOoMuOJA:I0T0wsdztiQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=GLwoOoMuOJA:I0T0wsdztiQ:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=GLwoOoMuOJA:I0T0wsdztiQ:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=GLwoOoMuOJA:I0T0wsdztiQ:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=GLwoOoMuOJA:I0T0wsdztiQ:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=GLwoOoMuOJA:I0T0wsdztiQ:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=YwkR-u9nhCs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=GLwoOoMuOJA:I0T0wsdztiQ:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=GLwoOoMuOJA:I0T0wsdztiQ:D7DqB2pKExk" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.prodevtips.com/2010/02/15/logitech-mx-1100-cordless-laser-mouse-review/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.prodevtips.com/2010/02/15/logitech-mx-1100-cordless-laser-mouse-review/</feedburner:origLink></item>
		<item>
		<title>Memcached in PHP on Dapper</title>
		<link>http://feedproxy.google.com/~r/prodevtips/LVkG/~3/dS6SNzshjbg/</link>
		<comments>http://www.prodevtips.com/2010/02/08/memcached-in-php-on-dapper/#comments</comments>
		<pubDate>Mon, 08 Feb 2010 17:36:54 +0000</pubDate>
		<dc:creator>Henrik</dc:creator>
		
		<category><![CDATA[Database]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[memcache]]></category>

		<category><![CDATA[memcached]]></category>

		<guid isPermaLink="false">http://www.prodevtips.com/2010/02/08/memcached-in-php-on-dapper/</guid>
		<description><![CDATA[Copyright © 2010 http://www.prodevtips.com. Visit the original article at http://www.prodevtips.com/2010/02/08/memcached-in-php-on-dapper/.What is Memcached and what is it good for?


   
  
  

Memcached is a very simple thing at heart; a daemon that runs in the background and that can be called from your code to store a value with the help of [...]]]></description>
			<content:encoded><![CDATA[Copyright © 2010 <a href="http://www.prodevtips.com">http://www.prodevtips.com</a>. Visit the original article at <a href="http://www.prodevtips.com/2010/02/08/memcached-in-php-on-dapper/">http://www.prodevtips.com/2010/02/08/memcached-in-php-on-dapper/</a>.<br /><p><strong>What is Memcached and what is it good for?</strong></p>
<div class="image_right">
<script type="text/javascript"><!--
      google_ad_client = "pub-4780703337538969";
      google_alternate_color = "dedcdc";
      google_ad_width = 250;
      google_ad_height = 250;
      google_ad_format = "250x250_as";
      google_ad_type = "text_image";
      google_color_border = "dedcdc";
      google_color_link = "993333";
      google_color_bg = "dedcdc";
      google_color_text = "000000";
      google_color_url = "003366";
      //-->
   </script><br />
  <script type="text/javascript"
    src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
  </script>
</div>
<p>Memcached is a very simple thing at heart; a daemon that runs in the background and that can be called from your code to store a value with the help of a key, and then retrieve said value with the help of the key used to store it; and it all happens in the RAM.</p>
<p>Since you can connect to Memcached from anywhere it&#8217;s easy to imagine scaling a system up by way of having separate parts being cached on different machines.</p>
<p><strong>Installation</strong></p>
<p>What a nightmare getting Memcached up and running on an old Dapper system. Simply doing <strong>apt-get install memcached</strong> (worked on Jaunty though) wouldn&#8217;t do it for me, apt-get complained about libevent1 as a dependency.</p>
<p>Luckily for me Memcached doesn&#8217;t depend on any other lib and whatever libs libevent needs (if any) were already installed.</p>
<p>Here is my command history:</p>
<pre><code>wget http://www.monkey.org/~provos/libevent-1.4.13-stable.tar.gz
tar -xzvf libevent-1.4.13-stable.tar.gz
cd libevent-1.4.13-stable
./configure
make
make install
wget http://memcached.googlecode.com/files/memcached-1.4.4.tar.gz
tar -xzvf memcached-1.4.4.tar.gz
./configure
make
make install
nano /etc/ld.so.conf (and adding /usr/local/lib to it)
ldconfig
/usr/local/bin/memcached -d -m 512 -l localhost -p 11211 -u root
pecl install memcache</code></pre>
<div class="image_right">
<script type="text/javascript"><!--
      google_ad_client = "pub-4780703337538969";
      google_alternate_color = "dedcdc";
      google_ad_width = 250;
      google_ad_height = 250;
      google_ad_format = "250x250_as";
      google_ad_type = "text_image";
      google_color_border = "dedcdc";
      google_color_link = "993333";
      google_color_bg = "dedcdc";
      google_color_text = "000000";
      google_color_url = "003366";
      //-->
   </script><br />
  <script type="text/javascript"
    src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
  </script>
</div>
<p>The ld.so.conf stuff is needed for Memcached to find the libevent library during runtime.</p>
<p>If the last pecl install line fails you probably need the same stuff you need in order to <a href="http://www.prodevtips.com/2009/03/30/compiling-php-529-on-ubuntu/">compile PHP</a>.</p>
<p>Note that there is a newer fancier pecl module called memcached, <strong>pecl install memcached</strong> will therefore also work. However I couldn&#8217;t find any proper usage documentation for that one so I went with the older one. Don&#8217;t forget to edit <strong>php.ini</strong>!</p>
<p>The second last line will start Memcached and have it use 500MB RAM.</p>
<p><strong>Implementation</strong></p>
<p>My Memchache class is based on <a href="http://abhinavsingh.com/blog/2009/01/memcached-and-n-things-you-can-do-with-it/">Abhinav Singh&#8217;s Memcache class</a>. You should read his article, it&#8217;s a good one, especially at the end where you get a few other scenarios where Memcache can make your dev life easier in addition to speeding up your site.</p>
<p><strong>Update</strong>: I&#8217;ve changed the original key encoding from base64_encode (like Abhinav has) to md5, base64_encode just wouldn&#8217;t work, neither is serialization needed (which he is also doing). I still recommend the end of his article though. </p>
<pre><code class="php">class Mcache extends PhModule{
	
	function __construct() {
		$this-&gt;con = new Memcache;
		$this-&gt;host = 'localhost';
		$this-&gt;port = 11211;
		$this-&gt;connect();	
	}
	
	function connect() {    
	   if($this-&gt;con-&gt;connect($this-&gt;host, $this-&gt;port))
	     return true;  
	   else{ 
	   	trigger_error("Could not connect to Memcached daemon.");
	     return false;
	   }
	}

	function flush(){
		$this-&gt;con-&gt;flush();
	}
	
	function close() { 
	   if($this-&gt;con-&gt;close())
	     return true;  
	   else
	     return false;
	}

	function query($query){
		$result = $this-&gt;getCache($query);
		if(empty($result)){
			phive()-&gt;sql()-&gt;query($q);
			$result = phive()-&gt;sql()-&gt;result();
			$this-&gt;setCache($query, $result);	
		}
		return $result;
	}
	
	function getCache($query) {
		$key = md5($query);  
		$resultset = $this-&gt;con-&gt;get($key);
		if($resultset != null)  
	 		return $resultset;  
		else
			return false;
	}
	
	function setCache($query, $resultset, $useCompression = 0, $ttl = 600){
	    $key = md5($query);   
	    if($this-&gt;con-&gt;set($key, $resultset, $useCompression, $ttl))
	      return true;  
	    else
	      return false;  
	}  
}</code></pre>
<p>As you can see here the SQL class and the Memcache class are completely separate, no caching happens per default. If I would simply have my SQL class cache every result all the time it would result in too much cache purging and writing, ie. 500MB RAM wouldn&#8217;t last long which defeats the whole purpose of Memcached.</p>
<p>Here is an example of the class in action:</p>
<pre><code class="php">public function getFailedLoginsLastDay(){
	$sql = $this-&gt;getModule('SQL');
	$table = $this-&gt;getSetting('db_activity');
	$ip = $_SERVER['REMOTE_ADDR'];
	
	$q = "SELECT COUNT(*) FROM `$table` WHERE `ipaddress`={$sql-&gt;escape($ip)} AND
		`code`=".ACTIVITY_LOGIN_FAIL." AND `timestamp` &gt; DATE_SUB(CURDATE(),INTERVAL 1 DAY)";
	
	if(phive()-&gt;moduleExists('Mcache'))
		return phive()-&gt;getModule('Mcache')-&gt;query($q);
	else{
		$sql-&gt;query($q);
		return $sql-&gt;result();
	}
	
	$sql-&gt;query($q);
	return $sql-&gt;result();
}</code></pre>
<p>The above query took 0.3 seconds, which is now reduced to virtually nothing. </p>
<p>Note: If you want your site to be perfectly responsive you will need to clear all or parts of the cache when something new happens, otherwise you will end up serving hour(s) (if that is your automatic flush frequency) old content. That is of course done with the <strong>flush()</strong> method above. </p>
<p>Currently I&#8217;m caching a forum so as soon as someone creates a new thread or post I flush the whole cache, this indiscriminate behavior results in a lot of cache clearing which of course isn&#8217;t ideal but it&#8217;s the best I could do on short notice; it&#8217;s OK as long as the action on the forum doesn&#8217;t get too frequent, which it isn&#8217;t yet.<br />
<h3>Related Posts</h3>
<ul class="related_post">
<li><a href="http://www.prodevtips.com/2010/01/29/foreign-relations-with-jquery-php/" title="Foreign relations with jQuery / PHP">Foreign relations with jQuery / PHP</a></li>
<li><a href="http://www.prodevtips.com/2010/01/10/simple-jquery-and-php-crud-interface/" title="The basic C(R)UD">The basic C(R)UD</a></li>
<li><a href="http://www.prodevtips.com/2009/12/09/multiple-select-lists-with-jquery-and-json/" title="Multiple select lists with jQuery and JSON">Multiple select lists with jQuery and JSON</a></li>
<li><a href="http://www.prodevtips.com/2009/12/05/shortening-multiple-urls-with-jquery-php-picolisp-and-bitly/" title="Shortening multiple URLs with jQuery, PHP, picolisp and bit.ly">Shortening multiple URLs with jQuery, PHP, picolisp and bit.ly</a></li>
<li><a href="http://www.prodevtips.com/2009/11/27/solving-memory-limit-exhausted-in-php/" title="Solving memory limit exhausted in PHP">Solving memory limit exhausted in PHP</a></li>
</ul>

<p><a href="http://feedads.g.doubleclick.net/~a/V9wl_DO5OO2v2-GTHXuDldTfg3M/0/da"><img src="http://feedads.g.doubleclick.net/~a/V9wl_DO5OO2v2-GTHXuDldTfg3M/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/V9wl_DO5OO2v2-GTHXuDldTfg3M/1/da"><img src="http://feedads.g.doubleclick.net/~a/V9wl_DO5OO2v2-GTHXuDldTfg3M/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=dS6SNzshjbg:MkJvriDyGCk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=dS6SNzshjbg:MkJvriDyGCk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=dS6SNzshjbg:MkJvriDyGCk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=dS6SNzshjbg:MkJvriDyGCk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=dS6SNzshjbg:MkJvriDyGCk:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=dS6SNzshjbg:MkJvriDyGCk:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=dS6SNzshjbg:MkJvriDyGCk:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=dS6SNzshjbg:MkJvriDyGCk:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=dS6SNzshjbg:MkJvriDyGCk:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=YwkR-u9nhCs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=dS6SNzshjbg:MkJvriDyGCk:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=dS6SNzshjbg:MkJvriDyGCk:D7DqB2pKExk" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.prodevtips.com/2010/02/08/memcached-in-php-on-dapper/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.prodevtips.com/2010/02/08/memcached-in-php-on-dapper/</feedburner:origLink></item>
		<item>
		<title>Foreign relations with jQuery / PHP</title>
		<link>http://feedproxy.google.com/~r/prodevtips/LVkG/~3/zFx69jxxCOE/</link>
		<comments>http://www.prodevtips.com/2010/01/29/foreign-relations-with-jquery-php/#comments</comments>
		<pubDate>Fri, 29 Jan 2010 07:46:07 +0000</pubDate>
		<dc:creator>Henrik</dc:creator>
		
		<category><![CDATA[Ajax]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[jQuery]]></category>

		<category><![CDATA[jquery]]></category>

		<guid isPermaLink="false">http://www.prodevtips.com/2010/01/29/foreign-relations-with-jquery-php/</guid>
		<description><![CDATA[Tutorial on how to manage foreign relations in an Ajax powered CRUD interface.]]></description>
			<content:encoded><![CDATA[<div class='series_toc'><h3><a href="#">Table of Contents for Simple jQuery and PHP CRUD interface</a></h3><ol><li><a href='http://www.prodevtips.com/2010/01/10/simple-jquery-and-php-crud-interface/' title='The basic C(R)UD'>The basic C(R)UD</a></li><li>Foreign relations with jQuery / PHP</li></ol></div> Copyright © 2010 <a href="http://www.prodevtips.com">http://www.prodevtips.com</a>. Visit the original article at <a href="http://www.prodevtips.com/2010/01/29/foreign-relations-with-jquery-php/">http://www.prodevtips.com/2010/01/29/foreign-relations-with-jquery-php/</a>.<br /><div class="image_right">
<a href='http://www.prodevtips.com/wp-content/uploads/2010/01/jquery_crud_foreign.png' title='jquery_crud_foreign.png'><img src='http://www.prodevtips.com/wp-content/uploads/2010/01/jquery_crud_foreign.thumbnail.png' alt='jquery_crud_foreign.png' /></a>
</div>
<p>Well that didn&#8217;t take long, unsurprisingly. I needed the interface to handle foreign relations, for this I would&#8217;ve liked to use conventions, for instance that all primary autoincrementing keys be named <strong>id</strong>. However the legacy database I&#8217;m working with won&#8217;t allow that, so we need configuration:</p>
<pre><code class="php">$this-&gt;foreign = array(
	'user_id' =&gt; array(
		'table' =&gt; 'users', 
		'label' =&gt; 'username', 
		'fid' 	=&gt; 'user_id'
	)
);

function foreignAttr($col_name){
	if(!empty($this-&gt;foreign[ $col_name ]))
		echo "foreign=\"$col_name\"";
}</code></pre>
<div class="image_right">
    <script type="text/javascript"><!--
      google_ad_client = "pub-4780703337538969";
      google_alternate_color = "dedcdc";
      google_ad_width = 234;
      google_ad_height = 60;
      google_ad_format = "234x60_as";
      google_ad_type = "text_image";
      google_color_border = "dedcdc";
      google_color_link = "993333";
      google_color_bg = "dedcdc";
      google_color_text = "000000";
      google_color_url = "003366";
      //-->
   </script><br />
  <script type="text/javascript"
    src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
  </script>
</div>
<p>The above will be used soon enough to get at the functionality we need. The foreign relation in this case is the user table (users) which is referenced through <strong>user_id</strong> which is also the name of its unique id column. The current table is user_points which will hold point entries containing the amount of points and a date when they were inserted.</p>
<p>The HTML has been slightly adjusted, we now add our own custom <strong>foreign</strong> attribute (using the above <strong>foreignAttr</strong> method):</p>
<pre><code class="html">&lt;input class="add_input" &lt;?php $this-&gt;foreignAttr( $row-&gt;Field ) ?&gt; type="text" name="&lt;?php echo $row-&gt;Field ?&gt;"/&gt;</code></pre>
<p>Let&#8217;s move on to the jQuery:</p>
<pre><code class="javascript">$("#add_form").find("input").keydown(function(event){

	var cur =  $(this);

	if(cur.attr('foreign').length &gt; 0){
		
		if($("#el_list").length == 0){
			cur.after('&lt;select id="el_list"&gt;&lt;/select&gt;');
			$("#el_list").blur(function(){
				var cur_id = $(this).find("option:selected").val();
				cur.val( cur_id );
				$(this).remove();
			});
		}
		
		if(cur.val().length &gt;= 2){
			$.post(window.location.href, {value: cur.val(), func: 'getForeignList', fkey: cur.attr('foreign')}, function(res){
				res = eval( '(' + res + ')' );
				var str = '';
				$.each(res, function(){
					str += '&lt;option value="'+this.el_id+'"&gt;'
					+ this.el_label 
					+ '&lt;/option&gt;';
				});
				$("#el_list").html(str);
			});
		}

	}
});</code></pre>
<div class="image_right">
    <script type="text/javascript"><!--
      google_ad_client = "pub-4780703337538969";
      google_alternate_color = "dedcdc";
      google_ad_width = 234;
      google_ad_height = 60;
      google_ad_format = "234x60_as";
      google_ad_type = "text_image";
      google_color_border = "dedcdc";
      google_color_link = "993333";
      google_color_bg = "dedcdc";
      google_color_text = "000000";
      google_color_url = "003366";
      //-->
   </script><br />
  <script type="text/javascript"
    src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
  </script>
</div>
<p>We are:</p>
<p>1.) Checking for all key presses in input boxes in the form with id <strong>add_form</strong>.</p>
<p>2.) Checking to se if we have the foreign attribute detailed above.</p>
<p>3.) If the current input has the foreign attribute and does not have a <strong>select</strong> box right next to it we create the select box and connect a function to its <strong>blur</strong> event. The function will get the value of the currently selected option and make it the value of its &#8220;parent&#8221; input box, and then remove the whole select box as it is not needed anymore.</p>
<p>4.) If the text in the current input box is longer than two characters (to avoid too many hits and subsequent entries in the select box) we post (by way of AJAX) the contents and the contents of the foreign attribute to the method <strong>getForeignList</strong>.</p>
<p>5.) The JSON result from PHP is used to generate the options in the select box.</p>
<p>And the getForeignList method:</p>
<pre><code class="php">function getForeignAttr($key){
	return $this-&gt;foreign[ $_POST['fkey'] ][$key];
}

function getForeignList(){
	$table 	= $this-&gt;getForeignAttr('table');
	$label 	= $this-&gt;getForeignAttr('label');
	$sql 	= "SELECT * FROM ".$this-&gt;getForeignAttr('table')." WHERE $label LIKE '%{$_POST['value']}%'";
	$rarr 	= array();
	foreach($this-&gt;sql-&gt;loadArray($sql) as $el)
		$rarr[] = array('el_id' =&gt; $el[ $this-&gt;getForeignAttr('fid') ], 'el_label' =&gt; $el[ $label ]);
	echo json_encode($rarr);
}</code></pre>
<p>Not much to add here, we run a simple SQL query to get the users whose username partially match what we just wrote in the input box and echo the JSON back.<br />
<h3>Related Posts</h3>
<ul class="related_post">
<li><a href="http://www.prodevtips.com/2010/01/10/simple-jquery-and-php-crud-interface/" title="The basic C(R)UD">The basic C(R)UD</a></li>
<li><a href="http://www.prodevtips.com/2009/12/09/multiple-select-lists-with-jquery-and-json/" title="Multiple select lists with jQuery and JSON">Multiple select lists with jQuery and JSON</a></li>
<li><a href="http://www.prodevtips.com/2009/12/05/shortening-multiple-urls-with-jquery-php-picolisp-and-bitly/" title="Shortening multiple URLs with jQuery, PHP, picolisp and bit.ly">Shortening multiple URLs with jQuery, PHP, picolisp and bit.ly</a></li>
<li><a href="http://www.prodevtips.com/2009/11/08/jquery-joomla-chat-adding-onlineoffline-and-friendlist/" title="JQuery Joomla chat, adding online/offline and friendlist">JQuery Joomla chat, adding online/offline and friendlist</a></li>
<li><a href="http://www.prodevtips.com/2009/10/31/facebook-style-chat-with-jquery-and-joomla/" title="Facebook style chat with jQuery and Joomla">Facebook style chat with jQuery and Joomla</a></li>
</ul>
 <div class='series_links'><a href='http://www.prodevtips.com/2010/01/10/simple-jquery-and-php-crud-interface/' title='The basic C(R)UD'>Previous in series</a> </div>
<p><a href="http://feedads.g.doubleclick.net/~a/2fcp3Na8OxyIpc77RMarl0rKilY/0/da"><img src="http://feedads.g.doubleclick.net/~a/2fcp3Na8OxyIpc77RMarl0rKilY/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/2fcp3Na8OxyIpc77RMarl0rKilY/1/da"><img src="http://feedads.g.doubleclick.net/~a/2fcp3Na8OxyIpc77RMarl0rKilY/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=zFx69jxxCOE:xEMUD4UBtM4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=zFx69jxxCOE:xEMUD4UBtM4:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=zFx69jxxCOE:xEMUD4UBtM4:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=zFx69jxxCOE:xEMUD4UBtM4:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=zFx69jxxCOE:xEMUD4UBtM4:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=zFx69jxxCOE:xEMUD4UBtM4:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=zFx69jxxCOE:xEMUD4UBtM4:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=zFx69jxxCOE:xEMUD4UBtM4:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=zFx69jxxCOE:xEMUD4UBtM4:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=YwkR-u9nhCs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=zFx69jxxCOE:xEMUD4UBtM4:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=zFx69jxxCOE:xEMUD4UBtM4:D7DqB2pKExk" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.prodevtips.com/2010/01/29/foreign-relations-with-jquery-php/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.prodevtips.com/2010/01/29/foreign-relations-with-jquery-php/</feedburner:origLink></item>
		<item>
		<title>Getting a server back online</title>
		<link>http://feedproxy.google.com/~r/prodevtips/LVkG/~3/ZednNca1HJg/</link>
		<comments>http://www.prodevtips.com/2010/01/25/getting-a-server-back-online/#comments</comments>
		<pubDate>Mon, 25 Jan 2010 10:52:47 +0000</pubDate>
		<dc:creator>Henrik</dc:creator>
		
		<category><![CDATA[Misc]]></category>

		<category><![CDATA[aministration]]></category>

		<category><![CDATA[apache]]></category>

		<category><![CDATA[Linux]]></category>

		<category><![CDATA[networking]]></category>

		<category><![CDATA[rescue]]></category>

		<guid isPermaLink="false">http://www.prodevtips.com/2010/01/25/getting-a-server-back-online/</guid>
		<description><![CDATA[Copyright © 2010 http://www.prodevtips.com. Visit the original article at http://www.prodevtips.com/2010/01/25/getting-a-server-back-online/.Last week our host had a power outage and the backup power didn&#8217;t kick in or something. In any case, the end result was a reboot of all our servers, which went surprisingly well, except for one.
This box could not have been restarted since long before [...]]]></description>
			<content:encoded><![CDATA[Copyright © 2010 <a href="http://www.prodevtips.com">http://www.prodevtips.com</a>. Visit the original article at <a href="http://www.prodevtips.com/2010/01/25/getting-a-server-back-online/">http://www.prodevtips.com/2010/01/25/getting-a-server-back-online/</a>.<br /><p>Last week our host had a power outage and the backup power didn&#8217;t kick in or something. In any case, the end result was a reboot of all our servers, which went surprisingly well, except for one.</p>
<p>This box could not have been restarted since long before I came to the company roughly a year ago and it needed to be accessed through the emergency console. The emergency console is an extra network card or something like that that you login to the machine through if all else fails. If you need to use it you know it&#8217;s bad.</p>
<p>As can be inferred, networking didn&#8217;t work at all. A colleague of mine discovered that there was a line missing in <strong>/etc/networking/interfaces</strong>, a gateway was not properly assigned in the <strong>eth0</strong> part. After fixing that and restarting networking at least the server was accessible through the normal networking and I could SSH and FTP in and backup everything.</p>
<p>Now the problem was name resolution, the machine continued to be inaccessible through its domain name. We still don&#8217;t know exactly what the problem was here. Simply restarting <strong>BIND</strong> didn&#8217;t work, however after making minor changes to the db.domain.com cache file, changes that themselves shouldn&#8217;t matter much, and restarting bind the problem was solved.</p>
<p>And then apache2 refused to start, or output any kind of error message as to why the refusal for that matter, a double whammy. After <a href="http://www.tech-recipes.com/rx/112/test-the-apache-configuration-file-httpdconf/">checking the apache configuration</a> my colleague noticed that some editor (probably nano) had automatically backed up one of the virtual host files as *.save. Apache was not ignoring this file which resulted in a double record and silent death. After we deleted it everything finally worked.</p>
<p>Rebooting can be a mess.<br />
<h3>Related Posts</h3>
<ul class="related_post">
<li><a href="http://www.prodevtips.com/2009/02/10/being-linux-admin-setting-up-virtual-servers-and-samba/" title="Being Linux admin - setting up virtual servers and Samba">Being Linux admin - setting up virtual servers and Samba</a></li>
<li><a href="http://www.prodevtips.com/2008/07/09/crazy-suse-mod_rewrite-problem/" title="Crazy SUSE mod_rewrite problem">Crazy SUSE mod_rewrite problem</a></li>
<li><a href="http://www.prodevtips.com/2007/10/15/8/" title="XAMPP on Suse">XAMPP on Suse</a></li>
<li><a href="http://www.prodevtips.com/2009/11/27/solving-memory-limit-exhausted-in-php/" title="Solving memory limit exhausted in PHP">Solving memory limit exhausted in PHP</a></li>
<li><a href="http://www.prodevtips.com/2009/10/25/ubuntu-810-karmic-koala-64bit-on-a-sony-vaio-aw11z/" title="Ubuntu 9.10 (Karmic Koala) 64bit on a SONY VAIO AW11Z">Ubuntu 9.10 (Karmic Koala) 64bit on a SONY VAIO AW11Z</a></li>
</ul>

<p><a href="http://feedads.g.doubleclick.net/~a/9cVk_TuURE0F0i8LrRkN_kD-qrU/0/da"><img src="http://feedads.g.doubleclick.net/~a/9cVk_TuURE0F0i8LrRkN_kD-qrU/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/9cVk_TuURE0F0i8LrRkN_kD-qrU/1/da"><img src="http://feedads.g.doubleclick.net/~a/9cVk_TuURE0F0i8LrRkN_kD-qrU/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=ZednNca1HJg:lE4wFCLidj4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=ZednNca1HJg:lE4wFCLidj4:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=ZednNca1HJg:lE4wFCLidj4:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=ZednNca1HJg:lE4wFCLidj4:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=ZednNca1HJg:lE4wFCLidj4:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=ZednNca1HJg:lE4wFCLidj4:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=ZednNca1HJg:lE4wFCLidj4:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=ZednNca1HJg:lE4wFCLidj4:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=ZednNca1HJg:lE4wFCLidj4:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=YwkR-u9nhCs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=ZednNca1HJg:lE4wFCLidj4:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=ZednNca1HJg:lE4wFCLidj4:D7DqB2pKExk" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.prodevtips.com/2010/01/25/getting-a-server-back-online/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.prodevtips.com/2010/01/25/getting-a-server-back-online/</feedburner:origLink></item>
		<item>
		<title>The basic C(R)UD</title>
		<link>http://feedproxy.google.com/~r/prodevtips/LVkG/~3/kYgPUeDqk3g/</link>
		<comments>http://www.prodevtips.com/2010/01/10/simple-jquery-and-php-crud-interface/#comments</comments>
		<pubDate>Sun, 10 Jan 2010 10:34:32 +0000</pubDate>
		<dc:creator>Henrik</dc:creator>
		
		<category><![CDATA[Ajax]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[jQuery]]></category>

		<category><![CDATA[ajax]]></category>

		<category><![CDATA[Javascript]]></category>

		<category><![CDATA[jquery]]></category>

		<guid isPermaLink="false">http://www.prodevtips.com/2010/01/10/simple-jquery-and-php-crud-interface/</guid>
		<description><![CDATA[Tutorial on how to create a simple CRUD interface powered by PHP, jQuery and Ajax.]]></description>
			<content:encoded><![CDATA[<div class='series_toc'><h3><a href="#">Table of Contents for Simple jQuery and PHP CRUD interface</a></h3><ol><li>The basic C(R)UD</li><li><a href='http://www.prodevtips.com/2010/01/29/foreign-relations-with-jquery-php/' title='Foreign relations with jQuery / PHP'>Foreign relations with jQuery / PHP</a></li></ol></div> Copyright © 2010 <a href="http://www.prodevtips.com">http://www.prodevtips.com</a>. Visit the original article at <a href="http://www.prodevtips.com/2010/01/10/simple-jquery-and-php-crud-interface/">http://www.prodevtips.com/2010/01/10/simple-jquery-and-php-crud-interface/</a>.<br /><div class="image_right">
<a href='http://www.prodevtips.com/wp-content/uploads/2010/01/jquery_ajax_php_crud.png' title='jquery_ajax_php_crud.png'><img src='http://www.prodevtips.com/wp-content/uploads/2010/01/jquery_ajax_php_crud.thumbnail.png' alt='jquery_ajax_php_crud.png' /></a>
</div>
<p>I recently made a very simple but functional administrational interface using jQuery and Ajax to avoid having to refresh the page all the time thus simplifying development.</p>
<p>The only convention/requirement here is that any database table that uses the interface has a unique id column aptly named id.</p>
<p>Let&#8217;s start with adding stuff:</p>
<pre><code class="html">Add:
&lt;form action="&lt;?php echo 'http://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'] ?&gt;" method="POST"&gt;
	&lt;table&gt;
		&lt;tr&gt;
			&lt;?php foreach($struct as $row): ?&gt;
				&lt;?php if($row-&gt;Field != "id"): ?&gt;
					&lt;th&gt;&lt;?php echo ucfirst($row-&gt;Field) ?&gt;&lt;/th&gt;
				&lt;?php endif ?&gt;
			&lt;?php endforeach ?&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;?php foreach($struct as $row): ?&gt;
				&lt;?php if($row-&gt;Field != "id"): ?&gt;
					&lt;td&gt;&lt;input class="add_input" type="text" name="&lt;?php echo $row-&gt;Field ?&gt;"/&gt;&lt;/td&gt;
				&lt;?php endif ?&gt;
			&lt;?php endforeach ?&gt;
			&lt;td&gt; &lt;input type="submit" id="add_submit" value="Save"&gt; &lt;/td&gt;
		&lt;/tr&gt;
	&lt;/table&gt;
	&lt;input type="hidden" name="post_action" value="insert"/&gt;
&lt;/form&gt;</code></pre>
<p>The insert/add form is using automatically generated meta information in the $<strong>struct</strong> array of objects. This information is used to generate column headlines but more importantly to automatically assign a name to each input field.</p>
<p>Let take a look at the PHP/MySQL behind this:</p>
<pre><code class="php">if(!empty($_POST['post_action'])){
	$func = $_POST['post_action'];
	unset($_POST['post_action']);
	$this-&gt;$func();
}

function insert(){
	echo "insert";
	$this-&gt;sql-&gt;insertArray($this-&gt;table(), $_POST);
}

$struct = $this-&gt;sql-&gt;loadObjects("SHOW COLUMNS IN ".$this-&gt;table());</code></pre>
<div class="image_right">
    <script type="text/javascript"><!--
      google_ad_client = "pub-4780703337538969";
      google_alternate_color = "dedcdc";
      google_ad_width = 234;
      google_ad_height = 60;
      google_ad_format = "234x60_as";
      google_ad_type = "text_image";
      google_color_border = "dedcdc";
      google_color_link = "993333";
      google_color_bg = "dedcdc";
      google_color_text = "000000";
      google_color_url = "003366";
      //-->
   </script><br />
  <script type="text/javascript"
    src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
  </script>
</div>
<p>We have a check for the presence of <strong>post_action</strong> in the POST array if we have it we use its value to call that function in the current class ($this->$func();), one of a select few nifty features of PHP.</p>
<p>If the post_action is <strong>insert</strong> we simply call insert() above which in turn makes use of a class called SQL which is outside the scope of this tutorial. Suffice to say that <strong>insertArray</strong> will build a MySQL insert query from the contents of the array and execute it.</p>
<p>A simple SHOW COLUMNS query, very handy in these cases when you need to create interfaces automatically.</p>
<p>Editing is the hardest part because we do it on a per cell basis, we don&#8217;t submit the whole row. Therefore we need to keep track of both row id and name, ie. the <strong>$key-$id</strong> combo below where $key is the field name and the $id the unique id of the row.</p>
<pre><code class="html">Edit:
&lt;table id="jform_table"&gt;
	&lt;?php foreach($rows as $id =&gt; $row): ?&gt;
		&lt;tr id="row-&lt;?php echo $id ?&gt;" &gt;
			&lt;?php foreach($row as $key =&gt; $val): ?&gt;
				&lt;?php if($key != 'id'): ?&gt;
					&lt;td&gt; &lt;input id="&lt;?php echo "$key-$id" ?&gt;" type="text" value="&lt;?php echo $val ?&gt;" /&gt; &lt;/td&gt;
				&lt;?php endif ?&gt;
			&lt;?php endforeach ?&gt;
			&lt;td&gt; 
				&lt;form action="&lt;?php echo 'http://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'] ?&gt;" method="POST"&gt;
					&lt;input type="submit" id="delete_submit" value="Delete"&gt;
					&lt;input type="hidden" name="post_action" value="delete"/&gt;
					&lt;input type="hidden" name="row_id" value="&lt;?php echo $id ?&gt;"/&gt;
				&lt;/form&gt; 
			&lt;/td&gt;
		&lt;/tr&gt;
	&lt;?php endforeach; ?&gt;
&lt;/table&gt;</code></pre>
<p>The javascript making all of this happen:</p>
<pre><code class="javascript">$(document).ready(function(){
	$("input").keydown(function(event){
		if(event.keyCode == 13){
			var field_id = $(this).attr("id").split("-");
			$.post(window.location.href, {field: field_id[0], id: field_id[1], val: $(this).val()});
		}
	});
});</code></pre>
<p>So as soon as we are editing a field we look for return key press, if we get it we post the value to the same url that generated the form. We submit the field name (field_id[0]) and the row id (field_id[1]) which we obtain by splitting the key-id combo.</p>
<p>So before we render the HTML we have the following check somewhere in the PHP code:</p>
<pre><code class="php">if(!empty($_POST['id'])){
	$this-&gt;sql-&gt;query("UPDATE ".$this-&gt;table()." SET {$_POST['field']} = '{$_POST['val']}' WHERE id = {$_POST['id']}");
	echo "ok";
	exit;
}</code></pre>
<p>If the POST global contains the id key we know we have an update request on our hands so we use the POST information to update the row.</p>
<p>As you could see above we also have a delete form attached to each row which upon submission will delete said row. This is not by way of Ajax and there is no JavaScript involved, hence each submit will refresh the page. Note that we submit to the same PHP script that generated the form yet again, all this stuff is self-contained in the same document.<br />
<script type="text/javascript"><!--
  google_ad_client = "pub-4780703337538969";
  google_alternate_color = "dedcdc";
  google_ad_width = 728;
  google_ad_height = 90;
  google_ad_format = "728x90_as";
  google_ad_type = "text_image";
  google_color_border = "dedcdc";
  google_color_link = "993333";
  google_color_bg = "dedcdc";
  google_color_text = "000000";
  google_color_url = "003366";
  //-->
</script><br />
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script><br />
<h3>Related Posts</h3>
<ul class="related_post">
<li><a href="http://www.prodevtips.com/2009/12/09/multiple-select-lists-with-jquery-and-json/" title="Multiple select lists with jQuery and JSON">Multiple select lists with jQuery and JSON</a></li>
<li><a href="http://www.prodevtips.com/2009/08/27/adding-a-facebook-style-information-box-with-jquery/" title="Facebook style information box with jQuery">Facebook style information box with jQuery</a></li>
<li><a href="http://www.prodevtips.com/2008/09/30/integrating-with-jquery-adding-pagination/" title="Integrating with jQuery - Adding Pagination">Integrating with jQuery - Adding Pagination</a></li>
<li><a href="http://www.prodevtips.com/2007/12/07/multiple-uploads-with-jquery-and-flex-or-flash/" title="Multiple uploads with jQuery and Flex or Flash">Multiple uploads with jQuery and Flex or Flash</a></li>
<li><a href="http://www.prodevtips.com/2010/03/07/jquery-drag-and-drop-to-sort-tree/" title="jQuery Drag and Drop to sort Tree">jQuery Drag and Drop to sort Tree</a></li>
</ul>
 <div class='series_links'> <a href='http://www.prodevtips.com/2010/01/29/foreign-relations-with-jquery-php/' title='Foreign relations with jQuery / PHP'>Next in series</a></div>
<p><a href="http://feedads.g.doubleclick.net/~a/ogwun-ZcSYEzMv_5QGmLndTHutE/0/da"><img src="http://feedads.g.doubleclick.net/~a/ogwun-ZcSYEzMv_5QGmLndTHutE/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/ogwun-ZcSYEzMv_5QGmLndTHutE/1/da"><img src="http://feedads.g.doubleclick.net/~a/ogwun-ZcSYEzMv_5QGmLndTHutE/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=kYgPUeDqk3g:xsh8VwJtvSw:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=kYgPUeDqk3g:xsh8VwJtvSw:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=kYgPUeDqk3g:xsh8VwJtvSw:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=kYgPUeDqk3g:xsh8VwJtvSw:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=kYgPUeDqk3g:xsh8VwJtvSw:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=kYgPUeDqk3g:xsh8VwJtvSw:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=kYgPUeDqk3g:xsh8VwJtvSw:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=kYgPUeDqk3g:xsh8VwJtvSw:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=kYgPUeDqk3g:xsh8VwJtvSw:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=YwkR-u9nhCs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=kYgPUeDqk3g:xsh8VwJtvSw:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=kYgPUeDqk3g:xsh8VwJtvSw:D7DqB2pKExk" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.prodevtips.com/2010/01/10/simple-jquery-and-php-crud-interface/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.prodevtips.com/2010/01/10/simple-jquery-and-php-crud-interface/</feedburner:origLink></item>
		<item>
		<title>On PicoLisp’s Wikipedia woes and the process of promoting a language</title>
		<link>http://feedproxy.google.com/~r/prodevtips/LVkG/~3/Vd7PuNXPcRw/</link>
		<comments>http://www.prodevtips.com/2010/01/09/on-picolisps-wikipedia-woes-and-the-process-of-promoting-a-language/#comments</comments>
		<pubDate>Sat, 09 Jan 2010 22:24:32 +0000</pubDate>
		<dc:creator>Henrik</dc:creator>
		
		<category><![CDATA[Lisp]]></category>

		<category><![CDATA[Pico Lisp]]></category>

		<category><![CDATA[picolisp]]></category>

		<category><![CDATA[wikipedia]]></category>

		<guid isPermaLink="false">http://www.prodevtips.com/2010/01/09/on-picolisps-wikipedia-woes-and-the-process-of-promoting-a-language/</guid>
		<description><![CDATA[Copyright © 2010 http://www.prodevtips.com. Visit the original article at http://www.prodevtips.com/2010/01/09/on-picolisps-wikipedia-woes-and-the-process-of-promoting-a-language/.It seems we&#8217;re having some problems with Wikipedia when it comes to creating a entry for PicoLisp there.
This prompted Alex Burger (the language creator) to write the following on the mailing list:

Besides this, I&#8217;m extremely frustrated. I think I wasted too much time
on communicating (instead of [...]]]></description>
			<content:encoded><![CDATA[Copyright © 2010 <a href="http://www.prodevtips.com">http://www.prodevtips.com</a>. Visit the original article at <a href="http://www.prodevtips.com/2010/01/09/on-picolisps-wikipedia-woes-and-the-process-of-promoting-a-language/">http://www.prodevtips.com/2010/01/09/on-picolisps-wikipedia-woes-and-the-process-of-promoting-a-language/</a>.<br /><p>It seems we&#8217;re having some <a href="http://www.mail-archive.com/picolisp@software-lab.de/msg01403.html">problems with Wikipedia</a> when it comes to creating a entry for <a href="http://www.software-lab.de/down.html">PicoLisp</a> there.</p>
<p>This prompted Alex Burger (the language creator) to write the following on the mailing list:</p>
<blockquote><p>
Besides this, I&#8217;m extremely frustrated. I think I wasted too much time<br />
on communicating (instead of using) PicoLisp during the last 8 years.</p>
<p>From now on I&#8217;ll concentrate on my own work. I won&#8217;t write any articles,<br />
or propagate PicoLisp in any way. I&#8217;ll answer questions in this mailing<br />
list, though.
</p></blockquote>
<p>Well as long as you&#8217;re active on the list I&#8217;m happy <img src='http://www.prodevtips.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Putting Wikipedia and other places aside, apart from personally enjoying helping people what could motive a language creator to help adoption (not counting pride and glory)?</p>
<p>Financial gain of course, in mainly the following areas:<br />
1.) Creation of libraries that will help him in his own endeavors, thus minimizing his own workload.<br />
2.) Successful projects using the language might need his professional help.<br />
3.) When other people gain more knowledge they might be inclined to help other people, thus offloading the creator.<br />
4.) The derivative effect, ie the persons he is helping might induce someone else to actually accomplish #1, #2 or #3.</p>
<p>With that in mind what could maximize the chances of either #1 or #2 happening, or otherwise getting across the threshold when the language creator can simply sit back and watch the popularity accelerate without much further effort on his part?</p>
<p>Helping people like me on IRC must be one of the least effective ways (although very nice for me), the mailing list is orders of magnitudes better since the information stays out there for all to see.</p>
<p>Having an entry on Wikipedia would unfortunately lend a lot of credibility for people who are shopping around for a new language to learn. As it happens it seems Alex managed in the end anyway because <a href="http://en.wikipedia.org/wiki/Picolisp" rel="nofollow">the article seems to be there</a> now (although if not more secondary sources are added it risks being deleted in the future apparently).</p>
<p>If the goal is to popularize PicoLisp what might be the way forward from here then? Looking at Python and Ruby I see two popular web development frameworks, Django and Rails. Especially in Ruby&#8217;s case the Rails framework has been instrumental in that language&#8217;s popularity.</p>
<p>As it happens PicoLisp has its own web development framework but it has everything to do with database administration and very little to do with the kind of problems a normal web developer faces in his/hers daily work of working mostly with a mix of administrative interfaces and content distribution and presentation.</p>
<p>So that&#8217;s what I intend to do, an alternative more general web development framework in PicoLisp, I just need to get a handle of a few more aspects of PicoLisp in particular and Linux in general, so hang in there Alex!</p>
<p>Another thing that&#8217;s somewhat missing is more library functions for performing common tasks, it should be easier to create than in many other languages though since getting stuff done in Lisp is easy.</p>
<p>Finally, without a lot of good documentation a language will get nowhere no matter how good it is. As it happens as of PicoLisp 3.0.1 the <a href="http://www.software-lab.de/doc/ref.html">reference</a> is now better than ever. Parts of it will still seem cryptic to beginners but a new wiki is in the works.</p>
<p>I think 2010 will be a very interesting year for PicoLisp.<br />
<h3>Related Posts</h3>
<ul class="related_post">
<li><a href="http://www.prodevtips.com/2009/12/05/shortening-multiple-urls-with-jquery-php-picolisp-and-bitly/" title="Shortening multiple URLs with jQuery, PHP, picolisp and bit.ly">Shortening multiple URLs with jQuery, PHP, picolisp and bit.ly</a></li>
<li><a href="http://www.prodevtips.com/2009/11/05/the-ugliest-lisp-in-the-world/" title="The ugliest LISP in the world">The ugliest LISP in the world</a></li>
<li><a href="http://www.prodevtips.com/2008/10/09/pilog-solve-and-the-aux-relation/" title="Pilog solve and the +Aux relation">Pilog solve and the +Aux relation</a></li>
<li><a href="http://www.prodevtips.com/2008/09/11/pico-lisp-and-json/" title="Pico Lisp and JSON">Pico Lisp and JSON</a></li>
<li><a href="http://www.prodevtips.com/2008/08/13/explicit-scope-resolution-in-pico-lisp/" title="Explicit scope resolution in Pico Lisp">Explicit scope resolution in Pico Lisp</a></li>
</ul>

<p><a href="http://feedads.g.doubleclick.net/~a/TQLwgfUHlS_5ihdVRdVFPRCsFhU/0/da"><img src="http://feedads.g.doubleclick.net/~a/TQLwgfUHlS_5ihdVRdVFPRCsFhU/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/TQLwgfUHlS_5ihdVRdVFPRCsFhU/1/da"><img src="http://feedads.g.doubleclick.net/~a/TQLwgfUHlS_5ihdVRdVFPRCsFhU/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=Vd7PuNXPcRw:inM7FCl8UbA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=Vd7PuNXPcRw:inM7FCl8UbA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=Vd7PuNXPcRw:inM7FCl8UbA:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=Vd7PuNXPcRw:inM7FCl8UbA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=Vd7PuNXPcRw:inM7FCl8UbA:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=Vd7PuNXPcRw:inM7FCl8UbA:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=Vd7PuNXPcRw:inM7FCl8UbA:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=Vd7PuNXPcRw:inM7FCl8UbA:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=Vd7PuNXPcRw:inM7FCl8UbA:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=YwkR-u9nhCs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=Vd7PuNXPcRw:inM7FCl8UbA:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=Vd7PuNXPcRw:inM7FCl8UbA:D7DqB2pKExk" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.prodevtips.com/2010/01/09/on-picolisps-wikipedia-woes-and-the-process-of-promoting-a-language/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.prodevtips.com/2010/01/09/on-picolisps-wikipedia-woes-and-the-process-of-promoting-a-language/</feedburner:origLink></item>
		<item>
		<title>Multiple select lists with jQuery and JSON</title>
		<link>http://feedproxy.google.com/~r/prodevtips/LVkG/~3/KjhRCyLNpbM/</link>
		<comments>http://www.prodevtips.com/2009/12/09/multiple-select-lists-with-jquery-and-json/#comments</comments>
		<pubDate>Wed, 09 Dec 2009 23:14:26 +0000</pubDate>
		<dc:creator>Henrik</dc:creator>
		
		<category><![CDATA[Ajax]]></category>

		<category><![CDATA[PHP]]></category>

		<category><![CDATA[jQuery]]></category>

		<category><![CDATA[ajax]]></category>

		<category><![CDATA[Javascript]]></category>

		<category><![CDATA[jquery]]></category>

		<category><![CDATA[json]]></category>

		<category><![CDATA[multi select]]></category>

		<guid isPermaLink="false">http://www.prodevtips.com/2009/12/09/multiple-select-lists-with-jquery-and-json/</guid>
		<description><![CDATA[Tutorial on how to control and read multi select boxes with jQuery and JavaScript.]]></description>
			<content:encoded><![CDATA[Copyright © 2010 <a href="http://www.prodevtips.com">http://www.prodevtips.com</a>. Visit the original article at <a href="http://www.prodevtips.com/2009/12/09/multiple-select-lists-with-jquery-and-json/">http://www.prodevtips.com/2009/12/09/multiple-select-lists-with-jquery-and-json/</a>.<br /><div class="image_right">
    <script type="text/javascript"><!--
      google_ad_client = "pub-4780703337538969";
      google_alternate_color = "dedcdc";
      google_ad_width = 234;
      google_ad_height = 60;
      google_ad_format = "234x60_as";
      google_ad_type = "text_image";
      google_color_border = "dedcdc";
      google_color_link = "993333";
      google_color_bg = "dedcdc";
      google_color_text = "000000";
      google_color_url = "003366";
      //-->
   </script><br />
  <script type="text/javascript"
    src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
  </script>
</div>
<p>This tutorial will all be about managing loading data into multiple select lists and then save the selections in the list.</p>
<p>There will be two multiple selects, one with a list of sites that will display a selection of partners, when a site is selected in the single select list the partners that have previously been mapped to it will automatically be selected in the multi select box listing them.</p>
<p>Let&#8217;s start with JS code working on a select box with the id <strong>partner_sites</strong>:</p>
<pre><code class="javascript">$(document).ready(function(){
	$("#partner_sites select option").click(function(){
		var siteId = $(this).val();
		$.post(window.location.href, {func: "jsonSitePartners", site_id: siteId}, function(res){
			var partners = $.evalJSON(res);
			if(partners.length &gt; 0){
				$("#partners_list").find("option").attr("selected", false);
				$.each(partners, function(){
					$("#partners_list").find("option[value='"+this.partner_id+"']").attr("selected", true);
				});
			}else
				$("#partners_list").find("option").attr("selected", false);
		});
	});
});</code></pre>
<div class="image_right">
    <script type="text/javascript"><!--
      google_ad_client = "pub-4780703337538969";
      google_alternate_color = "dedcdc";
      google_ad_width = 234;
      google_ad_height = 60;
      google_ad_format = "234x60_as";
      google_ad_type = "text_image";
      google_color_border = "dedcdc";
      google_color_link = "993333";
      google_color_bg = "dedcdc";
      google_color_text = "000000";
      google_color_url = "003366";
      //-->
   </script><br />
  <script type="text/javascript"
    src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
  </script>
</div>
<p>When we click a site the following happens:<br />
1.) We get the site&#8217;s id, it is in the clicked option&#8217;s value.</p>
<p>2.) We call a PHP method (which will be described shortly) called <strong>jsonSitePartners</strong> by way of AJAX, and we pass it the selected site&#8217;s id.</p>
<p>3.) We will now get a list of partners in the form of a JSON string which we will evaluate with the help of <a href="http://www.prodevtips.com/2008/08/15/jquery-json-with-php-json_encode-and-json_decode/">JQuery JSON</a>.</p>
<p>4.) We now have our partners as JavaScript objects in an array which we can loop through with the <a href="http://docs.jquery.com/Utilities/jQuery.each#objectcallback">jQuery utility function each</a>.</p>
<p>5.) During each loop we try and find an option containing each partner&#8217;s id in its value attribute, if we find one we select it, if not we unselect it, the reason for doing that is that any partner might have been selected already since we might have clicked another site before the currently clicked site. An alternative could have been to first unselect <strong>all</strong> partner options before we started looping with each. </p>
<pre><code class="php">function jsonSitePartners(){
	$partners = array();
	foreach($this-&gt;getSitePartners($_POST['site_id']) as $partner)
		$partners[] = array('full_name' =&gt; $partner-&gt;full_name, 'partner_id' =&gt; $partner-&gt;partner_id);
	echo json_encode($partners);
}</code></pre>
<p>Not much to add here, getSitePartners will query a linktable linking partners and sites for all partners belonging to the current site. After that we do some filtering which really should have been done in the MySQL query but that&#8217;s life sometimes when you work with other people&#8217;s code, you&#8217;re bound to get technical debt because you are either 1) too scared to change things for fear of breaking something else or 2) too lazy.</p>
<pre><code class="javascript">function savePartners(){
	var partner_ids	= [];
	var siteId = $("#partner_sites select option:selected").val();
	$("#partners_list option").each(function(){
		if($(this).attr('selected'))
			partner_ids.push( $(this).val() );
	});

	$.post(window.location.href, {func: "saveSitePartners", site_id: siteId, ids: $.toJSON(partner_ids)});
	$("#msgs").html("Partners saved.");
}</code></pre>
<p>So after we have successfully selected all the current partners of our site and then some more, or removed some maybe, we need to be able to save them. To do that we need two things, the ids of the partners we want to map to the currently selected site and of course the id of the currently selected site.</p>
<p>The id of the site can be had by checking which of the options in the site <strong>single</strong> select list has been selected. Next we loop through the partners and store all the ids of selected partners in an array.</p>
<p>Finally we JSON encode and AJAX post everything to a PHP method called <strong>saveSitePartners</strong>:</p>
<pre><code class="php">function saveSitePartners(){
	$ids = json_decode($_POST['ids']);
	$this-&gt;sql-&gt;query("DELETE FROM partners_site WHERE partner_id IN(".implode(',', $ids).")");
	foreach($ids as $pid)
		$this-&gt;sql-&gt;insertArray('partners_site', array('partner_id' =&gt; $pid, 'site_id' =&gt; $_POST['site_id']));
	echo "ok";
}</code></pre>
<p>First we decode the JSON and then we can use the fact that we now have an array by using <strong>implode</strong> on it with the help of a comma as glue, the result is something that can be used in the IN() SQL method, an often used &#8220;trick&#8221; of mine.</p>
<p>First we delete all partners belonging to the currently selected site from the link table, then we proceed by inserting them one by one, yet again not very clever since we&#8217;re doing repeat queries but this will not be a common operation so we can afford to be somewhat slow here.<br />
<h3>Related Posts</h3>
<ul class="related_post">
<li><a href="http://www.prodevtips.com/2010/03/07/jquery-drag-and-drop-to-sort-tree/" title="jQuery Drag and Drop to sort Tree">jQuery Drag and Drop to sort Tree</a></li>
<li><a href="http://www.prodevtips.com/2010/01/10/simple-jquery-and-php-crud-interface/" title="The basic C(R)UD">The basic C(R)UD</a></li>
<li><a href="http://www.prodevtips.com/2009/12/05/shortening-multiple-urls-with-jquery-php-picolisp-and-bitly/" title="Shortening multiple URLs with jQuery, PHP, picolisp and bit.ly">Shortening multiple URLs with jQuery, PHP, picolisp and bit.ly</a></li>
<li><a href="http://www.prodevtips.com/2009/08/27/adding-a-facebook-style-information-box-with-jquery/" title="Facebook style information box with jQuery">Facebook style information box with jQuery</a></li>
<li><a href="http://www.prodevtips.com/2008/09/30/integrating-with-jquery-adding-pagination/" title="Integrating with jQuery - Adding Pagination">Integrating with jQuery - Adding Pagination</a></li>
</ul>

<p><a href="http://feedads.g.doubleclick.net/~a/Lr5qoUBxZwyqrnb0TBVbcvHbibk/0/da"><img src="http://feedads.g.doubleclick.net/~a/Lr5qoUBxZwyqrnb0TBVbcvHbibk/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/Lr5qoUBxZwyqrnb0TBVbcvHbibk/1/da"><img src="http://feedads.g.doubleclick.net/~a/Lr5qoUBxZwyqrnb0TBVbcvHbibk/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=KjhRCyLNpbM:uMmL-oZy_cY:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=KjhRCyLNpbM:uMmL-oZy_cY:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=KjhRCyLNpbM:uMmL-oZy_cY:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=KjhRCyLNpbM:uMmL-oZy_cY:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=KjhRCyLNpbM:uMmL-oZy_cY:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=KjhRCyLNpbM:uMmL-oZy_cY:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=KjhRCyLNpbM:uMmL-oZy_cY:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=KjhRCyLNpbM:uMmL-oZy_cY:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=KjhRCyLNpbM:uMmL-oZy_cY:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=YwkR-u9nhCs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=KjhRCyLNpbM:uMmL-oZy_cY:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=KjhRCyLNpbM:uMmL-oZy_cY:D7DqB2pKExk" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.prodevtips.com/2009/12/09/multiple-select-lists-with-jquery-and-json/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.prodevtips.com/2009/12/09/multiple-select-lists-with-jquery-and-json/</feedburner:origLink></item>
		<item>
		<title>HTML stripping jQuery plugin</title>
		<link>http://feedproxy.google.com/~r/prodevtips/LVkG/~3/jRRB6L5FA2Y/</link>
		<comments>http://www.prodevtips.com/2009/12/05/html-stripping-jquery-plugin/#comments</comments>
		<pubDate>Sat, 05 Dec 2009 11:59:23 +0000</pubDate>
		<dc:creator>Henrik</dc:creator>
		
		<category><![CDATA[jQuery]]></category>

		<category><![CDATA[html]]></category>

		<category><![CDATA[jquery]]></category>

		<category><![CDATA[regex]]></category>

		<guid isPermaLink="false">http://www.prodevtips.com/2009/12/05/html-stripping-jquery-plugin/</guid>
		<description><![CDATA[Example of a jQuery plugin that will strip HTML tags.]]></description>
			<content:encoded><![CDATA[Copyright © 2010 <a href="http://www.prodevtips.com">http://www.prodevtips.com</a>. Visit the original article at <a href="http://www.prodevtips.com/2009/12/05/html-stripping-jquery-plugin/">http://www.prodevtips.com/2009/12/05/html-stripping-jquery-plugin/</a>.<br /><p>Small tag stripping jQuery plugin:</p>
<pre><code class="javascript">jQuery.fn.stripHTML = function() { 
  return this.each(function(){ 
    var me   = jQuery(this); 
    var html = me.html(); 
    me.html(html.replace(/&lt;[^&gt;]+&gt;/g, "").replace(/&lt;\/[^&gt;]+&gt;/g, ""));
  }); 
}</code></pre>
<p>If the code is HTML encoded it needs to first be <a href="http://www.prodevtips.com/2008/10/21/jquery-plugin-html-decode-and-encode/">HTML decoded</a>. </p>
<p>A usage example could look like this:</p>
<pre><code class="javascript">$(".article_title").decHTML().stripHTML();</code></pre>
<p>    <script type="text/javascript"><!--
      google_ad_client = "pub-4780703337538969";
      google_alternate_color = "dedcdc";
      google_ad_width = 728;
      google_ad_height = 90;
      google_ad_format = "728x90_as";
      google_ad_type = "text_image";
      google_color_border = "dedcdc";
      google_color_link = "993333";
      google_color_bg = "dedcdc";
      google_color_text = "000000";
      google_color_url = "003366";
      //-->
   </script><br />
  <script type="text/javascript"
    src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
  </script><br />
<h3>Related Posts</h3>
<ul class="related_post">
<li><a href="http://www.prodevtips.com/2009/10/31/facebook-style-chat-with-jquery-and-joomla/" title="Facebook style chat with jQuery and Joomla">Facebook style chat with jQuery and Joomla</a></li>
<li><a href="http://www.prodevtips.com/2008/11/12/jquery-ui-draggable-and-resizable-combination/" title="jQuery UI draggable and resizable combination">jQuery UI draggable and resizable combination</a></li>
<li><a href="http://www.prodevtips.com/2008/10/21/jquery-plugin-html-decode-and-encode/" title="jQuery plugin - HTML decode and encode">jQuery plugin - HTML decode and encode</a></li>
<li><a href="http://www.prodevtips.com/2008/08/25/adding-search-with-jquery-and-check-boxes/" title="Adding search with jQuery and Check Boxes">Adding search with jQuery and Check Boxes</a></li>
<li><a href="http://www.prodevtips.com/2008/07/06/jquery-treeview-with-modx-wayfinder/" title="jQuery Treeview with MODx Wayfinder">jQuery Treeview with MODx Wayfinder</a></li>
</ul>

<p><a href="http://feedads.g.doubleclick.net/~a/Q6dk-Xmxtqf1--cPPbDoNXDoIXM/0/da"><img src="http://feedads.g.doubleclick.net/~a/Q6dk-Xmxtqf1--cPPbDoNXDoIXM/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/Q6dk-Xmxtqf1--cPPbDoNXDoIXM/1/da"><img src="http://feedads.g.doubleclick.net/~a/Q6dk-Xmxtqf1--cPPbDoNXDoIXM/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=jRRB6L5FA2Y:MFZ1AQyYZrk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=jRRB6L5FA2Y:MFZ1AQyYZrk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=jRRB6L5FA2Y:MFZ1AQyYZrk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=jRRB6L5FA2Y:MFZ1AQyYZrk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=jRRB6L5FA2Y:MFZ1AQyYZrk:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=jRRB6L5FA2Y:MFZ1AQyYZrk:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=jRRB6L5FA2Y:MFZ1AQyYZrk:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=jRRB6L5FA2Y:MFZ1AQyYZrk:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=jRRB6L5FA2Y:MFZ1AQyYZrk:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?d=YwkR-u9nhCs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/prodevtips/LVkG?a=jRRB6L5FA2Y:MFZ1AQyYZrk:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/prodevtips/LVkG?i=jRRB6L5FA2Y:MFZ1AQyYZrk:D7DqB2pKExk" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.prodevtips.com/2009/12/05/html-stripping-jquery-plugin/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.prodevtips.com/2009/12/05/html-stripping-jquery-plugin/</feedburner:origLink></item>
	</channel>
</rss><!-- Dynamic Page Served (once) in 0.624 seconds --><!-- Cached page served by WP-Cache -->
