<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	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:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Serdar Yildirim - blog</title>
	<atom:link href="http://serdaryildirim.net/feed" rel="self" type="application/rss+xml" />
	<link>http://serdaryildirim.net</link>
	<description>About PLs and other stuff!</description>
	<lastBuildDate>Thu, 26 Apr 2012 07:43:36 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Couple of Notes After Getting TechCrunched</title>
		<link>http://serdaryildirim.net/startups/couple-of-notes-after-getting-techcrunched.html</link>
		<comments>http://serdaryildirim.net/startups/couple-of-notes-after-getting-techcrunched.html#comments</comments>
		<pubDate>Wed, 18 Apr 2012 14:54:11 +0000</pubDate>
		<dc:creator>serdar</dc:creator>
				<category><![CDATA[Startups]]></category>
		<category><![CDATA[app]]></category>
		<category><![CDATA[communication]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[lefeed]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[startup]]></category>
		<category><![CDATA[tc effect]]></category>
		<category><![CDATA[techcrunch]]></category>

		<guid isPermaLink="false">http://serdaryildirim.net/?p=365</guid>
		<description><![CDATA[TechCrunched? Great. Take a cup of coffee and stay awake.
My last side project, <a title="LeFeed" href="http://www.lefeed.com/" target="_blank">LeFeed.com</a> got <a title="lefeed on techcrunch" href="http://techcrunch.com/2012/04/05/lefeed-learns-your-preferences-shows-you-only-le-cool-stuff-on-le-facebook/">techcrunched</a> on April 5th by John Biggs.
It&#8217;s a great thing because of several reasons;

you&#8217;ll get lots of feedback instantly, right after you launch your project
first users will be highly interested in Tech and [...]]]></description>
			<content:encoded><![CDATA[<p>TechCrunched? Great. Take a cup of coffee and stay awake.</p>
<p>My last side project, <a title="LeFeed" href="http://www.lefeed.com/" target="_blank">LeFeed.com</a> got <a title="lefeed on techcrunch" href="http://techcrunch.com/2012/04/05/lefeed-learns-your-preferences-shows-you-only-le-cool-stuff-on-le-facebook/">techcrunched</a> on April 5th by John Biggs.</p>
<p>It&#8217;s a great thing because of several reasons;</p>
<ul style="list-style: square;">
<li>you&#8217;ll get lots of feedback instantly, right after you launch your project</li>
<li>first users will be highly interested in Tech and latest stuff.</li>
<li>users will sign up from all around the world, so if it&#8217;s a social product, you&#8217;ll see lots of reaction from different countries.</li>
<li>and hey it is TC!</li>
</ul>
<p>As long as it is working, and you can&#8217;t see really major bugs on your app, I don&#8217;t think there are lots of things to do before submitting your project to TC.</p>
<p>I mean, if design looks good on major modern browsers (and yeah including IE8&amp;9), functionalities are ok, you are sure about server, and all other things like logs etc., it is ready to go.</p>
<p>But in my case, I forgot something, and that caused lots of nightmares. Make sure your memory is <strong>sufficient!</strong></p>
<p>Ok, if it&#8217;s a new project, a VPS with a 1GB RAM is just fine. But if your project is something like <a title="LeFeed" href="http://serdaryildirim.net/ai/recommender-systems-collaborative-filtering-approach.html" target="_blank">LeFeed</a>, I mean it does heavy job on backend, processes millions of records, and lots of things while running learning and recommender algorithms, then get a bigger RAM, at least 2GB.</p>
<p>Because of this issue, I had to manually control whether users data processed correctly, checked log files to see if something went bad (memory allocation problems, facebook graph API connection timeout problems and some others).</p>
<p>After second day, I increased my mem so problems are solved. So do it before launching yours if you do lots of calculations, cause you&#8217;ll need that when hundreds of users come your website in an hour from TC.</p>
<p>And lastly, there are some other things that needs to be done after getting coverage,</p>
<ul style="list-style: square;">
<li><strong>Be responsive!</strong> Follow your company name on <a href="https://twitter.com/#!/search/realtime/lefeed" target="_blank">twitter</a>, <a href="https://graph.facebook.com/search?q=lefeed&amp;type=post" target="_blank">facebook</a> and <a href="https://www.google.com/search?q=%22lefeed%22+-site%3Awww.lefeed.com" target="_blank">google</a> (click to see some samples for LeFeed), try to respond questions or concerns.</li>
<li><strong>Make sure it runs fine.</strong> Regularly check logs and get notified if something goes wrong, (like apache down), and try to fix it fast.</li>
<li><strong>Take action fast!</strong> If you see something is wrong, fix it and deploy to production fast.</li>
</ul>
<p>For example, I noticed that users think they will get recommendations right after they just signed up. (naturally)</p>
<p>But some users have 1000+ users (so 1001 users data <strong>+</strong> 1001 users&#8217; likes data in total) and it is *really* not easy to fetch that huge data from Facebook quickly. (yes even by using batch request which lets you merge up to 50 requests). So I simply checked if users get recommendations or not, if not I&#8217;ve added a text to inform user by some js and css help. So I prevent users thinking that it is broken.</p>
<p>Finally about <a title="techcrunch" href="http://techcrunch.com/" target="_blank">TC</a> effect, it is <strong>not overrated.</strong> It is a great thing for new projects by many aspects, so <strong>build something great</strong>, <strong>they will be happy to cover it</strong>!</p>
<p>&nbsp;</p>
<p>That&#8217;s all for now, let me know if you have any questions, about this process or <a title="LeFeed" href="http://www.lefeed.com/" target="_blank">LeFeed</a> app.</p>
]]></content:encoded>
			<wfw:commentRss>http://serdaryildirim.net/startups/couple-of-notes-after-getting-techcrunched.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Launched 2 New Projects in February and April</title>
		<link>http://serdaryildirim.net/startups/launched-2-new-projects-in-feburary-and-april.html</link>
		<comments>http://serdaryildirim.net/startups/launched-2-new-projects-in-feburary-and-april.html#comments</comments>
		<pubDate>Mon, 02 Apr 2012 21:42:58 +0000</pubDate>
		<dc:creator>serdar</dc:creator>
				<category><![CDATA[Startups]]></category>
		<category><![CDATA[ann]]></category>
		<category><![CDATA[backbone]]></category>
		<category><![CDATA[cf]]></category>
		<category><![CDATA[coffeescript]]></category>
		<category><![CDATA[collaborative filtering]]></category>
		<category><![CDATA[lefeed]]></category>
		<category><![CDATA[neural networks]]></category>
		<category><![CDATA[socivid]]></category>
		<category><![CDATA[startups]]></category>
		<category><![CDATA[techcrunch]]></category>

		<guid isPermaLink="false">http://serdaryildirim.net/?p=344</guid>
		<description><![CDATA[Update: <a title="LeFeed" href="http://www.lefeed.com" target="_blank">LeFeed</a> <a title="lefeed on techcrunch" href="http://techcrunch.com/2012/04/05/lefeed-learns-your-preferences-shows-you-only-le-cool-stuff-on-le-facebook/" target="_blank">featured on techcrunch</a>, please also check John&#8217;s article for LeFeed.
And I guess I&#8217;ll write a TC effects post soon.

It&#8217;s been 2 months since I wrote my <a title="Recommender Systems" href="http://serdaryildirim.net/ai/recommender-systems-collaborative-filtering-approach.html">rec_sys post</a>, meanwhile, I launched 2 new beta projects, <a title="socivid" href="http://socivid.com" target="_blank">socivid</a> and <a title="LeFeed" href="http://www.lefeed.com" [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Update:</strong> <a title="LeFeed" href="http://www.lefeed.com" target="_blank">LeFeed</a> <a title="lefeed on techcrunch" href="http://techcrunch.com/2012/04/05/lefeed-learns-your-preferences-shows-you-only-le-cool-stuff-on-le-facebook/" target="_blank">featured on techcrunch</a>, please also check John&#8217;s article for LeFeed.</p>
<p>And I guess I&#8217;ll write a TC effects post soon.</p>
<hr />
<p>It&#8217;s been 2 months since I wrote my <a title="Recommender Systems" href="http://serdaryildirim.net/ai/recommender-systems-collaborative-filtering-approach.html">rec_sys post</a>, meanwhile, I launched 2 new beta projects, <a title="socivid" href="http://socivid.com" target="_blank">socivid</a> and <a title="LeFeed" href="http://www.lefeed.com" target="_blank">LeFeed</a>.</p>
<p>Most recently I launched LeFeed in April. (2 days ago actually)</p>
<p>LeFeed is started by an experimental project. I started to interest <a href="http://en.wikipedia.org/wiki/Artificial_neural_network" target="_blank">Artificial Neural Network</a> Algorithms and <a href="http://www.hindawi.com/journals/aai/2009/421425/" target="_blank">Collaborative Filtering</a> techniques lately.</p>
<p>I&#8217;ve spent weeks to implement several techniques (model/memory based and user/item based CF) and I started building LeFeed.</p>
<p><a title="LeFeed" href="http://www.lefeed.com" target="_blank">LeFeed</a> is basically a facebook news feed organizer and recommendation application.</p>
<p>It uses ANN algorithms to organize users&#8217; news feed and tries to find most accurate recommendations for the users by using CF techniques.</p>
<p>It regularly updates its analyzed data and tries to know better its users.</p>
<p>LeFeed recommends new content and subjects to users, based on active user&#8217;s interests &amp; feedback and his/her friends&#8217; interests</p>
<p>I really enjoy using it, I hope some other people find that useful too.</p>
<p>Its tech stack is just great; rails 3.2, MySQL, backbone, coffeescript, sass, and others.</p>
<p>***</p>
<p>Before that, in February socivid is launched. Socivid is built in order to provide a better video experience while sharing videos on facebook.</p>
<p>I have worked on socivid with my business co-founder, Roger.</p>
<p>It is built with rails 3.1, MySQL, coffeescript.</p>
<p>&nbsp;</p>
<p>So, that&#8217;s all for now. I hope my next post will be about user growth in my project.</p>
]]></content:encoded>
			<wfw:commentRss>http://serdaryildirim.net/startups/launched-2-new-projects-in-feburary-and-april.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Recommender Systems, Collaborative Filtering Approach</title>
		<link>http://serdaryildirim.net/ai/recommender-systems-collaborative-filtering-approach.html</link>
		<comments>http://serdaryildirim.net/ai/recommender-systems-collaborative-filtering-approach.html#comments</comments>
		<pubDate>Fri, 03 Feb 2012 22:11:05 +0000</pubDate>
		<dc:creator>serdar</dc:creator>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[item-based]]></category>
		<category><![CDATA[matrix factorization]]></category>
		<category><![CDATA[memory-based]]></category>
		<category><![CDATA[model-based]]></category>
		<category><![CDATA[recommender systems]]></category>
		<category><![CDATA[recsys]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[similarity methods]]></category>
		<category><![CDATA[svd]]></category>
		<category><![CDATA[user-based]]></category>

		<guid isPermaLink="false">http://serdaryildirim.net/?p=326</guid>
		<description><![CDATA[tl;dr -&#62; <a title="Collaborative Filtering implementations in Ruby" href="https://github.com/serdary/cf_recommendation" target="_blank">ruby collaborative filtering implementations including Model-Based and SVD Approaches</a>
Getting recommendations is an important part of the decision making. Suggestions for books on Amazon, or movies on Netflix are real- world examples of recommender systems.Design of such recommendation engines depends on the domain and the available data.
Recommender [...]]]></description>
			<content:encoded><![CDATA[<p><strong>tl;dr</strong> -&gt; <a title="Collaborative Filtering implementations in Ruby" href="https://github.com/serdary/cf_recommendation" target="_blank">ruby collaborative filtering implementations including Model-Based and SVD Approaches</a></p>
<p>Getting recommendations is an important part of the decision making. Suggestions for books on Amazon, or movies on Netflix are real- world examples of recommender systems.Design of such recommendation engines depends on the domain and the available data.</p>
<p>Recommender systems can be categorized as Content Based Recommendation Systems, Collaborative Filtering Recommendation Systems and Hybrid Recommendation Systems.</p>
<p>In short,</p>
<p><strong>Content Based Recommendation:</strong> Generates recommendations according to the items active user liked before. Recommender system analyzes the content of recent items of user, and recommends new ones according analyzed data.</p>
<p><strong>Collaborative Filtering Recommendation:</strong> Generating recommendations based on active user&#8217;s previous preferences, checks all users who liked similar items. (or checks all items which are liked by users.)</p>
<p><strong>Hybrid Recommendation:</strong> Generates recommendations by combining above 2 methods.</p>
<p>There are several techniques for each category, and it is impossible to show examples for each category/approach.</p>
<p>I am mainly interested in Collaborative Filtering (CF) Approach, and in this post you can find some implementation examples of CF Approach.</p>
<h3>Why Collaborative Filtering?</h3>
<p>For me, I made long hours of research before implementing few algorithms, but in short the approach you should choose is <strong>really </strong>depends on <strong>your data</strong> and <strong>application domain</strong>.</p>
<p>If you are thinking about creating your own recommendation system (RecSys), first analyze your data, and decide what features you&#8217;ll need in your application, can you go with a content based RecSys or not.</p>
<p>According to my data and my project details, I decided the best option for me is CF, specifically <strong>Incremental SVD</strong> is a great match for me.</p>
<h3>Why Collaborative Filtering Is So Popular?</h3>
<p><strong>Netflix! </strong>In my opinion (and I think many others may agree with me) <a title="Netflix Prize" href="http://www.netflixprize.com" target="_blank">The Nexflix Price</a> is the locomotive for CF Approaches and maybe matrix factorization.</p>
<p>Netflix Prize was a competition to improve Netflix&#8217;s own algorithm by at least 10%, and the winner took $1M (waow!), it ended in 09&#8242;.</p>
<p>Ok enough history, lets talk about a bit on CF.</p>
<p>Collaborative Filtering recommendation systems work by collecting users&#8217; preferences, and generating predictions by user-based similarities or item-based similarities.</p>
<p>CF methods can be divided into 2 categoeries as, Memory (Neighborhood) Based and Model Based Approaches.</p>
<h3>Memory (Neighborhood) Based Recommendation Systems<strong><br />
</strong></h3>
<p><strong></strong>User-based or item-based techniques can be used. For user-based technique, number of similar users are found by calculating similarity (we&#8217;ll get there soon -Jaccard Index, Euclidean&#8230;-) and with a basic loop inside similar users&#8217; items, all non-rated items are found with a weighted estimated rating value. A very similar method also works for item-based technique.</p>
<p>I implemented both item-based and user-based techniques while working on recommender systems, neighborhood approach is easy to understand and implement, takes only 3 steps.</p>
<p>1. Find similarity for active user to all other users, and pick top <strong>k</strong> users (called k-Nearest Neighborhood).</p>
<p>2. Select all items that active user hasn&#8217;t rated yet.</p>
<p>3. Compute a weighted prediction rating for items</p>
<p>There are several methods to calculate similarities between items or users, and I implemented only few of them including <a title="Pearson Correlation" href="http://en.wikipedia.org/wiki/Pearson_product-moment_correlation_coefficient" target="_blank">Pearson Correlation Coefficient</a>, <a title="Euclidean Distance" href="http://en.wikipedia.org/wiki/Euclidean_distance" target="_blank">Euclidean Distance</a>, <a title="Jaccard Index" href="http://en.wikipedia.org/wiki/Jaccard_index" target="_blank">Jaccard Index</a> and <a title="Cosine Based" href="http://www10.org/cdrom/papers/519/node12.html" target="_blank">Cosine Based Similarity</a>. Again, it is best to choose similarity method according to your data and application.</p>
<p>You can see math formulas for these methods at the end of the post.</p>
<h3>Model Based Recommendation Systems</h3>
<p>Model can be developed using matrix factorization techniques, data minin, machine learning algorithms to find the patterns based on the data. This model is used to make predictions on the real data afterwards.</p>
<p>There are various Collaborative Filtering modelling algorithms including Bayesian Networks, Latent Semantic Models, Clustering Models, Singular Value Decomposition and others.</p>
<p><strong>So what&#8217;s the pros and cons over Neighborhood Based Approach?</strong></p>
<p>The main disadvantage that is worth to mention is, they are difficult to implement. (but not that much, don&#8217;t give up <img src='http://serdaryildirim.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  )</p>
<p>So the advantages are, it <strong>handles data sparsity</strong> better, provides <strong>scalability on large datasets</strong>, increases the <strong>performance of prediction</strong>.</p>
<p>I implemented <strong>Item-based SVD,</strong> <strong>User-based SVD</strong> and <strong>Incremental SVD</strong> matrix factorization techniques to see what approach suits my data more. You can check all codes from github project linked below.</p>
<p>I won&#8217;t go into details for these implementations, SVD or matrix factorization, but you can check below useful links, including the my implementations. And you should search academic materials for new developments on topic in IEEE or somewhere else, especially <a title="Munir Sarwar" href="http://www-users.cs.umn.edu/~sarwar/research.html" target="_blank">Munir Sarwar</a> and <a title="Yehuda Koren" href="http://research.yahoo.com/Yehuda_Koren" target="_blank">Yehuda Koren</a> (winner of Netflix Price)</p>
<p><a title="SVD and Memory Based CF implementations in Ruby" href="https://github.com/serdary/cf_recommendation" target="_blank">My implementations in Ruby, including SVD, Memory Based Collaborative Filtering on Github</a></p>
<p><a title="Simon Funk" href="http://sifter.org/~simon/journal/20061211.html" target="_blank">Incremental SVD by Simon Funk</a></p>
<p><a title="Incremental SVD-Based Algorithms" href="http://glaros.dtc.umn.edu/gkhome/node/129" target="_blank">Incremental SVD-Based Algorithms for Highly Scalable Recommender Systems</a></p>
<p><a title="Adomavicus - Next Gen RecSys" href="http://ids.csom.umn.edu/faculty/gedas/papers/recommender-systems-survey-2005.pdf" target="_blank">G. Adomavicus and A. Tuzhilin &#8211; Next Gen RecSys</a></p>
<p><a title="Melville RecSys" href="http://vikas.sindhwani.org/recommender.pdf" target="_blank">Prem Melville and Vikas Sindhwan &#8211; Recommender Systems</a></p>
<p><a title="Advances in Collaborative Filtering" href="http://research.yahoo.com/pub/3503" target="_blank">Advances in Collaborative Filtering &#8211; Koren Y., Bell R.</a></p>
<p>&nbsp;</p>
<p>And finally, I used publicly available MovieLens test data (mostly the package that has 100K ratings), you can download a test data here: <a title="http://www.grouplens.org/node/73" href="http://www.grouplens.org/node/73" target="_blank">http://www.grouplens.org/node/73</a></p>
<p>&#8212;</p>
<p><strong>Similarity Methods Math Formulas</strong></p>
<p><a href="http://serdaryildirim.net/wp-content/uploads/2012/02/image00.png"><img class="alignnone size-medium wp-image-328" title="Pearson Correlation" src="http://serdaryildirim.net/wp-content/uploads/2012/02/image00-300x100.png" alt="" width="300" height="100" /></a></p>
<p><em>Pearson Correlation</em><img src="data:image/png;base64,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YkwqSaFikxBEmxQSAn5gEcRCooVIqmChwSqIiMeIiIRwQJGQayHJKYJYGBQJIY0pUqhJEYJHBYng/elw5y47Hzuz786+7+7+T3GYnZ155nl+z8zs887uzq7766+//qU/ERABERABERABEUgm8O/kkiooAiIgAiIgAiIgAn8TUPSgfiACIiACIiACIpBHQNFDHi+VFgEREAEREAERuFkIREAEREAERGDQBO666y5X/6tXr7qZykkk0PhMpKKHRJIqJgIiIAIisLgErly5srjKjVEz3bkYo1dlkwiIgAiIgAiUJKDooSRdyRYBERABERCBMRJQ9DBGr8omERABERABEShJQNFDSbqSLQIiIAIiIAJjJKDoYYxelU0iIAIiIAIiUJKAooeSdCVbBERABERABMZIQNHDGL0qm0RABERABESgJAFFDyXpSrYIiIAIiIAIjJGAoocxelU2iYAIiIAIiEBJAtprsiRdyRYBERABEShP4Ndff81t5Keffnr99ddXV1ePHj16+vTpa9euXbp06cyZM7lyJlte0cNkXS/DRUAERGAkBNatW5drydtvv728vLxhw4aVlRUSVG8hJLfRMZVf1/gljDFZK1tEQAREQATGR4CvZOV+54K1Bzhs3rz5xo0bJM6dO/fII4+sra2ND04hi/TcQyGwEisCIiACIrC4BO65556PP/6Y6MGo+M477zz++OOLq+7iaaboYfF8Io1EQAREQATKEzh16hTrDaadEydO8BjEK6+8Ur7ZkbSg6GEkjpQZIiACIiACWQQuX7584MABU2XLli3Hjx9fWlrKkjDlwnruYcrel+0iIAIiMAYCLZ57GIPZc7VBaw9zxa/GRUAEREAERGCABBQ9DNBpUlkEREAEREAE5kpA0cNc8atxERABERABERggAUUPA3SaVBYBERABERCBuRLQXpNzxT+WxnnN6ciRI2OxRnaIgAi0JKDtB1uCG2A1vXMxQKctnsp64HnxfCKNRGBCBG677bbffvvNNZiNqFt8AsOVc/DgwbfeesvNn3KO7lxM2fvd2P7cc8/t37+/G1mSIgIiIAL5BG655RZvpUOHDpn8m2+++ccff2RppPGPYt98882bb7755JNP3nnnnab6u+++65U/5cwOogezW3gPEHtrKMuW3rTqraEs8yl88uRJb1S+sArHDVwQtRdEjTgr9+xA1XYN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" alt="" width="545" height="80" /><em></em></p>
<p><em>Euclidean Distance</em></p>
<p><em></em><img src="data:image/png;base64,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" alt="" /></p>
<p><em>Jaccard Index</em><em></em></p>
<p><img src="data:image/png;base64,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" alt="" /></p>
<p><em>Cosine Based</em></p>
]]></content:encoded>
			<wfw:commentRss>http://serdaryildirim.net/ai/recommender-systems-collaborative-filtering-approach.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Creating People Groups Using Genetic Algorithm</title>
		<link>http://serdaryildirim.net/ai/creating-people-groups-using-genetic-algorithm.html</link>
		<comments>http://serdaryildirim.net/ai/creating-people-groups-using-genetic-algorithm.html#comments</comments>
		<pubDate>Thu, 22 Dec 2011 22:21:58 +0000</pubDate>
		<dc:creator>serdar</dc:creator>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[2-opt]]></category>
		<category><![CDATA[ai]]></category>
		<category><![CDATA[clustering]]></category>
		<category><![CDATA[GA]]></category>
		<category><![CDATA[Genetic Algorithm]]></category>
		<category><![CDATA[group people]]></category>
		<category><![CDATA[local search]]></category>
		<category><![CDATA[optimization]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://serdaryildirim.net/?p=295</guid>
		<description><![CDATA[update: check out <a title="group people - genetic algorithm" href="https://github.com/serdary/GroupPeople" target="_blank">https://github.com/serdary/GroupPeople</a> for source code.
Genetic Algorithm is great, it is lots of fun to write GA codes.
GA is very useful on optimization problems, but in many cases, you won&#8217;t get a huge optimization if you use only GA on a problem (at least that is my [...]]]></description>
			<content:encoded><![CDATA[<p>update: check out <a title="group people - genetic algorithm" href="https://github.com/serdary/GroupPeople" target="_blank">https://github.com/serdary/GroupPeople</a> for source code.</p>
<p><strong>Genetic Algorithm</strong> is great, it is lots of fun to write GA codes.</p>
<p>GA is very useful on optimization problems, but in many cases, you won&#8217;t get a huge optimization if you use only GA on a problem (at least that is my experience).<br />
I started adding a <strong>Local Search Algorithm</strong> (2-opt) with Genetic Algorithm (thanks to AI Prof. Ugur), and the results are better now.</p>
<p>I am not gonna go into detail on Genetic Algorithm here. Cause there are already lots of great resource about Genetic Algorithm. Instead I&#8217;ll share some of my experience on GA.</p>
<p>Here, I shared one of my Genetic Algorithm project that is written with <strong>Ruby</strong>.<br />
It is not a simple program, so you may find this a little complex if you are new to GA.</p>
<p><strong>Group People </strong></p>
<p>Shortly, it finds sub-groups that have similar people from a large group.</p>
<p>Let&#8217;s say you have a list of 100 people, and want to create sub groups that have most similar people to each other.</p>
<p>There are various ways to achieve that, and GA is one of them.</p>
<p>So here is the details..</p>
<p>I created a test class (group_people_test.rb) to test the program. As you can in that file, I created random people and interests (all configurable).</p>
<p>With these people, I created an instance of GroupPeople class and let that run and find the sub-groups.</p>
<p>In GroupPeople class (group_people.rb), there are various Constant values that you can play and see the difference of results.</p>
<p>Some of them are: Population size, Generation count, crossover type, selection type and muration rate.</p>
<p>In this class, I created an initial population with some chromosomes include random people.</p>
<p>After this simple step, program generates new generations as much as the specified generation count.</p>
<p>In each generation process, there are lots of things going on, but mainly;</p>
<ol>
<li>Choose the <strong>elitist</strong> chromosome (if ELITISM is activated on GroupPeople)</li>
<li>Select 2 parent chromosomes by a <strong>selection</strong> type to apply crossover. (selection type is specified on GroupPeople)</li>
<li>Apply <strong>crossover</strong> according to crossover type. (crossover type is specified on GroupPeople)</li>
<li>Apply <strong>mutation</strong> to new chromosomes according to mutation rate if mutation is activated</li>
<li>Eliminate worst chromosomes if population size is bigger than old population size (this may occur if elitism is active)</li>
</ol>
<p>For each step, execution may be changed according to Genetic Algorithm parameters that are defined in GroupPeople class.</p>
<p>There are 2 different chromosome <strong>selection type</strong>, <span style="text-decoration: underline;"><em>rank_selection</em></span> and <em><span style="text-decoration: underline;">random</span></em>.</p>
<p>random is just for experimental, it perform <strong>*really*</strong> not good on big populations.</p>
<p>There are 3 different <strong>crossover types</strong>, <em><span style="text-decoration: underline;">1point, 2point </span></em>and<em><span style="text-decoration: underline;"> uniform</span></em></p>
<p>You can try them all and decide what best fits for your project.</p>
<p><strong>Mutation rate</strong> is 3% as default, it may be disabled by changing to zero or a different value.</p>
<p>The last step is actually about elitism.</p>
<p>When you choose the best chromosome in a population as elitist, there will be 1 additional chromosome at the end of all chromosomes are crossoverred. So I removed the worst chromosome from population if elitism is active.</p>
<p>Currently, it only performs crossover on people. My initial thought was to apply all actions (crossover, mutation and elitism) on groups as well.</p>
<p>i.e: chromosome1: Group1 (FitnessValue=5) , Group2 (FV=3), Group3 (FV=1), Group4 (FV=2.5), Group5 (FV=2)</p>
<p>Choose Group1 as elitist group, apply crossover and mutation over groups etc.</p>
<p>Maybe I can add that feature in future version to see the differences and possible improvements.</p>
<p>So what is the result?</p>
<p>As you can see there is varying improvement on latest fitness values of chromosomes. But not as much as I thought.</p>
<p>I already mentioned about applying a local search algorithm (2-opt, 3-opt..) increases the effect of algorithm but I did not apply here.</p>
<h6>Crossover Type                  Initial Fitness Value         Improved Fitness Value     Generation Count            Group Size          RunningTime (secs)</h6>
<p><img src="data:image/png;base64,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" alt="" width="679" height="132" /></p>
<p>As always, you can <a title="fork the source code on github" href="https://github.com/serdary/GroupPeople" target="_blank">fork the source code on github</a>, and feel free to browse <a title="my repo" href="https://github.com/serdary" target="_blank">my repo</a>.</p>
<p>Any feedback <strong>{ :question / :comment / :correction / :etc }</strong> is highly appreciated, thanks for reading.</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://serdaryildirim.net/ai/creating-people-groups-using-genetic-algorithm.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Backbone JS &#8211; Facebook News Feed Example</title>
		<link>http://serdaryildirim.net/js/backbone-js-facebook-news-feed-example.html</link>
		<comments>http://serdaryildirim.net/js/backbone-js-facebook-news-feed-example.html#comments</comments>
		<pubDate>Wed, 30 Nov 2011 22:02:34 +0000</pubDate>
		<dc:creator>serdar</dc:creator>
				<category><![CDATA[JS]]></category>
		<category><![CDATA[backbone]]></category>
		<category><![CDATA[coffeescript]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[js]]></category>
		<category><![CDATA[koala]]></category>
		<category><![CDATA[mvc]]></category>
		<category><![CDATA[rails 3.1]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://serdaryildirim.net/?p=251</guid>
		<description><![CDATA[update: check out <a href="https://github.com/serdary/backbone-facebook-newsfeed" title="backbone facebook news feed" target="_blank">https://github.com/serdary/backbone-facebook-newsfeed</a> for source code.
<a href="http://documentcloud.github.com/backbone/" title="backbone" target="_blank">Backbone.js</a> is a javascript framework and I just started using backbone along with coffeescript for my new 2 projects.
In this tutorial, I&#8217;ll develop a simple backbone javascript application that fetches logged in facebook user&#8217;s news feed and lets the user [...]]]></description>
			<content:encoded><![CDATA[<p><em>update: check out <a href="https://github.com/serdary/backbone-facebook-newsfeed" title="backbone facebook news feed" target="_blank">https://github.com/serdary/backbone-facebook-newsfeed</a> for source code.</em></p>
<p><a href="http://documentcloud.github.com/backbone/" title="backbone" target="_blank">Backbone.js</a> is a javascript framework and I just started using backbone along with coffeescript for my new 2 projects.</p>
<p>In this tutorial, I&#8217;ll develop a simple backbone javascript application that fetches logged in facebook user&#8217;s news feed and lets the user share a new status message.<br />
I used koala gem for facebook open graph.</p>
<p>You can use <a href="http://jashkenas.github.com/coffee-script/" title="coffeescript" target="_blank">coffeescript</a> instead of pure javascript, I&#8217;ll probably add coffeescript version of this simple app in part 2.</p>
<p>Backbone is a great framework if you will create a heavy-js app. It may have some differences than traditional MVC pattern, like views can be used as controllers. But if you know MVC pattern, it won&#8217;t take too much time to learn backbone.</p>
<p>I assume you know the basics of rails, so I will not add rails related stuff all the time.</p>
<p>In short, backbone has Model, Collection, Router and View.<br />
Model is just like rails models.<br />
Collection provides some extra functionality to model groups like sorting and filtering.<br />
Router acts as rails controllers and routes definitions to map urls to actions.<br />
Views = rails views. We can (should) use a templating library something like mustache, haml or jquery templates to separate html from javascript views.</p>
<p>I&#8217;ll structure js codes in assets/javascript/backbone, just like:</p>
<p><strong>app<br />
&#8211;assets<br />
&#8212;-javascripts<br />
&#8212;&#8212;backbone<br />
&#8212;&#8212;&#8211;models</strong><br />
&#8212;&#8212;&#8212;-feed.js<br />
<strong>&#8212;&#8212;&#8211;routers</strong><br />
&#8212;&#8212;&#8212;-feeds_router.js<br />
<strong>&#8212;&#8212;&#8211;views<br />
&#8212;&#8212;&#8212;-feeds</strong><br />
&#8212;&#8212;&#8212;&#8212;new_view.js<br />
&#8212;&#8212;&#8212;&#8212;show_view.js<br />
&#8212;&#8212;&#8212;&#8212;index_view.js<br />
&#8212;&#8212;myfeed.js<br />
&#8212;&#8212;backbone-min.js<br />
&#8212;&#8212;underscore-min.js</p>
<p>p.s: if you&#8217;ll use <a href="http://jashkenas.github.com/coffee-script/" title="coffeescript" target="_blank">coffeescript</a>, I strongly recommend <a href="https://github.com/codebrew/backbone-rails" title="backbone-rails gem" target="_blank">backbone-rails gem</a> which creates this structure (and more) for you with a simple command.</p>
<p>After creating this folder structure, we need to add some require and require_tree directives to application.js and myfeed.js file.<br />
You can see all the <em>requires directives</em> on <a href="https://github.com/serdary/backbone-facebook-newsfeed" title="backbone facebook news feed" target="_blank">github</a>, now lets start the application with a rails controller and feed model.</p>
<p>Lets create first controller, the main entry point of app, <strong>home controller</strong> with a simple index action and make it homepage via routes.rb file.</p>
<p>Now, change the index.html.erb view under home controller to call our app&#8217;s init function.</p>
<pre>
&lt;h1&gt;
	&lt;a href=&quot;#&quot;&gt;My Facebook Feeds&lt;/a&gt;
&lt;/h1&gt;

&lt;div id=&quot;notice&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;

&lt;script type=&quot;text/javascript&quot;&gt;
    $(function() {
        App.init();
    });
&lt;/script&gt;
</pre>
<p><strong>Model</strong></p>
<pre>
App.Models.Feed = Backbone.Model.extend({
	defaults: {
		from_name: null,
		from_id: null,
		message: null,
		feed_type: null,
		like_count: null
	}
});
App.Collections.Feeds = Backbone.Collection.extend({
	model: App.Models.Feed,
	url: '/feeds'
});
</pre>
<p>I just defined the default values for the feed model properties and created a feeds collection which has a model property points Feed and a url points /feeds (we&#8217;ll create a feeds controller in a moment)</p>
<p><strong>Router</strong><br />
The only router will be feed_router for this app. We&#8217;ll add the routes to call related actions.</p>
<pre>
App.Routers.FeedsRouter = Backbone.Router.extend({
	feeds: {},
	initialize: function() {
		// create a new object to hold feeds collection
		feeds = new App.Collections.Feeds();
	},
	routes: {
		''      : 'index',
		'/index': 'index',
		'/new'  : 'newFeed',
		'/:id'  : 'show'
	},
	index: function() {
		var view = new App.Views.IndexView(feeds);
		$('#app').html(view.render().el);
	},
	show: function(id) {
		console.log('index'+id);
	},
	newFeed: function() {
		console.log('newFeed');
	}
});
</pre>
<p>So after creating this router, if you wanna try your app, you may get &#8220;Backbone.history is undefined&#8221; error on your console. I have spent 15 mins to resolve that, the reason is you don&#8217;t have any routes on your controller. (I had routes but I mistyped as &#8216;routers&#8217;, so that resulted an error)</p>
<p><strong>View</strong></p>
<pre>
App.Views.IndexView = Backbone.View.extend({
	initialize: function() {
		this.feeds = this.options.feeds;
	},

	addAll: function() {
		if (this.feeds === undefined || this.feeds.length &lt; 1) {
    		$(this.el).find(&quot;tbody&quot;).append('no feeds yet');
    		return;
		}
		// TODO: use haml-js or jquery templates
		var view = '';
		var template = '&lt;tr&gt;&lt;td&gt;[from_name]&lt;/td&gt;&lt;td&gt;[message]&lt;/td&gt;&lt;td&gt;[feed_type]&lt;/td&gt;&lt;td&gt;[like_count]&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;#/[id]&quot;&gt;Show&lt;/td&gt;&lt;/tr&gt;';
		for (var i = 0; i &lt; this.feeds.models.length; i++) {
			var feed = this.feeds.models[i].attributes;
			view += template.replace('[from_name]', feed.from_name).replace('[message]', feed.message)
				.replace('[feed_type]', feed.feed_type).replace('[like_count]', feed.like_count).replace('[id]', feed.id);
		}

    		$(this.el).find(&quot;tbody&quot;).append(view);
	},

	render: function() {
		var table = '&lt;h1&gt;Feeds&lt;/h1&gt;&lt;a href=&quot;#/new&quot;&gt;New Feed&lt;/a&gt;&lt;table&gt;&lt;tr&gt;&lt;th&gt;From&lt;/th&gt;&lt;th&gt;Message&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Like count&lt;/th&gt;&lt;/tr&gt;&lt;/table&gt;';
		$(this.el).html(table);
		this.addAll();
		return this; // chain
	}
});
</pre>
<p>At this point, you should get the index view with an empty table and a warning, as &#8216;no feeds yet&#8217;.<br />
So it&#8217;s clear that we need feeds to try index page and show page. I could add facebook open graph related codes here but it may distract the backbone subject, so I&#8217;ll just create a <strong>feeds controller</strong> and a dummy json feeds response for now.</p>
<p><strong>Feeds Controller</strong></p>
<pre>
class FeedsController < ApplicationController
  def index
    #dummy
    feeds = [{ :id => 1, :from_name => 'dummy from1', :message => 'dummy message1', :feed_type => 'dummy feed_type1',
      :like_count => 'dummy like_count 1' },
      { :id => 2, :from_name => 'dummy from2', :message => 'dummy message2', :feed_type => 'dummy feed_type2',
      :like_count => 'dummy like_count 2' }]

    render :json => feeds
  end
  def create
  end
end
</pre>
<p>Now, we should have a working feed listing page. Let&#8217;s add a separate show page for items.<br />
<strong>Show View</strong></p>
<pre>
App.Views.ShowView = Backbone.View.extend({
	render: function() {
		var template = '&lt;b&gt;From name:&lt;/b&gt;&lt;em&gt;[from_name]&lt;/em&gt;&lt;b&gt;message:&lt;/b&gt;&lt;em&gt;[message]&lt;/em&gt;&lt;a href=&quot;#&quot;&gt;home&lt;/a&gt;';

		var view = template.replace('[from_name]', this.model.attributes.from_name).replace('[message]', this.model.attributes.message);
		$(this.el).html(view);
		return this;
	}
});
</pre>
<p><strong>Router &#8211; Show Action</strong></p>
<pre>
App.Routers.FeedsRouter = Backbone.Router.extend({
...
	show: function(id) {
		var feed = feeds.get(id);
		var view = new App.Views.ShowView({ model: feed });

		$('#app').html(view.render().el);
	}
...
});
</pre>
<p>Now lets implement javascript part of the create action, then we need to start coding facebook open graph stuff to finalize the app.</p>
<p><strong>New View</strong></p>
<pre>
App.Views.NewView = Backbone.View.extend({
	initialize: function() {
		this.collection = this.options.collection;
		this.model = new this.collection.model();
	},
	events: {
		'submit #new-feed' : 'save'
	},
	render: function() {
		var template = '&lt;h1&gt;New feed&lt;/h1&gt;&lt;form id=&quot;new-feed&quot; name=&quot;feed&quot;&gt;&lt;div&gt;&lt;b&gt; message:&lt;/b&gt;&lt;input type=&quot;text&quot; name=&quot;message&quot; id=&quot;message&quot; /&gt;&lt;/div&gt;&lt;div&gt;&lt;input type=&quot;submit&quot; value=&quot;Create Feed&quot; /&gt;&lt;/div&gt;&lt;/form&gt;&lt;a href=&quot;#&quot;&gt;Home&lt;/a&gt;';

		$(this.el).html(template);
		return this;
	},
	save: function() {
		this.collection.create({ message: $('#message').val() }, {
			success: function(feed) {
	  			this.model = feed;
	  			//window.location.hash = '#/' + this.model.id
	  			window.location.hash = '#'
  			},
  			error: function(feed) {
  			}
  		});
  		return false;
	}
});
</pre>
<p><strong>Router &#8211; New Action</strong></p>
<pre>
App.Routers.FeedsRouter = Backbone.Router.extend({
...
	newFeed: function() {
		var view = new App.Views.NewView({ collection: feeds });

		$('#app').html(view.render().el);
	}
...
});
</pre>
<p><strong>Connect to Facebook Open Graph</strong><br />
Now we need to let users connect app via their facebook account and fetch their news feed, update their status.<br />
To provide this, I&#8217;ll use awesome <a href="https://github.com/arsduo/koala" title="koala gem" target="_blank">koala gem</a>.</p>
<p><strong>1.</strong> create a new facebook app and get app_id, app_secret.<br />
<strong>2.</strong> add koala gem to Gemfile<br />
gem &#8220;koala&#8221;</p>
<p><strong>3.</strong> create a new rails controller with connect_fb and fb_callback actions<br />
rails g controller sessions connect_fb fb_callback<br />
<strong>4.</strong> check if the user is logged in. Do this for all the actions for all controllers, so add a before_filter to ApplicationController method to main controller.</p>
<pre>
class ApplicationController < ActionController::Base
  before_filter :authorize
  protect_from_forgery

  protected
  def authorize
    is_user_logged_in
    # TODO: redirect to root_url if not authorized
  end
  private
  def is_user_logged_in
    @user_logged_in = session[:fb_access_token] != nil
  end
end
</pre>
<p><strong>5.</strong> Add a facebook login link to home/index view.</p>
<pre>
..
<% unless @user_logged_in %>
	<%= link_to 'Connect Facebook', sessions_connect_fb_path, { :class => 'fb_connect_btn' } %>
<% end %>
..
</pre>
<p><strong>6.</strong> Add routes for session controller to routes.rb file</p>
<p>Then the only thing left is creating callback action and redirecting user to facebook with a callback url. So here it is:</p>
<pre>
class SessionsController < ApplicationController
  def connect_fb
    app_id = '' # Your app_id
    app_secret = '' # Your app_secret
    session[:oauth] = Koala::Facebook::OAuth.new(app_id, app_secret, sessions_fb_callback_url)

    redirect_to session[:oauth].url_for_oauth_code(:permissions => "publish_stream,read_stream")
  end
  def fb_callback
    if params[:code].blank?
      redirect_to root_url, :notice => 'You should allow app to connect your Facebook account'
      return
    end
    session[:fb_access_token] = session[:oauth].get_access_token(params[:code])
    redirect_to root_url, :notice => 'FB Connected!'
  end
end
</pre>
<p>I've added below code piece to application.js, it is a facebook connect hotfix. When facebook call-backs your app, it adds an hash and some chars, so we need to remove it to start our js app.<br />
$(function() {<br />
  // fb connect redirect hotfix<br />
  if (window.location.hash === '#_=_') {<br />
  	window.location.hash = '';<br />
  }<br />
});</p>
<p>Now our app can connect to facebook, so we can actually fetch user's news feed and post user's status messages to facebook open graph API.</p>
<p><strong>FeedsController - working with real facebook news feed data</strong></p>
<pre>
class FeedsController &lt; ApplicationController
  def index
    unless session[:fb_access_token]
      render :json =&gt; {}
      return
    end

    begin
      graph = Koala::Facebook::API.new(session[:fb_access_token])
      result = graph.get_connections('me', 'home')
      feeds = create_feed_objects(result)
    rescue Exception =&gt; ex
      session[:fb_access_token] = nil
      logger.error &quot;Exception - #{ex}&quot;
    end

    render :json =&gt; feeds
  end

  private
  def create_feed_objects(result)
    feeds = []
    result.each do |feed|
      from_name = feed['from'].is_a?(Hash) ? feed['from']['name'] : ''
      from_id = feed['from'].is_a?(Hash) ? feed['from']['id'] : ''
      like_count = feed['likes'].is_a?(Hash) ? feed['likes']['count'] : 0
      message = (feed['type'] == 'link' or feed['message'].blank?) ? feed['story'] : feed['message']

      feeds.push({ :id =&gt; feed['id'], :from_name =&gt; from_name, :from_id =&gt; from_id, :like_count =&gt; like_count,
        :feed_type =&gt; feed['type'], :message =&gt; message })
    end
    feeds
  end
end
</pre>
<p><strong>FeedsController - post status messages to facebook open graph</strong></p>
<pre>
class FeedsController &lt; ApplicationController
...
  def create
    return unless session[:fb_access_token]

    begin
      graph = Koala::Facebook::API.new(session[:fb_access_token])
      obj_id = graph.put_wall_post(params[:feed][:message])

      #feed = create_feed_objects(graph.get_object(obj_id))[0]
      feed = {}
    rescue Exception =&gt; ex
      session[:fb_access_token] = nil
      logger.error &quot;Exception - #{ex}&quot;
    end

    render :json =&gt; feed
  end
...
</pre>
<p>So with these latest changes, a simple backbone javascript mvc app is ready.<br />
It displays the news feed of logged in user, post new status messages as logged in user, by using facebook open graph API.</p>
<p>koala gem is used for facebook graph calls and authentication, backbone framework is used to organize the js code.</p>
<p>Please check the source code of <a href="https://github.com/serdary/backbone-facebook-newsfeed" title="backbone news feed" target="_blank">backbone news feed on github</a>, and let me know your thoughts!</p>
]]></content:encoded>
			<wfw:commentRss>http://serdaryildirim.net/js/backbone-js-facebook-news-feed-example.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Developing Javascript MVC Application</title>
		<link>http://serdaryildirim.net/js/developing-javascript-mvc-application.html</link>
		<comments>http://serdaryildirim.net/js/developing-javascript-mvc-application.html#comments</comments>
		<pubDate>Fri, 04 Nov 2011 12:00:53 +0000</pubDate>
		<dc:creator>serdar</dc:creator>
				<category><![CDATA[JS]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[js mvc application]]></category>
		<category><![CDATA[mvc]]></category>
		<category><![CDATA[notebook mvc app]]></category>

		<guid isPermaLink="false">http://serdaryildirim.net/?p=194</guid>
		<description><![CDATA[update: full source code on github: <a href="https://github.com/serdary/JavaScript-MVC-NoteBook-App" target="_blank">https://github.com/serdary/JavaScript-MVC-NoteBook-App</a>
demo: <a href="http://serdaryildirim.net/javascript-mvc-application-notebook-demo.html" target="_blank">notebook js mvc application</a>
Recently I needed to create a basic javascript web application that is written with Model-View-Controller Architecture.
There are some good JS tools (MVC-MVVM) that lots of startups and bigger companies use, such as <a href="http://knockoutjs.com/" target="_blank">knockout</a>, <a href="http://javascriptmvc.com/" target="_blank">javascriptmvc</a>.
But if you don&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<p><strong>update</strong>: full source code on github: <a href="https://github.com/serdary/JavaScript-MVC-NoteBook-App" target="_blank">https://github.com/serdary/JavaScript-MVC-NoteBook-App</a><br />
demo: <a href="http://serdaryildirim.net/javascript-mvc-application-notebook-demo.html" target="_blank">notebook js mvc application</a></p>
<p>Recently I needed to create a basic javascript web application that is written with Model-View-Controller Architecture.</p>
<p>There are some good JS tools (MVC-MVVM) that lots of startups and bigger companies use, such as <a href="http://knockoutjs.com/" target="_blank">knockout</a>, <a href="http://javascriptmvc.com/" target="_blank">javascriptmvc</a>.</p>
<p>But if you don&#8217;t need something that complex, or you just want to write your own js mvc structure app from scratch, unfortunately, there isn&#8217;t lots of resource about this, so I created a mini notebook javascript MVC app.</p>
<p>It is not using any external libraries, such as jquery. It is purely written with javascript and I tried to avoid any non-crossbrowser built-in functions, like Array.indexOf. So I suppose it should work on most browsers.</p>
<p>Notebook App has around 400 LoC, so I&#8217;m not gonna add whole app here, but you can check from <a href="https://github.com/serdary/JavaScript-MVC-NoteBook-App" target="_blank">github</a>. Please feel free to add your comments/corrections.</p>
<h2>NoteBook Javascript MVC App</h2>
<p>I&#8217;m not gonna explain MVC architecture here in detail, but here is some important points;<br />
view should know nothing about the models and model should be about the data.<br />
If you need to fetch data from server or insert/change data on server, this should be done in models.<br />
And when a model changes, it should notify all the related view(s) about the changes.<br />
<a href="http://en.wikipedia.org/wiki/Observer_pattern" target="_blank">Observer Pattern</a> can be used to provide this functionality.</p>
<h3>EventObserver</h3>
<p>I created below EventObserver class to provide this notification system, flow is generally as follows:<br />
- when the model is created, it adds events that are related.<br />
- view attaches observers to an event.<br />
- when a model changed (a method may be triggered on model etc.), it notifies the attached observers for the event, with optional data parameter.</p>
<pre>var EventObserver = function(events) {
	var _eventObservers = {};
	// adds an event if it is not added before
	var addEvent = function(event) { };

	// notifies the attached observers to the event with data param
	var notify = function(event, data) { };

	// attaches an observer to the event if it is not already attached
	var attach = function(event, observer) { };

	// public methods for notifying and attaching observers
	return {
		notifyObservers: function(event, data) {
			notify(event, data);
		},
		attachObserver: function(event, observer) {
			attach(event, observer);
		}
	};
}</pre>
<h3>Models</h3>
<p>I created 2 models for notebook app.</p>
<p>First one is <strong>Note Model</strong>. Class has <em>_id</em> and <em>_content</em> properties, which is very basic.<br />
It has a private setter for id and some public methods such as <strong>save(), remove(), toString()</strong> and <strong>getters</strong>.<br />
I have added 2 dummy methods (saveDummy() and removeDummy()) for testing purposes. In a real production app, save and remove methods will probably make an ajax call to server and methods will change the object state according to the operation result on server.<br />
But in these dummy methods, it simply makes the value of <em>_id</em> -1 after removeDummy() called and assigns an incremental value to <em>_id</em> when saveDummy() method called.</p>
<pre>// note model
var Note = function(content) {
	// private vars
	var _id;
	var _content = content;

	// setter
	var setId = function(id) {
		_id = id;
	};

	return {
		// getters

		// saves the current note
		save: function() {
			// all model validations go here
			if (_content === undefined || _content === '') {
				return false;
			}
			/*
			Make an ajax call to server, save the note and get id, i.e.:
			$.ajax({
				url: 'note/create',
				... });
			*/
		},

		// removes the note, returns the result
		remove: function() { },

		// used for testing the app without tiding an actual db,
		// identifiers are set by externally from the list
		saveDummy: function(dummyAutoId) {
		},

		// removes the note, returns the result
		removeDummy: function() {
		},
		toString: function() { }
	};
};</pre>
<p>Second model is <strong>NoteList Model</strong> which holds a list of notes and an eventObservers object.<br />
NoteList object provides the functionality to add / remove new notes and attach observers to the list events.</p>
<pre>var NoteList = function() {
	var _list = [];
	// add the events which will be used to attach and notify observers
	var _eventObservers = EventObserver(['noteAdd', 'noteRemove']);
	return {
		// getter for the list
		getList: function() { },

		// adds a note to the list
		addNote: function(note) { },

		// removes a note from list
		removeNote: function(note) { },

		// used to attach an observer to an event
		attachObserver: function(event, observer) { },

		toString: function() { },

		// adds dummy notes to the list -- used to test the listing feature
		addDummyNotes: function(limit) { }
	};
};</pre>
<p>Ok now lets create some views and a controller for the app.<br />
I created 2 views for the app, a <strong>list view</strong> class and an <strong>add note view</strong> class.</p>
<h3>Views</h3>
<p><strong>addEventListener</strong> functions are used to call the controller methods when a remove note link is clicked or a new note form is submitted. See the usage for submit form button below, </p>
<pre>
	// submit button for the add form
	var addButton = document.createElement('input');
	addButton.type = 'submit';
	addButton.value = 'add note';
	addButton.addEventListener('click', function(e) {
		e.preventDefault(); // prevent the link element's default behavior.
		noteController.handleAddEvent(textboxElement.value, noteList);
	}, false);
	// the last false parameter is about an event bubbling cross browser issue.
	//No need to detail right now.
</pre>
<p><strong>List View</strong> has 3 major methods,<br />
<strong><em>displayAllNotes</em></strong>: displays all the notes in the list. Called when the app is initialized.</p>
<p><strong><em>updateListAfterRemoving</em></strong>: updates the note list on browser when user triggered remove a note event.<br />
This observer is attached for <strong>noteRemove</strong> event when the view is created. So when noteRemoved event is triggered by the user, controller calls the appropriate method (<em>NoteList.removeNote</em> in this case), and the method notifies this function by using EventObserver object.</p>
<p><strong><em>updateListAfterAdding</em></strong>: updates the note list when user submits a new note.<br />
Same as updateListAfterRemoving, this observer method is called when the model changed.</p>
<pre>var NoteListView = function(noteList, noteController) {
	// empties list wrapper and displays all of the user's notes.
	// if user has no notes, then displays a warning message
	var displayAllNotes = function() {
		var listWrapper = document.getElementById('list_wrapper');
		for (var i = 0; i &lt; list.length; i++) {
			listWrapper.appendChild(createNoteElement(list[i]));
		}
	};

	// called from EventObserver class when user removed a note from the list
	// gets data from model, removes the note if it is removed successfully
	// adds a feedback message to browser
	var updateListAfterRemoving = function(data) { };

	// called from EventObserver class when user added a note to the list
	// gets data from model, adds the note to the end of the list, if it is added successfully
	// adds a feedback message to browser
	var updateListAfterAdding = function(data) { };

	// attach add and remove observers for the related events
	noteList.attachObserver('noteAdd', updateListAfterAdding);
	noteList.attachObserver('noteRemove', updateListAfterRemoving);

	return {
		// a public method to display the whole note list
		displayList: function() {
			displayAllNotes();
		}
	};
};</pre>
<p><strong>Note Add View</strong> has just 1 method which displays the &#8220;add a new note form&#8221;.<br />
Method is called when the app is initialized.</p>
<pre>var NoteAddView = function(noteList, noteController) {
	return {
		// displays the add form
		displayForm: function() {
		}
	};
};</pre>
<h3>Controller</h3>
<p><strong>Note Controller</strong> is the main controller for this basic app.<br />
It has 2 handlers for <strong>addEvent</strong> and <strong>removeEvent</strong> and a <strong>displayNoteList</strong> public method to display all notes when the app starts.</p>
<pre>var NoteController = function() {
	return {
		// handles the add event when a new form is submitted
		// creates a new note instnace and add to the notelist if it is valid
		handleAddEvent: function(content, noteList) {
			var note = Note(content);
			noteList.addNote(note);
		},
		// handles the remove event when user click the remove button
		// gets the note as param, remove it from the list
		handleRemoveEvent: function(note, noteList) {
			noteList.removeNote(note);
		},
		// triggered from webpage. Creates an empty list, shows add form and the note list to user.
		displayNoteList: function() {
			var noteList = NoteList();
			var noteAddView = NoteAddView(noteList, this);
			noteAddView.displayForm();
			var noteListView = NoteListView(noteList, this);
			noteListView.displayList();
		}
	};
};</pre>
<p>A basic html markup for this app might be as follows.<br />
It creates a new <strong>NoteController</strong> object and displays all the notes.</p>
<pre>
&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;Javascript MVC Notebook&lt;/title&gt;
  &lt;script type=&quot;text/javascript&quot; src=&quot;notebook.js&quot;&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
	&lt;div id=&quot;wrapper&quot;&gt;
		Javascript MVC Application - NoteBook
		&lt;div id=&quot;message&quot;&gt;&lt;/div&gt;
		&lt;div id=&quot;new_note_wrapper&quot;&gt;&lt;/div&gt;
		&lt;div id=&quot;list_wrapper&quot;&gt;&lt;/div&gt;
	&lt;/div&gt;
	&lt;script type=&quot;text/javascript&quot;&gt;
		var controller = NoteController();
		controller.displayNoteList();
	&lt;/script&gt;
&lt;/body&gt;
&lt;&#47;html&gt;
</pre>
<p>2 great blog posts, you should also check them out:<br />
<a href="http://michaux.ca/articles/mvc-architecture-for-javascript-applications" target="_blank">MVC Architecture for JavaScript Applications</a><br />
<a href="http://www.alistapart.com/articles/javascript-mvc/" target="_blank">Javascript mvc</a></p>
<p>That&#8217;s it!<br />
If you have any questions, fixes or suggestions, please add your comments.<br />
Thanks for reading!</p>
]]></content:encoded>
			<wfw:commentRss>http://serdaryildirim.net/js/developing-javascript-mvc-application.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Twitter Mass Follow App</title>
		<link>http://serdaryildirim.net/ruby-on-rails/twitter-mass-follow-app.html</link>
		<comments>http://serdaryildirim.net/ruby-on-rails/twitter-mass-follow-app.html#comments</comments>
		<pubDate>Wed, 02 Nov 2011 14:27:35 +0000</pubDate>
		<dc:creator>serdar</dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[rails 3.1]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://serdaryildirim.net/?p=181</guid>
		<description><![CDATA[If you need a starter for twitter API or omniauth gem, take a look at this app. You can find sample usages of changing friendship (follow or unfollow) and using search API of twitter.
Source code: <a href="https://github.com/serdary/massfollow" target="_blank">https://github.com/serdary/massfollow</a>
Demo: <a title="Twitter Mass Follow" href="http://massfollow.net/" target="_blank">Twitter Mass Follow</a>
This basic twitter mass follow/unfollow app has been created for [...]]]></description>
			<content:encoded><![CDATA[<p>If you need a starter for twitter API or omniauth gem, take a look at this app. You can find sample usages of changing friendship (follow or unfollow) and using search API of twitter.</p>
<p>Source code: <a href="https://github.com/serdary/massfollow" target="_blank">https://github.com/serdary/massfollow</a><br />
Demo: <a title="Twitter Mass Follow" href="http://massfollow.net/" target="_blank">Twitter Mass Follow</a></p>
<p>This basic twitter mass follow/unfollow app has been created for working with twitter API and oauth.</p>
<p>omnioauth library is used for oauth communication, configatron gem is for creating a site config and the famous will_paginate gem is used.</p>
]]></content:encoded>
			<wfw:commentRss>http://serdaryildirim.net/ruby-on-rails/twitter-mass-follow-app.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Finding Friends of Friends using Prolog</title>
		<link>http://serdaryildirim.net/ai/finding-friends-of-friends-using-prolog.html</link>
		<comments>http://serdaryildirim.net/ai/finding-friends-of-friends-using-prolog.html#comments</comments>
		<pubDate>Tue, 01 Nov 2011 16:39:55 +0000</pubDate>
		<dc:creator>serdar</dc:creator>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[ai]]></category>
		<category><![CDATA[fof]]></category>
		<category><![CDATA[friends of friends]]></category>
		<category><![CDATA[prolog]]></category>
		<category><![CDATA[social networks]]></category>

		<guid isPermaLink="false">http://serdaryildirim.net/?p=171</guid>
		<description><![CDATA[Here is a *really* simple prolog code snippet to find a list of &#8220;friends of friends&#8221;.
It is a simple program that uses lists, recursion and database usage for dynamic fact storage.

DOMAINS
person = symbol
people_list = symbol*

FACTS
human(person)	%used to store found friend of friend for the goal person

PREDICATES
nondeterm has_friend(person, people_list)
nondeterm write_possible_friends(person)
nondeterm is_member(symbol, people_list)
nondeterm check_friends(person, people_list, people_list)
nondeterm find_friends_of_friends(person, person)
nondeterm [...]]]></description>
			<content:encoded><![CDATA[<p>Here is a *<strong>really</strong>* simple prolog code snippet to find a list of &#8220;friends of friends&#8221;.<br />
It is a simple program that uses lists, recursion and database usage for dynamic fact storage.</p>
<pre>
DOMAINS
person = symbol
people_list = symbol*

FACTS
human(person)	%used to store found friend of friend for the goal person

PREDICATES
nondeterm has_friend(person, people_list)
nondeterm write_possible_friends(person)
nondeterm is_member(symbol, people_list)
nondeterm check_friends(person, people_list, people_list)
nondeterm find_friends_of_friends(person, person)
nondeterm set_friends_of_friends(person, people_list, people_list)
nondeterm set_possible_friend(person)
nondeterm may_be_friend(person)

CLAUSES
%Define relationships
has_friend(serdar, [don, bob, jessica]).
has_friend(don, [sam, serdar]).
has_friend(bob, [serdar]).
has_friend(jessica, [mary, serdar]).
has_friend(sam, [don]).
has_friend(mary, [jessica]).

%Write found possible friends.
write_possible_friends(GoalPerson) :-
	findall(Person, human(Person),L),
	write("Goal Person is: "), write(GoalPerson), nl,
	write("Friends of friends / Possible Friends are: "), write(L), nl,
	retractall(_, dbasedom).

%Check if a person exists in a list
is_member(Person, [Person|_]).
is_member(Person, [_|Tail]):-
	is_member(Person,Tail).

%Check recursively a friend of friend is already a friend or the goal person
%If not, add him/her to to DB.
check_friends(Person, [], []).
check_friends(Person, [H|T], Tail) :-
	has_friend(Person, FL),
	not(is_member(H, FL)),
	not(Person = H),
	!,
	%write("*** Friend of friend is: "), write(H), nl,
	assertz(human(H)),
	check_friends(Person, T, Tail).

check_friends(Person, [H|T],[H|Tail]):-
	check_friends(Person, T, Tail).

%Finds friend list of goal person's friend (Person2)
%and check possible friends of current friend(Person2)
find_friends_of_friends(Person1, Person2):-
	has_friend(Person2, FriendList),
	check_friends(Person1, FriendList, ProcessedList),

%Traverse every friend of goal person and sets fof
set_friends_of_friends(Person, [], []).
set_friends_of_friends(Person, [H|T], Tail) :-
	%write("Processing friend: "), write(H), nl,
	find_friends_of_friends(Person, H),
	set_friends_of_friends(Person, T, Tail).

set_friends_of_friends(Person, [H|T],[H|Tail]):-
	set_friends_of_friends(Person, T, Tail).

set_possible_friend(Person):-
	has_friend(Person, FriendList),
	set_friends_of_friends(Person, FriendList, ProcessedList).

%Sets possible friends of friends to DB and writes them to the screen.
may_be_friend(Person):-
	set_possible_friend(Person);
	write_possible_friends(Person).

GOAL
%may_be_friend(mary).	mary, bob, don, jessica, sam, serdar
may_be_friend(serdar).
</pre>
<p>P.S: I&#8217;m using visual prolog for development.<br />
There is a great document for learning prolog inside DOC folder. (LANGUAGE.doc) </p>
]]></content:encoded>
			<wfw:commentRss>http://serdaryildirim.net/ai/finding-friends-of-friends-using-prolog.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>savedis.com &#8211; rails 3.1 open source bookmarking tool</title>
		<link>http://serdaryildirim.net/ruby-on-rails/savedis-com-rails-3-1-open-source-bookmarking-tool.html</link>
		<comments>http://serdaryildirim.net/ruby-on-rails/savedis-com-rails-3-1-open-source-bookmarking-tool.html#comments</comments>
		<pubDate>Tue, 04 Oct 2011 05:19:11 +0000</pubDate>
		<dc:creator>serdar</dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[mongodb]]></category>
		<category><![CDATA[nokogiri]]></category>
		<category><![CDATA[passenger]]></category>
		<category><![CDATA[rails 3.1]]></category>

		<guid isPermaLink="false">http://serdaryildirim.net/?p=164</guid>
		<description><![CDATA[Here is my rails 3.1 learning app, <a href="http://savedis.com">savedis.com</a>
I used MySQL to store data, will_paginate gem for pagination, configatron gem for custom configuration files, mechanize gem to traverse html of the target webpage&#8217;s source file and some others.
I had some difficulties while deploying to my server. My server has CentOS 4 so that causes some [...]]]></description>
			<content:encoded><![CDATA[<p>Here is my rails 3.1 learning app, <a href="http://savedis.com">savedis.com</a></p>
<p>I used MySQL to store data, will_paginate gem for pagination, configatron gem for custom configuration files, mechanize gem to traverse html of the target webpage&#8217;s source file and some others.</p>
<p>I had some difficulties while deploying to my server. My server has CentOS 4 so that causes some problems on passenger.<br />
I used passenger module on apache to deploy, but passenger 3.x did not work on my CentOS 4 machine so I had to install passenger 2.x.<br />
But for some reason rails 3 did not work on passenger 2.x. So I was blocked. I upgraded my CentOS to 5 and installed passenger 3.x, and that worked!</p>
<p>The only gem I had problems is nokogiri gem. It isn&#8217;t installed when I try bundle install/update or gem install nokogiri. The error I get:</p>
<blockquote><p>ERROR:  Error installing nokogiri:<br />
ERROR: Failed to build gem native extension.</p>
<p>/usr/local/bin/ruby extconf.rb<br />
checking for libxml/parser.h&#8230; yes<br />
checking for libxslt/xslt.h&#8230; no<br />
&#8212;&#8211;<br />
libxslt is missing.  please visit http://nokogiri.org/tutorials/installing_nokogiri.html for help with installing dependencies.<br />
&#8212;&#8211;<br />
*** extconf.rb failed ***</p></blockquote>
<p>installing libxml2 and libxslt by below commands also did not worked.</p>
<blockquote><p>sudo yum install -y libxml2 libxml2-devel libxslt libxslt-devel<br />
sudo gem install nokogiri</p></blockquote>
<p>So I had to remove libxml2 and libxslt through yum, and then manually installing them from source. Then simple gem install nokogiri worked.</p>
<p>That&#8217;s it for now, now it&#8217;s time to work on a real project with rails 3.1 and maybe mongodb..</p>
]]></content:encoded>
			<wfw:commentRss>http://serdaryildirim.net/ruby-on-rails/savedis-com-rails-3-1-open-source-bookmarking-tool.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Some useful notes on rails 3.1</title>
		<link>http://serdaryildirim.net/ruby-on-rails/some-useful-notes-on-rails-3-1.html</link>
		<comments>http://serdaryildirim.net/ruby-on-rails/some-useful-notes-on-rails-3-1.html#comments</comments>
		<pubDate>Fri, 19 Aug 2011 11:18:00 +0000</pubDate>
		<dc:creator>serdar</dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[rails 3.1]]></category>
		<category><![CDATA[RoR]]></category>

		<guid isPermaLink="false">http://serdaryildirim.net/?p=141</guid>
		<description><![CDATA[Here I&#8217;ll try to list some useful things that I faced while developing a rails app as a noob.
Ok let&#8217;s say you detached your rails server to use the same terminal, but later you need to stop rails server, how? (surprise!)
The solution I found is simply finding Webrick server process id and kill it!

ps -ef [...]]]></description>
			<content:encoded><![CDATA[<p>Here I&#8217;ll try to list some useful things that I faced while developing a rails app as a noob.</p>
<p>Ok let&#8217;s say you detached your rails server to use the same terminal, but later you need to stop rails server, how? (surprise!)</p>
<p>The solution I found is simply finding Webrick server process id and kill it!<br />
<br />
<code>ps -ef | grep script/rails</code></p>
<p>now, kill the process id which is the first integer on the line</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>If you follow a &#8220;rails 3 tutorial&#8221; just like me, you probably have problems with ajax.</p>
<p>That&#8217;s because now jquery is default js framework in 3.1, not prototype. Prototype is a gem which you need to add your Gemfile to use that.</p>
<p>That&#8217;s why you should write partial templates in a .erb file not .rjs</p>
<p>An example change:<br />
page.replace_html(&#8216;item&#8217;, render(@item))</p>
<p>$(&#8216;#item-holder&#8217;).html(&#8220;&lt;%= j render @item  %&gt; &#8220;);</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>And lastly, If you installed MAMP and using MySql for your rails app, that&#8217;s a good chance that you will have issues while connecting the DB.<br />
Below is my database.yml which works for me for a rails 3.1 app</p>
<p>adapter: mysql2<br />
host: localhost<br />
database: railsapp-dev<br />
username: mamp_username<br />
password: mamp_pass<br />
socket: /Applications/MAMP/tmp/mysql/mysql.sock</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>That&#8217;s all for now, probably more rails posts will appear here..</p>
]]></content:encoded>
			<wfw:commentRss>http://serdaryildirim.net/ruby-on-rails/some-useful-notes-on-rails-3-1.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

