tag:blogger.com,1999:blog-60356679657894168592024-02-20T06:07:34.840-03:00The MindcasterCarlos Eduardo's blog...
Build it now to enjoy it later.Carlos Eduardohttp://www.blogger.com/profile/00674164975841007118noreply@blogger.comBlogger20125tag:blogger.com,1999:blog-6035667965789416859.post-91180821511225252982009-09-16T11:33:00.000-03:002009-09-16T11:33:01.992-03:00Using Soocial to keep contacts in syncFor a long time, I've been looking for a clean way to keep all my contacts in sync between the multiple platforms I use. Currently, I have a Macbook at home, a Windows PC with Outlook at work, the iPhone and my main email, a Gmail account. <br />
<div> </div><div>I have tried almost all available solutions to keep them in sync. Plaxo, multiple applications to sync Outlook to Gmail, Mac to Gmail but no success on having a clean way to do it and without hassle.</div><div> </div><div>About two months ago, I found a promising one. <a href="http://www.soocial.com/">Soocial</a>. Their objective is to have a central platform and from it sync to multiple points via web APIs or local applications.</div><div> </div><div>For the last months, I installed it and substituted all sync options I had by Soocial. In the beginning, many bugs were found. Sync between Soocial and Outlook had problems with multiple emails, Soocial-Gmail had problems with work phones (phone did not appear on Gmail) and some minor ones.</div><div> </div><div>About <a href="http://blog.soocial.com/2009/08/05/please-upgrade-your-gmail-connections/">a month ago</a>, Soocial rewrote their Gmail communication using the newest API and that sync problems went away.</div><div> </div><div>This week, Soocial <a href="http://blog.soocial.com/2009/09/15/new-outlook-client-available/">released </a>a new Outlook client that finished the problems I found out. Having this, made Soocial the best platform to keep contacts in sync on multiple platforms.</div><div> </div><div>Currently the support Mac Address Book, Outlook, Gmail, Windows Live, Yahoo and other phones(Nokia/Sony Ericsson) via SyncML protocol.</div><div> </div><div>The topology I choose to have all my devices in sync was:</div><div> </div><div>- Soocial - Gmail connection (it's bi-directional)</div><div>- Soocial - Outlook connection via it's application</div><div>- Soocial - Mac connection via it's application</div><div>- iPhone sync directly to Gmail using Exchange Protocol described <a href="http://www.google.com/support/mobile/bin/answer.py?answer=138740&topic=14252">here</a></div><div> </div><div>It's been working perfectly and practically online where any update in any point triggers the sync making all devices updated.</div><div><br />
</div><div>Have you experienced any contact sync solution? Leave your feedback on comments.</div><div><br />
</div><div>Disclaimer: This post is not endorsed by Soocial or any other cited companies in any way. All content posted represents my own opinion.</div>Carlos Eduardohttp://www.blogger.com/profile/00674164975841007118noreply@blogger.com3tag:blogger.com,1999:blog-6035667965789416859.post-32031348458571664512009-09-11T16:49:00.000-03:002009-09-11T16:49:25.506-03:00Switching Browsers - From Firefox to Safari/ChromeFrom time to time we hear complains about web browsers. Recently, major sites like Youtube added a notice to it main page warning Internet Explorer 6 users that the browser will be discontinued shortly.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://3.bp.blogspot.com/_Ha-kKLoJrps/SqqpJ8yDCaI/AAAAAAAAAX4/5Vfu0cd19ao/s1600-h/youtube-ie6.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/_Ha-kKLoJrps/SqqpJ8yDCaI/AAAAAAAAAX4/5Vfu0cd19ao/s320/youtube-ie6.JPG" /></a></div><br />
<br />
Apple provides via software update its new browsers automatically. Microsoft does the same with Windows Update. Today, it is very easy to update. Probably a big slice of these users have pirated copies and can not update by official ways. For companies, it is a bit more complicated since it involves hundreds of machines.<br />
<br />
The main point is that there are many options for all tastes when browsers came into play. It's just a matter of trying each one since there are no costs involved and just time is needed.<br />
<br />
The most natural option you see around is people migrating from Internet Explorer to Firefox since it is more exposed to media, you see more users going this way.<br />
<br />
Lately I found Firefox very slow and bloated with extensions I almost don't use (I know, I should uninstall) and consuming lots of memory. Instead of cleaning it up and start using a fresh install, I went another way. Switched to Safari at home (Mac) and Chrome at work (WindowsXP).<br />
<br />
I only did the switch because a mandatory feature for me, bookmark synchronization, using the fantastic <a href="http://www.xmarks.com/">Xmarks</a> extension is now available on Chrome via <a href="http://beta.xmarks.com/">beta channel</a>. It became available for Safari earlier this year.<br />
<br />
Of course, I miss some features given by other extensions. The ones I miss more are AdBlock, rocker gestures, Gmail notifier and Twitterfox.<br />
<br />
Latest Chrome dev builds can use extensions when loaded with the --enable-extensions parameter. On Chrome <a href="http://dev.chromium.org/">dev page</a>, there is a sample <a href="http://dev.chromium.org/developers/design-documents/extensions/samples">Gmail checker extension</a> that does the basic job. That parameter is also needed to use Xmarks extension.<br />
<br />
Replacing Twitterfox was a harder job because I wanted a small and featured client. I ended up on <a href="http://destroytwitter.com/">DestroyTwitter</a>, an Adobe Air client that is better than other options I tested. I will leave this Twitter client choice for another post.<br />
<br />
I've been "switched" for some weeks now and don't miss Firefox nor its extensions. Tell me if you did something similar and if it worked.Carlos Eduardohttp://www.blogger.com/profile/00674164975841007118noreply@blogger.com1tag:blogger.com,1999:blog-6035667965789416859.post-35853606046935190052009-09-04T16:25:00.004-03:002009-09-04T16:56:41.096-03:00How I upgraded to Snow Leopard<div>When I started planning to upgrade to Snow Leopard, I had two options on my head. Update from what it is now or do a full reinstall. Since I think my Macbook 3,1 became slower from the time I bought it (around 1 1/2 years ago), maybe a full cleanup and reinstall could get it snappier.<br />
<br />
<div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"></div><div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"></div></div><div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">With this in mind, I started updating all installed software with <a href="http://metaquark.de/appfresh/">AppFresh</a> and ran a maintenance job using <a href="http://www.macupdate.com/info.php/id/11582">Onyx</a>. Then, backup everything using Time Machine and pop the Snow Leopard DVD choosing a full install.</div></div></div><div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"></div></div><div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"></div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
When the installation finished, I will restored my data and applications (previously cleaned up) with Migration Assistant from TM backup. The restore brought back all data from my previous profile including terminal exports, Macports data and system settings.</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"></div></div></div><div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"></div></div><div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
In case anything went wrong, I would restore Leopard and then do the "update" from Snow Leopard DVD.</div></div></div><div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"></div></div><div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"></div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
After all, I feel my applications much faster to load and the system is more responsive. Really worth the upgrade.</div></div></div></div></div>Carlos Eduardohttp://www.blogger.com/profile/00674164975841007118noreply@blogger.com0tag:blogger.com,1999:blog-6035667965789416859.post-6233709338526796972009-09-03T12:46:00.000-03:002009-09-03T12:46:45.328-03:00Vinyl, not only for audiophiles.<div>Steve Guttenberg wrote a nice post about the recent revival of Vinyl records and the differences from CD. A short post that lights up the curiosity music lovers.</div><blockquote>Vinyl is back, big time, but the fact is most folks, probably close to 99 percent of the under 40-set, <a href="http://news.cnet.com/8301-13645_3-10279859-47.html" style="border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; cursor: pointer; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-align: left; vertical-align: baseline;"><span style="color: black;">haven't heard records</span></a>.</blockquote><div> From <a href="http://news.cnet.com/8301-13645_3-10323224-47.html?tag=mncol;title">Cnet's "The Audiophiliac" blog</a></div>Carlos Eduardohttp://www.blogger.com/profile/00674164975841007118noreply@blogger.com1tag:blogger.com,1999:blog-6035667965789416859.post-10496126991401161102009-09-03T12:12:00.000-03:002009-09-03T12:12:14.808-03:00Guitar Rig 4 , effects and modeling software released.The amazing Guitar Rig 4 from Native Instruments has been released. It's a great combination of software and a foot controller. Starting at $99 up to $499 (with the foot controller).<br />
<br />
<blockquote>Guitar Rig 4 Pro will include two new amp models, the “Hot Plex” and the “Jump.” The new version will also come with two new delay units and two new flavors of reverb, bringing the overall number of included effects to 48.</blockquote><br />
From <a href="http://www.loopinsight.com/2009/09/01/native-instruments-announces-guitar-rig-4-pro/">The Loop</a>.Carlos Eduardohttp://www.blogger.com/profile/00674164975841007118noreply@blogger.com0tag:blogger.com,1999:blog-6035667965789416859.post-8769523621068077182009-09-01T10:54:00.000-03:002009-09-01T10:54:10.745-03:00Ars Technica Snow Leopard review<span style="font-family: Verdana, sans-serif;">The article posted yesterday by John Siracusa to Ars Technica can almost be considered part of the documentation for the OS not only a review. Worth every second.</span><br />
<span style="font-family: Verdana, sans-serif;"><br />
</span><br />
<span class="Apple-style-span" style="-webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; font-size: 14px; white-space: pre-wrap;"><span style="font-family: Verdana, sans-serif;"><a href="http://bit.ly/w1PhY">http://arstechnica.com/apple/reviews/2009/08/mac-os-x-10-6.ars</a></span></span><br />
<span style="font-family: Verdana, sans-serif; font-size: medium;"><span class="Apple-style-span" style="-webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; font-size: 14px; white-space: pre-wrap;"><br />
</span></span>Carlos Eduardohttp://www.blogger.com/profile/00674164975841007118noreply@blogger.com0tag:blogger.com,1999:blog-6035667965789416859.post-55272725829376049882009-08-31T11:37:00.000-03:002009-08-31T11:37:26.425-03:00How I use Evernote<span style="font-family: Verdana, sans-serif;">Resuming the blog, I will start a series of "How I use ..." articles. I usually find these kind of posts valuable because it gives some insights about software usage thus having a new perspective and also improve the workflow on it. </span><br />
<span style="font-family: Verdana, sans-serif;"><br />
</span><br />
<span style="font-family: Verdana, sans-serif;">In this post, I will briefly describe how I use Evernote and how it can help you out.</span><br />
<span style="font-family: Verdana, sans-serif;"><br />
</span><br />
<span style="font-family: Verdana, sans-serif;">I signed up <a href="http://www.evernote.com/">Evernote </a>more than a year ago but only started using it on a daily basis around two months ago. All started when I needed a way to organize small pieces of information at work. For about two years, I switched from application to application going thru TXT files organized in folders, a small app called Keynote and even a personal local wiki using <a href="http://www.tiddlywiki.com/">www.tiddlywiki.com</a>.</span><br />
<span style="font-family: Verdana, sans-serif;"><br />
</span><br />
<span style="font-family: Verdana, sans-serif;">One day, the idea came, why not use Evernote since I already had a free account and no more than 3-5 unused notes on it. The plus side of using it is that it is fast, simple and syncs your information to make it available everywhere. On the negative side is it's limitations on the editor like creating tables and formatting options.</span><br />
<span style="font-family: Verdana, sans-serif;"><br />
</span><br />
<span style="font-family: Verdana, sans-serif;">With this in mind, I started looking for posts like this to see how people use Evernote and found a great way to manage documentation and also a workflow for GTD (getting things done) either personally and at work.</span><br />
<span style="font-family: Verdana, sans-serif;">The structure for my notebooks became:</span><br />
<span style="font-family: Verdana, sans-serif;"><br />
</span><br />
<div><span style="font-family: Verdana, sans-serif;">#Carlosedp - Personal notes<br />
1. Inbox - All created projects go to this notebook until I start working on them<br />
2. To Do - The tasks inside this notebook have actions to be done by me<br />
3. Followup - These tasks are in a "wait" state or a "followup" state where I have no personal action on<br />
4. Docs - Here I store all information and references for daily usage like system documentation<br />
5. Archive - The finished tasks go to this notebook</span></div><div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/_Ha-kKLoJrps/SpvfhWiqC7I/AAAAAAAAAXw/901oR1TNZCg/s1600-h/clip_image002.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Verdana, sans-serif;"><img border="0" src="http://1.bp.blogspot.com/_Ha-kKLoJrps/SpvfhWiqC7I/AAAAAAAAAXw/901oR1TNZCg/s400/clip_image002.jpg" /></span></a></div><div><span style="font-family: Verdana, sans-serif;"><br />
</span></div><div><span style="font-family: Verdana, sans-serif;"><br />
</span></div><br />
<span style="font-family: Verdana, sans-serif;">I also recently created a notebook to store the drafts and posted articles here.</span><br />
<span style="font-family: Verdana, sans-serif;">What is great in Evernote is that all notes are synchronized to the server so if I need to check something about a project or want to finish a blog post at home or at work, it just works either using a client for your platform of choice or the great web interface.</span><br />
<span style="font-family: Verdana, sans-serif;"><br />
</span><br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://3.bp.blogspot.com/_Ha-kKLoJrps/SpvfXuRzQZI/AAAAAAAAAXo/uDkZ_hU9Q64/s1600-h/clip_image004.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Verdana, sans-serif;"><img border="0" src="http://3.bp.blogspot.com/_Ha-kKLoJrps/SpvfXuRzQZI/AAAAAAAAAXo/uDkZ_hU9Q64/s400/clip_image004.jpg" /></span></a></div><span style="font-family: Verdana, sans-serif;"><br />
</span><br />
<span style="font-family: Verdana, sans-serif;">For each incoming task/project, I create a template like this:</span><br />
<span style="font-family: Verdana, sans-serif;"><br />
</span><br />
<br />
<strong><u><span style="font-family: Verdana, sans-serif;">##Project/task name - Code</span></u></strong><br />
<span style="font-family: Verdana, sans-serif;">Description of the task/project</span><br />
<span style="font-family: Verdana, sans-serif;"><span class="Apple-style-span" style="text-decoration: underline;"><br />
</span></span><br />
<u><span style="font-family: Verdana, sans-serif;">Premises:</span></u><br />
<ul type="disc"><li><span style="font-family: Verdana, sans-serif;">AAAAAA</span></li>
<li><span style="font-family: Verdana, sans-serif;">BBBBBBB</span></li>
</ul><u><span style="font-family: Verdana, sans-serif;">Scope:</span></u><br />
<ul type="disc"><li><span style="font-family: Verdana, sans-serif;">AAAAAA</span></li>
<li><span style="font-family: Verdana, sans-serif;">BBBBBBB</span></li>
</ul><u><span style="font-family: Verdana, sans-serif;">Negative Scope:</span></u><br />
<ul type="disc"><li><span style="font-family: Verdana, sans-serif;">AAAAAA</span></li>
<li><span style="font-family: Verdana, sans-serif;">BBBBBBB</span></li>
</ul><strong><u><span style="font-family: Verdana, sans-serif;">To-Do:</span></u></strong><br />
<ul><li><span style="font-family: Verdana, sans-serif;">Item 1</span></li>
<ul><li><span style="font-family: Verdana, sans-serif;">Item 2</span></li>
</ul><li><span style="font-family: Verdana, sans-serif;">Item 3</span></li>
</ul><br />
<span style="font-family: Verdana, sans-serif;">Having it this way, it is easy to add new information and check each step when it is finished. Also the search functionality is great, wow I just wonder if the monthly 40MB of transfer of the free account will be enough or if I will need to sign up for an upgraded account.</span><br />
<span style="font-family: Verdana, sans-serif;"><br />
</span><br />
<span style="font-family: Verdana, sans-serif;">Using Evernote this way made me way more productive and keeps the information handy all the time. If you have tips to improve this workflow or have another suggestion I will be glad to consider.</span><br />
<span style="font-family: Verdana, sans-serif;"><br />
</span><br />
<span style="font-family: Verdana, sans-serif;">Disclaimer: This post is not sponsored in any way by Evernote and expresses my own opinions on all matters.</span>Carlos Eduardohttp://www.blogger.com/profile/00674164975841007118noreply@blogger.com2tag:blogger.com,1999:blog-6035667965789416859.post-3938384956574109462009-08-28T14:56:00.000-03:002009-08-28T14:56:36.004-03:00Resume blog activity<div><span style="font-family: Verdana, sans-serif;">After many months being idle here in the blog, I thought about changing things a little.</span></div><div><span style="font-family: Verdana, sans-serif;"><br />
</span></div><span style="font-family: Verdana, sans-serif;">With <a href="http://twitter.com/carlosedp">Twitter</a>, all I write on the internet gets resumed into 140 chars. Most times, this is enough but for more detailed information it is not sufficient.</span><br />
<span style="font-family: Verdana, sans-serif;"><br />
</span><br />
<span style="font-family: Verdana, sans-serif;">Having this in mind, I'm going to start posting here stuff not only related to programming like I used to but also GTD (getting things done) articles, usage tips, etc.</span><br />
<span style="font-family: Verdana, sans-serif;"><br />
</span><br />
<span style="font-family: Verdana, sans-serif;">I hope this gets useful to people and complements my Twitter updates.</span><br />
<span style="font-family: Verdana, sans-serif;"><br />
</span><br />
<span style="font-family: Verdana, sans-serif;">My next blog will cover my usage of Evernote, stay tuned.</span>Carlos Eduardohttp://www.blogger.com/profile/00674164975841007118noreply@blogger.com2tag:blogger.com,1999:blog-6035667965789416859.post-33056330835769376092009-01-21T15:43:00.001-02:002009-01-21T15:44:50.509-02:00Service Interruption<p><span style="font-weight: bold;"></span>Found this amazing:<br /></p><p></p><blockquote><p>Dear World:</p> <p>We, the United States of America, your top quality supplier of ideals of democracy, would like to apologize for our 2001-2008 interruption in service. The technical fault that led to this eight-year service outage has been located, and the software responsible was replaced November 4. Early tests of the newly installed program indicate that we are now operating correctly, and we expect it to be fully functional on January 20. We apologize for any inconvenience caused by the outage. We look forward to resuming full service and hope to improve in years to come. We thank you for your patience and understanding,</p> <p>Sincerely,<br />THE UNITED STATES OF AMERICA</p></blockquote><p></p>Carlos Eduardohttp://www.blogger.com/profile/00674164975841007118noreply@blogger.com0tag:blogger.com,1999:blog-6035667965789416859.post-80572898495763142502007-11-20T16:45:00.000-02:002007-11-20T16:59:42.619-02:00PSP Stackless Python ProjectAfter releasing PSP Stackless Python 2.5.1 last week, I started working on a project site to host the files, sources, documentation and issues for my Stackless Python port for the PSP.<br /><br />You can reach the project here: <a href="http://pspstacklesspython.googlecode.com/">http://pspstacklesspython.googlecode.com/</a><br /><br />There you will find the Stackless Python 2.5.1 for PSP, now including a readme to clarify the installation and usage process, a Wiki that contains information on module usage, references to the modules ported by fraca7, build the interpreter from source, etc... I tried to condensate all information I posted on this blog to have it in one central place.<br /><br />In the project page, one can create issues to report problems, feature requests and even patches to correct problems.<br /><br />I created a zipped source for the last release and I`m also in process of uploading the code to the SVN repository.<br /><br />I hope this makes the Stackless Python for PSP widespread and within reach of everyone, also dont forget to keep an eye on <a href="http://stacklessexamples.googlecode.com">Stackless Examples Project</a>, where you can find nice use cases for it.<br /><br />CarlosCarlos Eduardohttp://www.blogger.com/profile/00674164975841007118noreply@blogger.com13tag:blogger.com,1999:blog-6035667965789416859.post-91191778474862576042007-11-14T15:29:00.000-02:002007-11-14T15:48:52.461-02:00Stackless Python 2.5.1 for PSPAfter working some time on it, I have updated the Stackless Python for PSP to version 2.5.1, the latest version released and made the application user mode tested on 3.71 firmware.<br /><br />In this release, I have fixes the problem exiting the application (where it locked the PSP) and tested many other functionality.<br /><br />Here follows changes between last version:<br /><br />- The SSL has been removed for now because it was not working on latest release.<br />- Fixed time and datetime modules to display correct dates and times based on PSP timezones and DST.<br />- Fixed problems on sys and os modules<br />- Ported to user mode and 3.xx kernel.<br /><br />I hope many people could test this release and post feedbacks about it.<br /><br />The package can be downloaded from here: <a href="http://stacklesspsp.googlepages.com/StacklessPSP2.5.1_1.zip">http://stacklesspsp.googlepages.com/StacklessPSP2.5.1_1.zip</a><br /><br />The installation is the same, put the "python" directory on your MS root and place the EBOOT.PBP in your PSP/GAME3xx or GAME dir if you set it to run 3.xx apps.<br /><br />Check my older posts about module usage and tips. Also check <a href="http://www.youtube.com/v/1vjwSiGl7Jw">this video</a> posted by Domino Man showing a simple demo provided in <a href="http://stacklesspsp.googlepages.com/Gamedemo.zip">this zip</a>.<br /><br />CarlosCarlos Eduardohttp://www.blogger.com/profile/00674164975841007118noreply@blogger.com15tag:blogger.com,1999:blog-6035667965789416859.post-37208687321918319742007-08-31T18:58:00.000-03:002007-08-31T19:06:35.007-03:00Python 3.0a1 has been released! Woot!Its great to see that the effort from the best developers around gets alive.<br /><br />Congratulations to Guido and all the team committed to make this all happen and providing us this great language.<br /><br />You can grab it here: <a href="http://python.org/download/releases/3.0/">http://python.org/download/releases/3.0/</a>Carlos Eduardohttp://www.blogger.com/profile/00674164975841007118noreply@blogger.com0tag:blogger.com,1999:blog-6035667965789416859.post-26231175099244991272007-08-17T17:28:00.001-03:002007-08-17T19:09:18.717-03:00Stackless asynchronous fileIO moduleFor a long time I wanted to create a module to allow asynchronous file IO for Stackless Python.<br /><br />The problem is that the currently available file object, does blocking calls to the read() and write() methods making all the interpreter block and not permitting the other tasklets do its job.<br /><br />The solution was to create a module where the tasklet calls the method and only he gets blocked in the channel allowing other tasklets run freely... when the data is read/wrote a manager fires back to the channel and the requester tasklet continues.<br /><br />I have already created a <a href="http://stacklessexamples.googlecode.com/svn/trunk/examples/fileIO/stacklessfile.py">module using a threadpool</a> where the requests are fired, the workers read or write the data and returns back to the calling tasklet but this consumes memory for the multiple OS threads running as workers and you have to configure the worker quantity based on your usage.<br /><br />Fiddling around I found that on windows select() doesn't support file descriptors so the other option was OverlappedIO also known as IOCP.<br /><br />This made me learn a thousand things I thought would never know... Ctypes, Windows internal APIs (kernel32 stuff), and even python internals to see how its fileobject works.<br /><br />After this all here it is, the module that mimics the internal python file() object. Please test it and report any successes or failures. I also made a script to test its usage.<br /><br />Hope it's useful.<br /><br />Carlos<br /><br />The code is below, if its too difficult to read, it is pasted here: http://dpaste.com/hold/17151/ and will be posted on <a href="http://stacklessexamples.googlecode.com/svn/trunk/">Stackless Examples SVN</a><br /><br /><br /><span style="font-family:Courier New;"><span style=";font-family:Courier New;color:green;" >#<br /></span><span style=";font-family:Courier New;color:green;" ># Stackless Asynchronous file module:<br /></span><span style=";font-family:Courier New;color:green;" >#<br /></span><span style=";font-family:Courier New;color:green;" ># Author: Carlos E. de Paula <carlosedp@gmail.com><br /></span><span style=";font-family:Courier New;color:green;" >#<br /></span><span style=";font-family:Courier New;color:green;" ># This code was written to serve as an example of Stackless Python usage.<br /></span><span style=";font-family:Courier New;color:green;" ># Feel free to email me with any questions, comments, or suggestions for<br /></span><span style=";font-family:Courier New;color:green;" ># improvement.<br /></span><span style=";font-family:Courier New;color:green;" >#<br /></span><span style=";font-family:Courier New;color:green;" ># This is an asynchronous file class in order to have a file module replacement<br /></span><span style=";font-family:Courier New;color:green;" ># that uses channels and a windows async API to allow its methods to<br /></span><span style=";font-family:Courier New;color:green;" ># block just the calling tasklet not the entire interpreter.<br /></span><span style=";font-family:Courier New;color:green;" >#<br /></span><span style=";font-family:Courier New;color:green;" >#<br /></span><b><span style=";font-family:Courier New;color:navy;" >import</span></b> os<br /><b><span style=";font-family:Courier New;color:navy;" >import</span></b> time<br /><b><span style=";font-family:Courier New;color:navy;" >import</span></b> stackless<br /><b><span style=";font-family:Courier New;color:navy;" >from</span></b> ctypes <b><span style=";font-family:Courier New;color:navy;" >import</span></b> *<br /><b><span style=";font-family:Courier New;color:navy;" >from</span></b> ctypes.wintypes <b><span style=";font-family:Courier New;color:navy;" >import</span></b> HANDLE, ULONG, DWORD, BOOL, LPCSTR, LPCWSTR, WinError<br /><br /><span style=";font-family:Courier New;color:green;" ># Verify module compatibility<br /></span><b><span style=";font-family:Courier New;color:navy;" >if</span></b> os.name != <span style=";font-family:Courier New;color:olive;" >'nt'</span>:<br /> raise ImportError(<span style=";font-family:Courier New;color:olive;" >'This module has been implemented for windows systems.'</span>)<br /><br /><span style=";font-family:Courier New;color:green;" ># Windows structures<br /></span><br /><b><span style=";font-family:Courier New;color:navy;" >class</span></b> <b><span style=";font-family:Courier New;color:blue;" >_US</span></b>(Structure):<br /> _fields_ = [<br /> (<span style=";font-family:Courier New;color:olive;" >"Offset"</span>, DWORD),<br /> (<span style=";font-family:Courier New;color:olive;" >"OffsetHigh"</span>, DWORD),<br /> ]<br /><br /><b><span style=";font-family:Courier New;color:navy;" >class</span></b> <b><span style=";font-family:Courier New;color:blue;" >_U</span></b>(Union):<br /> _fields_ = [<br /> (<span style=";font-family:Courier New;color:olive;" >"s"</span>, _US),<br /> (<span style=";font-family:Courier New;color:olive;" >"Pointer"</span>, c_void_p),<br /> ]<br /><br /> _anonymous_ = (<span style=";font-family:Courier New;color:olive;" >"s"</span>,)<br /><br /><b><span style=";font-family:Courier New;color:navy;" >class</span></b> <b><span style=";font-family:Courier New;color:blue;" >OVERLAPPED</span></b>(Structure):<br /> _fields_ = [<br /> (<span style=";font-family:Courier New;color:olive;" >"Internal"</span>, POINTER(ULONG)),<br /> (<span style=";font-family:Courier New;color:olive;" >"InternalHigh"</span>, POINTER(ULONG)),<br /> (<span style=";font-family:Courier New;color:olive;" >"u"</span>, _U),<br /> (<span style=";font-family:Courier New;color:olive;" >"hEvent"</span>, HANDLE),<br /><br /> <span style=";font-family:Courier New;color:green;" ># Custom fields.<br /></span> (<span style=";font-family:Courier New;color:olive;" >"taskletID"</span>, ULONG),<br /> ]<br /><br /> _anonymous_ = (<span style=";font-family:Courier New;color:olive;" >"u"</span>,)<br /><br /><span style=";font-family:Courier New;color:green;" ># Windows kernel32 API<br /></span><br />CreateIoCompletionPort = windll.kernel32.CreateIoCompletionPort<br />CreateIoCompletionPort.argtypes = (HANDLE, HANDLE, POINTER(c_ulong), DWORD)<br />CreateIoCompletionPort.restype = HANDLE<br /><br />GetQueuedCompletionStatus = windll.kernel32.GetQueuedCompletionStatus<br />GetQueuedCompletionStatus.argtypes = (HANDLE, POINTER(DWORD), POINTER(c_ulong),<br /> POINTER(POINTER(OVERLAPPED)), DWORD)<br />GetQueuedCompletionStatus.restype = BOOL<br /><br />ReadFile = windll.kernel32.ReadFile<br />ReadFile.argtypes = (HANDLE, c_void_p, DWORD, POINTER(DWORD), POINTER(OVERLAPPED))<br />ReadFile.restype = BOOL<br /><br />WriteFile = windll.kernel32.WriteFile<br />WriteFile.argtypes = (HANDLE, c_void_p, DWORD, POINTER(DWORD), POINTER(OVERLAPPED))<br />WriteFile.restype = BOOL<br /><br />CreateFileA = windll.kernel32.CreateFileA<br />CreateFileA.argtypes = (LPCSTR, DWORD, DWORD, c_void_p, DWORD, DWORD, HANDLE)<br />CreateFileA.restype = HANDLE<br /><br />CreateFileW = windll.kernel32.CreateFileW<br />CreateFileW.argtypes = (LPCWSTR, DWORD, DWORD, c_void_p, DWORD, DWORD, HANDLE)<br />CreateFileW.restype = HANDLE<br /><br />CloseHandle = windll.kernel32.CloseHandle<br />CloseHandle.argtypes = (HANDLE,)<br />CloseHandle.restype = BOOL<br /><br />GetLastError = windll.kernel32.GetLastError<br /><br /><span style=";font-family:Courier New;color:green;" ># Python API<br /></span><br />pythonapi.PyErr_SetFromErrno.argtypes = (py_object,)<br />pythonapi.PyErr_SetFromErrno.restype = py_object<br /><br /><span style=";font-family:Courier New;color:green;" ># Windows definitions<br /></span><br />INVALID_HANDLE_VALUE = <span style=";font-family:Courier New;color:blue;" >0xFFFFFFFF</span><br />NULL = c_ulong()<br /><br />WAIT_TIMEOUT = <span style=";font-family:Courier New;color:blue;" >0x102</span><br />ERROR_IO_PENDING = <span style=";font-family:Courier New;color:blue;" >997</span><br />FILE_FLAG_RANDOM_ACCESS = <span style=";font-family:Courier New;color:blue;" >0x10000000</span><br />FILE_FLAG_OVERLAPPED = <span style=";font-family:Courier New;color:blue;" >0x40000000</span><br /><br />GENERIC_READ = <span style=";font-family:Courier New;color:blue;" >0x80000000</span><br />GENERIC_WRITE = <span style=";font-family:Courier New;color:blue;" >0x40000000</span><br />FILE_APPEND_DATA = <span style=";font-family:Courier New;color:blue;" >0x00000004</span><br /><br />FILE_SHARE_READ = <span style=";font-family:Courier New;color:blue;" >0x00000001</span><br />FILE_SHARE_WRITE = <span style=";font-family:Courier New;color:blue;" >0x00000002</span><br /><br />OPEN_EXISTING = <span style=";font-family:Courier New;color:blue;" >3</span><br />OPEN_ALWAYS = <span style=";font-family:Courier New;color:blue;" >4</span><br />CREATE_ALWAYS = <span style=";font-family:Courier New;color:blue;" >2</span><br /><br /><span style=";font-family:Courier New;color:green;" ># ----------------------------------------------------------------------------<br /></span><br /><b><span style=";font-family:Courier New;color:navy;" >class</span></b> <b><span style=";font-family:Courier New;color:blue;" >resultsManager</span></b>(object):<br /> <span style=";font-family:Courier New;color:olive;" >"""<br /> Manages the results sent by the CreateIoCompletionPort call.<br /> The resultsManager dequeues the IO requests and keeps a list of pending handles.<br /> The taskletID is stored in OVERLAPPED structure so it can be recalled and the<br /> signalling data sent via its channel unblocking the original tasklet.<br /> The handle is then removed from the dict.<br /> """</span><br /> <b><span style=";font-family:Courier New;color:navy;" >def</span></b> <b><span style=";font-family:Courier New;color:blue;" >__init__</span></b>(self, numThreads=NULL):<br /> self.running = True<br /> self.handle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL,<br /> NULL, numThreads)<br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> self.handle == <span style=";font-family:Courier New;color:blue;" >0</span>:<br /> raise WinError()<br /><br /> self.numThreads = numThreads<br /> stackless.tasklet(self.poll)()<br /> self.overlappedByID = {}<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >def</span></b> <b><span style=";font-family:Courier New;color:blue;" >__del__</span></b>(self):<br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> self.handle is None:<br /> <b><span style=";font-family:Courier New;color:navy;" >return</span></b><br /> self.overlappedByID.clear()<br /> CloseHandle(self.handle)<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >def</span></b> <b><span style=";font-family:Courier New;color:blue;" >poll</span></b>(self, timeout=<span style=";font-family:Courier New;color:blue;" >1</span>):<br /> <b><span style=";font-family:Courier New;color:navy;" >while</span></b> self.running <b><span style=";font-family:Courier New;color:navy;" >and</span></b> self.overlappedByID:<br /> numBytes = DWORD()<br /> completionKey = c_ulong()<br /> ovp = POINTER(OVERLAPPED)()<br /><br /> ret = GetQueuedCompletionStatus(self.handle, byref(numBytes),<br /> byref(completionKey), byref(ovp),<br /> timeout)<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> <b><span style=";font-family:Courier New;color:navy;" >not</span></b> ovp <b><span style=";font-family:Courier New;color:navy;" >and</span></b> ret == <span style=";font-family:Courier New;color:blue;" >0</span>:<br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> GetLastError() == WAIT_TIMEOUT:<br /> stackless.schedule()<br /> continue<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> ovp.contents.taskletID <b><span style=";font-family:Courier New;color:navy;" >in</span></b> self.overlappedByID:<br /> <span style=";font-family:Courier New;color:green;" >#print ovp.contents.taskletID, " tasklet ID IN pool"<br /></span> c = self.overlappedByID[ovp.contents.taskletID]<br /> <b><span style=";font-family:Courier New;color:navy;" >else</span></b>:<br /> <span style=";font-family:Courier New;color:green;" >#print ovp.contents.taskletID, " tasklet ID NOT in pool"<br /></span> continue<br /><br /> <span style=";font-family:Courier New;color:green;" >#print "sending data back to channel in ID", ovp.contents.taskletID<br /></span> c.send(numBytes)<br /> <span style=";font-family:Courier New;color:green;" >#print "sent data to channel in ID", ovp.contents.taskletID, numBytes<br /></span> self.UnregisterChannelObject(ovp.contents.taskletID)<br /><br /> self.running = False<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >def</span></b> <b><span style=";font-family:Courier New;color:blue;" >RegisterChannelObject</span></b>(self, ob, c):<br /> self.overlappedByID[ob] = c<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >def</span></b> <b><span style=";font-family:Courier New;color:blue;" >UnregisterChannelObject</span></b>(self, ob):<br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> self.overlappedByID.has_key(ob):<br /> del self.overlappedByID[ob]<br /><br /><br />mng = resultsManager()<br /><br /><b><span style=";font-family:Courier New;color:navy;" >class</span></b> <b><span style=";font-family:Courier New;color:blue;" >stacklessfile</span></b>(object):<br /> <span style=";font-family:Courier New;color:olive;" >"""<br /> stacklessfile(name[, mode[, buffering]]) -> stackless file object<br /><br /> This class creates a new file module permitting nonblocking IO calls<br /> for tasklets using windows IOCP functionality.<br /> When a read or write operation is called, only the calling tasklet is<br /> blocked. In standard file module, the whole interpreter gets blocked<br /> until the operation is concluded.<br /><br /> Open a file. The mode can be 'r', 'w' or 'a' for reading (default),<br /> writing or appending. The file will be created if it doesn't exist<br /> when opened for writing or appending; it will be truncated when<br /> opened for writing. Add a 'b' to the mode for binary files.<br /> Add a '+' to the mode to allow simultaneous reading and writing.<br /> If the buffering argument is given, 0 means unbuffered, 1 means line<br /> buffered, and larger numbers specify the buffer size.<br /> Add a 'U' to mode to open the file for input with universal newline<br /> support. Any line ending in the input file will be seen as a \'\\n\'<br /> in Python. Also, a file so opened gains the attribute 'newlines';<br /> the value for this attribute is one of None (no newline read yet),<br /> \'\\r\', \'\\n\', \'\\r\\n\' or a tuple containing all the newline types seen.<br /> """</span><br /> closed = True<br /> <b><span style=";font-family:Courier New;color:navy;" >def</span></b> <b><span style=";font-family:Courier New;color:blue;" >__init__</span></b>(self, name, mode=<span style=";font-family:Courier New;color:olive;" >'r'</span>, buffering=-<span style=";font-family:Courier New;color:blue;" >1</span>):<br /> <span style=";font-family:Courier New;color:olive;" >"""<br /> Initializes the file object and creates an internal file object.<br /> """</span><br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> <b><span style=";font-family:Courier New;color:navy;" >not</span></b> self.closed:<br /> self.close()<br /> self.name = name<br /> self.mode = mode<br /> self.offset = <span style=";font-family:Courier New;color:blue;" >0</span><br /> self.iocpLinked = False<br /> self._check_manager()<br /> self.open_handle()<br /> self.closed = False<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >def</span></b> <b><span style=";font-family:Courier New;color:blue;" >__repr__</span></b>(self):<br /> <b><span style=";font-family:Courier New;color:navy;" >return</span></b> <span style=";font-family:Courier New;color:olive;" >"<%s file '%s', mode '%s' at 0x%08X>"</span> % ([ <span style=";font-family:Courier New;color:olive;" >"open"</span>, <span style=";font-family:Courier New;color:olive;" >"closed"</span> ][self.closed], self.name, self.mode, id(self))<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >def</span></b> <b><span style=";font-family:Courier New;color:blue;" >__del__</span></b>(self):<br /> self.close()<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >def</span></b> <b><span style=";font-family:Courier New;color:blue;" >_check_manager</span></b>(self):<br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> <b><span style=";font-family:Courier New;color:navy;" >not</span></b> mng.running:<br /> stackless.tasklet(mng.poll)()<br /> mng.running = True<br /> <span style=";font-family:Courier New;color:green;" >#print "ERROR - Manager not running"<br /></span><br /> <b><span style=";font-family:Courier New;color:navy;" >def</span></b> <b><span style=";font-family:Courier New;color:blue;" >_check_still_open</span></b>(self):<br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> self.closed:<br /> raise ValueError(<span style=";font-family:Courier New;color:olive;" >"I/O operation on closed file"</span>)<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >def</span></b> <b><span style=";font-family:Courier New;color:blue;" >_ensure_iocp_association</span></b>(self):<br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> <b><span style=";font-family:Courier New;color:navy;" >not</span></b> self.iocpLinked:<br /> CreateIoCompletionPort(self.handle, mng.handle, NULL, mng.numThreads)<br /> self.iocpLinked = True<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >def</span></b> <b><span style=";font-family:Courier New;color:blue;" >close</span></b>(self):<br /> <span style=";font-family:Courier New;color:olive;" >"""<br /> close() -> None or (perhaps) an integer. Close the file.<br /><br /> Sets data attribute .closed to True. A closed file canno<br /> further I/O operations. close() may be called more than<br /> error. Some kinds of file objects (for example, opened b<br /> may return an exit status upon closing.<br /> """</span><br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> <b><span style=";font-family:Courier New;color:navy;" >not</span></b> self.closed:<br /> CloseHandle(self.handle)<br /> del self.handle<br /> self.closed = True<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >def</span></b> <b><span style=";font-family:Courier New;color:blue;" >open_handle</span></b>(self):<br /> self.binary = <span style=";font-family:Courier New;color:olive;" >'b'</span> <b><span style=";font-family:Courier New;color:navy;" >in</span></b> self.mode<br /> access = GENERIC_READ<br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> <span style=";font-family:Courier New;color:olive;" >'w'</span> <b><span style=";font-family:Courier New;color:navy;" >in</span></b> self.mode <b><span style=";font-family:Courier New;color:navy;" >or</span></b> (<span style=";font-family:Courier New;color:olive;" >'r'</span> <b><span style=";font-family:Courier New;color:navy;" >in</span></b> self.mode <b><span style=";font-family:Courier New;color:navy;" >and</span></b> <span style=";font-family:Courier New;color:olive;" >'+'</span> <b><span style=";font-family:Courier New;color:navy;" >in</span></b> self.mode):<br /> access |= GENERIC_WRITE<br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> <span style=";font-family:Courier New;color:olive;" >'a'</span> <b><span style=";font-family:Courier New;color:navy;" >in</span></b> self.mode:<br /> access |= FILE_APPEND_DATA<br /><br /> share = FILE_SHARE_READ | FILE_SHARE_WRITE<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> <span style=";font-family:Courier New;color:olive;" >'w'</span> <b><span style=";font-family:Courier New;color:navy;" >in</span></b> self.mode:<br /> disposition = CREATE_ALWAYS<br /> <b><span style=";font-family:Courier New;color:navy;" >elif</span></b> <span style=";font-family:Courier New;color:olive;" >'r'</span> <b><span style=";font-family:Courier New;color:navy;" >in</span></b> self.mode <b><span style=";font-family:Courier New;color:navy;" >and</span></b> <span style=";font-family:Courier New;color:olive;" >'+'</span> <b><span style=";font-family:Courier New;color:navy;" >in</span></b> self.mode:<br /> disposition = OPEN_ALWAYS<br /> <b><span style=";font-family:Courier New;color:navy;" >else</span></b>:<br /> disposition = OPEN_EXISTING<br /><br /> flags = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_OVERLAPPED<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> isinstance(self.name, unicode):<br /> func = CreateFileW<br /> <b><span style=";font-family:Courier New;color:navy;" >else</span></b>:<br /> func = CreateFileA<br /><br /> self.handle = func(self.name, access,<br /> share, c_void_p(), disposition,<br /> flags, NULL )<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> self.handle == INVALID_HANDLE_VALUE:<br /> raise WinError()<br /><br /> self.iocpLinked = False<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >def</span></b> <b><span style=";font-family:Courier New;color:blue;" >read</span></b>(self, size=None):<br /> <span style=";font-family:Courier New;color:olive;" >"""<br /> read([size]) -> read at most size bytes, returned as a string.<br /> """</span><br /> self._check_still_open()<br /> maxBytesToRead = int(os.path.getsize(self.name)) - self.offset<br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> (size is None) <b><span style=";font-family:Courier New;color:navy;" >or</span></b> (maxBytesToRead < size):<br /> size = maxBytesToRead<br /><br /> bytesRead = DWORD()<br /> self.o = OVERLAPPED()<br /> self.o.Offset = self.offset<br /> self.o.taskletID = id(self)<br /> self.buffer = create_string_buffer(size)<br /> self.channel = stackless.channel()<br /> self._ensure_iocp_association()<br /> self._check_manager()<br /><br /> <span style=";font-family:Courier New;color:green;" >#print self.o.taskletID, "ID on read", self.name<br /></span> <span style=";font-family:Courier New;color:green;" >#print "firing ReadFile", self.name<br /></span><br /> r = ReadFile(self.handle, self.buffer,<br /> size, byref(bytesRead), byref(self.o));<br /> <span style=";font-family:Courier New;color:green;" >#print "fired ReadFile", self.name<br /></span><br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> r == <span style=";font-family:Courier New;color:blue;" >0</span>:<br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> GetLastError() != ERROR_IO_PENDING:<br /> pythonapi.PyErr_SetExcFromWindowsErrWithFilename(py_object(IOError),<br /> <span style=";font-family:Courier New;color:blue;" >0</span>, c_char_p(self.name))<br /> mng.RegisterChannelObject(self.o.taskletID, self.channel)<br /> <span style=";font-family:Courier New;color:green;" >#print "blocked on channel",self.channel, self.name, self.o.taskletID<br /></span> self.channel.receive()<br /> <span style=";font-family:Courier New;color:green;" >#print "returned from channel",self.channel, self.name, self.o.taskletID<br /></span><br /> self.offset += size<br /> <b><span style=";font-family:Courier New;color:navy;" >return</span></b> self.buffer[:size]<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >def</span></b> <b><span style=";font-family:Courier New;color:blue;" >write</span></b>(self, data):<br /> <span style=";font-family:Courier New;color:olive;" >"""<br /> write(str) -> None. Write string str to file.<br /> """</span><br /> self._check_still_open()<br /> bytesToWrite = c_int()<br /> writeBufferPtr = c_char_p()<br /> bytesWritten = DWORD()<br /> self.o = OVERLAPPED()<br /> self.o.Offset = self.offset<br /> self.o.taskletID = id(self)<br /> self.channel = stackless.channel()<br /> self._ensure_iocp_association()<br /> self._check_manager()<br /> <span style=";font-family:Courier New;color:green;" >#print self.o.taskletID, "ID on write", self.name<br /></span><br /> fmt = self.binary <b><span style=";font-family:Courier New;color:navy;" >and</span></b> <span style=";font-family:Courier New;color:olive;" >"s#"</span> <b><span style=";font-family:Courier New;color:navy;" >or</span></b> <span style=";font-family:Courier New;color:olive;" >"t#"</span><br /> ret = pythonapi.PyArg_ParseTuple(py_object((data,)), c_char_p(fmt),<br /> byref(writeBufferPtr), byref(bytesToWrite))<br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> ret == <span style=";font-family:Courier New;color:blue;" >0</span>:<br /> raise WinError()<br /><br /> <span style=";font-family:Courier New;color:green;" >#print "firing WriteFile", self.name<br /></span> r = WriteFile(self.handle, writeBufferPtr,<br /> bytesToWrite.value, byref(bytesWritten), byref(self.o))<br /> <span style=";font-family:Courier New;color:green;" >#print "fired WriteFile", self.name<br /></span><br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> r == <span style=";font-family:Courier New;color:blue;" >0</span>:<br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> GetLastError() != ERROR_IO_PENDING:<br /> pythonapi.PyErr_SetExcFromWindowsErrWithFilename(py_object(IOError),<br /> <span style=";font-family:Courier New;color:blue;" >0</span>, c_char_p(self.name))<br /><br /> mng.RegisterChannelObject(self.o.taskletID, self.channel)<br /> <span style=";font-family:Courier New;color:green;" >#print "blocked on channel",self.channel, self.name, self.o.taskletID<br /></span> written = self.channel.receive()<br /> <span style=";font-family:Courier New;color:green;" >#print "returned from channel",self.channel, self.name, self.o.taskletID<br /></span> <b><span style=";font-family:Courier New;color:navy;" >else</span></b>:<br /> written = bytesWritten<br /> <span style=";font-family:Courier New;color:green;" >#print "Checking contents...", bytesToWrite.value, written.value, self.name<br /></span><br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> bytesToWrite.value != written.value:<br /> <span style=";font-family:Courier New;color:green;" ># Check if the quantity of bytes sent has been written to the file<br /></span> <span style=";font-family:Courier New;color:green;" >#print self.o.taskletID, "size mismatch"<br /></span> raise WinError()<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >def</span></b> <b><span style=";font-family:Courier New;color:blue;" >tell</span></b>(self):<br /> <span style=";font-family:Courier New;color:olive;" >"""<br /> tell() -> current file position, an integer (may be a long integer).<br /> """</span><br /> <b><span style=";font-family:Courier New;color:navy;" >return</span></b> self.offset<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >def</span></b> <b><span style=";font-family:Courier New;color:blue;" >seek</span></b>(self, offset, whence=os.SEEK_SET):<br /> <span style=";font-family:Courier New;color:olive;" >"""<br /> seek(offset[, whence]) -> None. Move to new file position.<br /><br /> Argument offset is a byte count. Optional argument whence defaults to<br /> 0 (offset from start of file, offset should be >= 0); other values are 1<br /> (move relative to current position, positive or negative), and 2 (move<br /> relative to end of file, usually negative, although many platforms allow<br /> seeking beyond the end of a file). If the file is opened in text mode,<br /> only offsets returned by tell() are legal. Use of other offsets causes<br /> undefined behavior.<br /> Note that not all file objects are seekable.<br /> """</span><br /> self._check_still_open()<br /> <b><span style=";font-family:Courier New;color:navy;" >if</span></b> whence == os.SEEK_SET:<br /> self.offset = offset<br /> <b><span style=";font-family:Courier New;color:navy;" >elif</span></b> whence == os.SEEK_CUR:<br /> self.offset += offset<br /> <b><span style=";font-family:Courier New;color:navy;" >elif</span></b> whence == os.SEEK_END:<br /> raise RuntimeError(<span style=";font-family:Courier New;color:olive;" >"SEEK_END unimplemented"</span>)<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >def</span></b> <b><span style=";font-family:Courier New;color:blue;" >flush</span></b>(self):<br /> pass<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >def</span></b> <b><span style=";font-family:Courier New;color:blue;" >isatty</span></b>(self):<br /> <span style=";font-family:Courier New;color:olive;" >"""<br /> isatty() -> true or false. True if the file is connected to a tty device.<br /> """</span><br /> self._check_still_open()<br /> <b><span style=";font-family:Courier New;color:navy;" >return</span></b> False<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >def</span></b> <b><span style=";font-family:Courier New;color:blue;" >isatty</span></b>(self):<br /> self._check_still_open()<br /> <b><span style=";font-family:Courier New;color:navy;" >return</span></b> False<br /><br /><br /><b><span style=";font-family:Courier New;color:navy;" >if</span></b> __name__ == <span style=";font-family:Courier New;color:olive;" >'__main__'</span>:<br /> <b><span style=";font-family:Courier New;color:navy;" >import</span></b> time<br /> <b><span style=";font-family:Courier New;color:navy;" >import</span></b> glob<br /> <b><span style=";font-family:Courier New;color:navy;" >import</span></b> os<br /> stdfile = file<br /><br /> <span style=";font-family:Courier New;color:green;" ># On your stackless apps, use these 2 lines below<br /></span> <b><span style=";font-family:Courier New;color:navy;" >from</span></b> stacklessfile <b><span style=";font-family:Courier New;color:navy;" >import</span></b> stacklessfile as file<br /> open = file<br /><br /> <span style=";font-family:Courier New;color:green;" ># Function to copy a file<br /></span> <b><span style=";font-family:Courier New;color:navy;" >def</span></b> <b><span style=";font-family:Courier New;color:blue;" >copyfile</span></b>(who, infile, out):<br /> st = time.time()<br /> f1 = file(infile, <span style=";font-family:Courier New;color:olive;" >'rb'</span>)<br /> f2 = file(out, <span style=";font-family:Courier New;color:olive;" >'wb'</span>)<br /> <b><span style=";font-family:Courier New;color:navy;" >print</span></b> <span style=";font-family:Courier New;color:olive;" >"%s started reading %s ..."</span> % (who, infile)<br /> a = f1.read()<br /> <b><span style=";font-family:Courier New;color:navy;" >print</span></b> <span style=";font-family:Courier New;color:olive;" >"%s started writing %s -> %s ..."</span> % (who, infile, out)<br /> f2.write(a)<br /> f1.close()<br /> f2.close()<br /> <b><span style=";font-family:Courier New;color:navy;" >print</span></b> <span style=";font-family:Courier New;color:olive;" >"Finished tasklet %s (%s) in %s"</span> % (who, infile, time.time()-st)<br /><br /> <span style=";font-family:Courier New;color:green;" ># Creating two dummy files<br /></span> newfile = stdfile(<span style=";font-family:Courier New;color:olive;" >'test-small.txt'</span>,<span style=";font-family:Courier New;color:olive;" >'w'</span>)<br /> <b><span style=";font-family:Courier New;color:navy;" >for</span></b> x <b><span style=";font-family:Courier New;color:navy;" >in</span></b> xrange(<span style=";font-family:Courier New;color:blue;" >10000</span>):<br /> newfile.write(str(x))<br /> newfile.close()<br /><br /> newfile2 = stdfile(<span style=";font-family:Courier New;color:olive;" >'test-big.txt'</span>,<span style=";font-family:Courier New;color:olive;" >'w'</span>)<br /> <b><span style=";font-family:Courier New;color:navy;" >for</span></b> x <b><span style=";font-family:Courier New;color:navy;" >in</span></b> xrange(<span style=";font-family:Courier New;color:blue;" >500000</span>):<br /> newfile2.write(str(x))<br /> newfile2.close()<br /><br /> <span style=";font-family:Courier New;color:green;" ># Launching tasklets to perform the file copy<br /></span> <b><span style=";font-family:Courier New;color:navy;" >for</span></b> i <b><span style=";font-family:Courier New;color:navy;" >in</span></b> xrange(<span style=";font-family:Courier New;color:blue;" >1</span>,<span style=";font-family:Courier New;color:blue;" >11</span>):<br /> stackless.tasklet(copyfile)(i, <span style=";font-family:Courier New;color:olive;" >'test-big.txt'</span>,<span style=";font-family:Courier New;color:olive;" >'big%s.txt'</span> % i)<br /><br /> <b><span style=";font-family:Courier New;color:navy;" >for</span></b> i <b><span style=";font-family:Courier New;color:navy;" >in</span></b> xrange(<span style=";font-family:Courier New;color:blue;" >1</span>,<span style=";font-family:Courier New;color:blue;" >21</span>):<br /> stackless.tasklet(copyfile)(i, <span style=";font-family:Courier New;color:olive;" >'test-small.txt'</span>,<span style=";font-family:Courier New;color:olive;" >'sm%s.txt'</span> % i)<br /><br /> st = time.time()<br /> stackless.run()<br /> <b><span style=";font-family:Courier New;color:navy;" >print</span></b> <span style=";font-family:Courier New;color:olive;" >"Total time is %s seconds."</span> % (time.time() - st)<br /><br /> <span style=";font-family:Courier New;color:green;" ># Cleanup all test files used<br /></span> <b><span style=";font-family:Courier New;color:navy;" >for</span></b> f <b><span style=";font-family:Courier New;color:navy;" >in</span></b> glob.glob(<span style=";font-family:Courier New;color:olive;" >'test*.txt'</span>):<br /> os.unlink(f)<br /> <b><span style=";font-family:Courier New;color:navy;" >for</span></b> f <b><span style=";font-family:Courier New;color:navy;" >in</span></b> glob.glob(<span style=";font-family:Courier New;color:olive;" >'sm*.txt'</span>):<br /> os.unlink(f)<br /> <b><span style=";font-family:Courier New;color:navy;" >for</span></b> f <b><span style=";font-family:Courier New;color:navy;" >in</span></b> glob.glob(<span style=";font-family:Courier New;color:olive;" >'big*.txt'</span>):<br /> os.unlink(f)<br /></span>Carlos Eduardohttp://www.blogger.com/profile/00674164975841007118noreply@blogger.com3tag:blogger.com,1999:blog-6035667965789416859.post-32345389671803317522007-08-01T09:50:00.000-03:002007-08-01T15:16:04.325-03:00Stackless Python, open your mind to itThis morning I was delighted to see a post by <a href="http://muharem.wordpress.com/2007/07/31/erlang-vs-stackless-python-a-first-benchmark/">Muharem Hrnjadovic post</a> about Stackless Python. Its great to see that its usage is getting widespread and its benefits demonstrated and shown to everyone.<br /><br />I'm telling this because some time ago I started to play with Erlang and liked it a lot. Because of work issues I didn't have enough time to keep my studies (I plan to buy Joe Armstrong's book) but I found it a great language and with its focus on parallel processing made me think about a comparison with Stackless.<br /><br />For my surprise, it happened today on Muharen's post. He did a great job creating both apps and comparing them even with graphics demonstrating the results. It showed that Stackless is great for the job and should be considered for a lot more projects than it is now.<br /><br />For more information on Stackless visit <a href="http://www.stackless.com/">www.stackless.com</a>, the <a href="http://news.gmane.org/gmane.comp.python.stackless">Stackless mailing list</a> or the Stackless Examples project hosted on <a href="http://code.google.com/p/stacklessexamples/">http://code.google.com/p/stacklessexamples/</a> where we have an increasing number of samples and day to day use cases.Carlos Eduardohttp://www.blogger.com/profile/00674164975841007118noreply@blogger.com0tag:blogger.com,1999:blog-6035667965789416859.post-33560052693565948452007-07-02T18:14:00.000-03:002007-07-02T18:56:06.231-03:00Stackless Python for PSP progressAs the time goes by, a lot of progress has been made in my Stackless port for the Sony PSP.<br /><br />Here I will list everything that changed since the last published archive:<br /><br /><ul><li>Time function returns correct date based on PSP Timezone<br /></li></ul><ul><li>OGG Vorbis support</li><ul><li>I have added a basic OGG Vorbis support for the port. The API is based on oggplayer from PSPMediaCenter. The problem is that i loads the entire file into memory and playbacks it from there. On MP3 this doesnt happens.. more below.</li><li>The API for the OGG is very simple, a sample application follows at the end of the post.</li></ul><li>MP3 Support</li><ul><li>Its here! With the great help from Ghoti (thanks Rein) the MP3 streaming playback is now available transparently. What streaming means? Your application wont load the entire file into memory for playback. The application creates a buffer and loads small chunks from disk as needed. This leaves a lot of memory to the interpreter and you play with. In my tests, my interpreter have around 18Mb RAM available.</li><li>A small demo is in the bottom of this post.</li></ul><li>SSL Support</li><ul><li>This is the latest addition. Since I cant test all its functionality, I need someone to test it for me. I made a small test where a <span style="font-family: courier new;">import socket; hasattr(socket, "ssl")<span style="font-family: georgia;">returned "True" so I assumed everything was fine.</span></span></li></ul></ul>All this progress couldn't be made without the help of a lot of people. Jerome for its awesome Python port, Jim for his oggplayer and mp3player libraries based on libTremor and libMad. Ghoti for the MP3 streaming support and all guys that ported the libraries to PSP.<br /><br />Now I will start tracking the released versions using my own version numbers after a _ character.<br /><br />This new release is named: <a href="http://stacklesspsp.googlepages.com/PSP-Stackless-2.4.4_1.zip">PSP-Stackless-2.4.4_1.zip</a> and can be downloaded <a href="http://stacklesspsp.googlepages.com/PSP-Stackless-2.4.4_1.zip">here</a>.<br /><br />Here are some example apps:<br /><br />OGG Playback:<br /><br /><span style="font-family: courier new;">import pspogg, psp2d</span><br /><br /><span style="font-family: courier new;">pspogg.init(2)</span><br /><span style="font-family: courier new;">pspogg.load('REALTEST.OGG')</span><br /><br /><span style="font-family: courier new;">pspogg.play()</span><br /><br /><span style="font-family: courier new;">while 1:</span><br /><span style="font-family: courier new;"> pad = psp2d.Controller()</span><br /><span style="font-family: courier new;"> if pspogg.endofstream() == 1 or pad.cross:</span><br /><span style="font-family: courier new;"> print pspogg.getsec()</span><br /><span style="font-family: courier new;"> print "end of stream"</span><br /><span style="font-family: courier new;"> pspogg.end()</span><br /><span style="font-family: courier new;"> break</span><br /><br /><span style="font-family: courier new;">print "exit"</span><br /><br />MP3 Playback:<br /><br /><span style="font-family: courier new;">import pspmp3, psp2d</span><br /><br /><span style="font-family: courier new;">pspmp3.init(1)</span><br /><span style="font-family: courier new;">pspmp3.load('test.mp3')</span><br /><span style="font-family: courier new;">pspmp3.play()</span><br /><br /><span style="font-family: courier new;">while 1:</span><br /><span style="font-family: courier new;"> global lastPad</span><br /><span style="font-family: courier new;"> pad = psp2d.Controller()</span><br /><span style="font-family: courier new;"> if pspmp3.endofstream() == 1 or pad.cross:</span><br /><span style="font-family: courier new;"> print pspmp3.gettime()</span><br /><span style="font-family: courier new;"> pspmp3.end()</span><br /><span style="font-family: courier new;"> break</span><br /><br /><span style="font-family: courier new;">print "exit"</span><br /><br />SSL Support:<br /><br /><span style="font-family: courier new;">import socket</span><br /><span style="font-family: courier new;">print hasattr(socket, "ssl")</span><br /><br /><br />The modules have the following API:<br /><br /><span style="font-weight: bold;">pspogg</span><br /><br />pspogg.init(ch) Initializes the OGGVorbis subsystem.<br />pspogg.load(file) Loads an OGG file.<br />pspogg.stop() Stop OGG playback.<br />pspogg.pause() Pauses OGG playback, call again to unpause.<br />pspogg.play() Play a loaded OGG file.<br />pspogg.endofstream() Returns 1 if stream has ended.<br />pspogg.getsec() Returns the stream play time in seconds.<br />pspogg.getmin() Returns the stream play time in minutes.<br />pspogg.gethour() Returns the stream play time in hours.<br />pspogg.volume(vol) Sets the OGG subsystem volume.<br />pspogg.end() Stops playback and free up used memory.<br /><br /><span style="font-weight: bold;">pspmp3</span><br /><br />pspmp3.init(ch) Initializes the MP3 subsystem.<br />pspmp3.load(file) Loads a MP3 file.<br />pspmp3.stop() Stop MP3 playback.<br />pspmp3.pause() Pauses MP3 playback, call again to unpause.<br />pspmp3.play() Play a loaded MP3 file.<br />pspmp3.endofstream() Returns 1 if stream has ended.<br />pspmp3.gettime() Returns the stream play time in format HH:MM:SS.<br />pspmp3.freetune() Free up used memory and releases MP3 subsystem.<br />pspmp3.end() Stops playback and calls freetune.<br /><br />Carlos<br />carlosedp+themindcaster@gmail.comCarlos Eduardohttp://www.blogger.com/profile/00674164975841007118noreply@blogger.com8tag:blogger.com,1999:blog-6035667965789416859.post-64672429981217930182007-06-25T10:29:00.000-03:002007-06-25T10:50:40.231-03:00Stackless for PSP Tutorial - Part 1As promised, today I will start a series of small tutorials for the Stackless usage.<br /><br />The examples will be focused on PSP but they can all be implemented for <a href="http://www.pygame.org">Pygame</a>, just switch the graphic functions in psp2d.<br /><br />A great package that helps a lot the development is the <a href="http://stacklesspsp.googlepages.com/psplibs-pygame_mockup.rar">psp mockup libraries</a>. They mimic the psp2d module and translates them to Pygame. With an installation of Python and Pygame you can test all your programs in PC before putting them in the PSP.<br /><br />Well, lets start the tutorial, the code is very documented and can be easily understood, if you have any questions, contact me over the commentaries or my email - carlosedp+themindcaster at gmail.com<br /><br />The full code package can be downloaded <a href="http://stacklesspsp.googlepages.com/Tutorial-1.zip">here</a>.<br /><br />The Stackless for PSP can be downloaded <a href="http://stacklesspsp.googlepages.com/PSP-Stackless-2.4.4.zip">here</a>.<br /><br /><span style="font-size:85%;"><span style="font-family:courier new;"># -*- coding: iso-8859-1 -*-</span><br /><br /><span style="font-family:courier new;">'''</span><br /><span style="font-family:courier new;">This is an example on using Stackless Python in PSP. The idea is based on a</span><br /><span style="font-family:courier new;">tutorial created by Sakya.</span><br /><br /><span style="font-family:courier new;">Here we have the concept of agent based programming where the player, the NPC</span><br /><span style="font-family:courier new;">and the render engine as an agent doing its actions.</span><br /><br /><span style="font-family:courier new;">The player agent waits for the user input captured from the keypad.</span><br /><br /><span style="font-family:courier new;">The NPC agent starts running aroundn the screen in a predefined pattern.</span><br /><br /><span style="font-family:courier new;">The render engine does all the drawing job clearing the screen and putting each</span><br /><span style="font-family:courier new;">agent in its own place.</span><br /><br /><span style="font-family:courier new;">As you can see, all the logic is very simplified because of the flexibility</span><br /><span style="font-family:courier new;">stackless gives to us. Every agent can have its own behaviour and optionally</span><br /><span style="font-family:courier new;">follow some "world" rules defined for example in a separate Agent.</span><br /><br /><span style="font-family:courier new;">This "World" could detect collisions, handle communications between agents and</span><br /><span style="font-family:courier new;">interact with other elements. This can be an exercise to the user.</span><br /><br /><span style="font-family:courier new;">'''</span><br /><span style="font-family:courier new;">import psp2d, pspos</span><br /><span style="font-family:courier new;">from time import time</span><br /><span style="font-family:courier new;">import sys</span><br /><span style="font-family:courier new;">import stackless</span><br /><br /><span style="font-family:courier new;"># Set processor and bus speed</span><br /><span style="font-family:courier new;">pspos.setclock(222)</span><br /><span style="font-family:courier new;">pspos.setbus(111)</span><br /><br /><span style="font-family:courier new;"># Creates the screen and its background color (Black)</span><br /><span style="font-family:courier new;">screen = psp2d.Screen()</span><br /><span style="font-family:courier new;">screen.clear(psp2d.Color(0,0,0,255))</span><br /><br /><span style="font-family:courier new;"># Loads the font</span><br /><span style="font-family:courier new;">font = psp2d.Font('font.png')</span><br /><br /><span style="font-family:courier new;"># Loads the character movement images</span><br /><span style="font-family:courier new;">spriteImages = []</span><br /><span style="font-family:courier new;">spriteImages.append((psp2d.Image('amg1_bk1.png'), psp2d.Image('amg1_bk2.png'))) #Direction = north = 0</span><br /><span style="font-family:courier new;">spriteImages.append((psp2d.Image('amg1_fr1.png'), psp2d.Image('amg1_fr2.png'))) #Direction = south = 1</span><br /><span style="font-family:courier new;">spriteImages.append((psp2d.Image('amg1_lf1.png'), psp2d.Image('amg1_lf2.png'))) #Direction = west = 2</span><br /><span style="font-family:courier new;">spriteImages.append((psp2d.Image('amg1_rt1.png'), psp2d.Image('amg1_rt2.png'))) #Direction = east = 3</span><br /><br /><br /><span style="font-family:courier new;"># Creates the Agent base class</span><br /><span style="font-family:courier new;">class Agent(object):</span><br /><span style="font-family:courier new;"> def __init__(self):</span><br /><span style="font-family:courier new;"> self.ch = stackless.channel() # Communication channel (not used here)</span><br /><span style="font-family:courier new;"> self.running = True # Flag to control the running status</span><br /><span style="font-family:courier new;"> stackless.tasklet(self.runAction)() # Creates the agent tasklet</span><br /><br /><span style="font-family:courier new;"> def runAction(self):</span><br /><span style="font-family:courier new;"> # Here we define the main action, a repetition of the function self.action()</span><br /><span style="font-family:courier new;"> while self.running:</span><br /><span style="font-family:courier new;"> # Runs the action</span><br /><span style="font-family:courier new;"> self.action()</span><br /><span style="font-family:courier new;"> # Give other tasklets its turn</span><br /><span style="font-family:courier new;"> stackless.schedule()</span><br /><br /><span style="font-family:courier new;"> def action(self):</span><br /><span style="font-family:courier new;"> # In the base class do nothing</span><br /><span style="font-family:courier new;"> pass</span><br /><br /><span style="font-family:courier new;">class player(Agent):</span><br /><span style="font-family:courier new;"> def __init__(self, rend):</span><br /><span style="font-family:courier new;"> Agent.__init__(self)</span><br /><span style="font-family:courier new;"> self.rend = rend # Reference to the renderer tasklet</span><br /><span style="font-family:courier new;"> self.boolSprite = False</span><br /><span style="font-family:courier new;"> self.direction = 1</span><br /><span style="font-family:courier new;"> self.speed = 3</span><br /><span style="font-family:courier new;"> self.posX = 30</span><br /><span style="font-family:courier new;"> self.posY = 30</span><br /><span style="font-family:courier new;"> self.lastPad = time()</span><br /><span style="font-family:courier new;"> self.rend.agents.append(self) # Adds this agent to the renderer</span><br /><span style="font-family:courier new;"> self.sprite = spriteImages[self.direction][int(self.boolSprite)]</span><br /><br /><span style="font-family:courier new;"> def action(self):</span><br /><span style="font-family:courier new;"> self.sprite = spriteImages[self.direction][int(self.boolSprite)]</span><br /><span style="font-family:courier new;"> pad = psp2d.Controller()</span><br /><span style="font-family:courier new;"> if pad.cross:</span><br /><span style="font-family:courier new;"> print "exit"</span><br /><span style="font-family:courier new;"> self.rend.exit()</span><br /><span style="font-family:courier new;"> elif pad.triangle:</span><br /><span style="font-family:courier new;"> screen.saveToFile("ms0:/PSP/PHOTO/screenshot.png")</span><br /><span style="font-family:courier new;"> elif pad.down and (not self.lastPad or time() - self.lastPad >= 0.05):</span><br /><span style="font-family:courier new;"> #Draw the player facing south:</span><br /><span style="font-family:courier new;"> self.lastPad = time()</span><br /><span style="font-family:courier new;"> self.direction = 1</span><br /><span style="font-family:courier new;"> if self.posY + self.sprite.height + self.speed <><br /><span style="font-family:courier new;"> self.posY += self.speed</span><br /><span style="font-family:courier new;"> self.boolSprite = not self.boolSprite</span><br /><span style="font-family:courier new;"> elif pad.up and (not self.lastPad or time() - self.lastPad >= 0.05):</span><br /><span style="font-family:courier new;"> #Draw the player facing north:</span><br /><span style="font-family:courier new;"> self.lastPad = time()</span><br /><span style="font-family:courier new;"> self.direction = 0</span><br /><span style="font-family:courier new;"> if self.posY - self.speed >= 0:</span><br /><span style="font-family:courier new;"> self.posY -= self.speed</span><br /><span style="font-family:courier new;"> self.boolSprite = not self.boolSprite</span><br /><span style="font-family:courier new;"> elif pad.left and (not self.lastPad or time() - self.lastPad >= 0.05):</span><br /><span style="font-family:courier new;"> #Draw the player facing west:</span><br /><span style="font-family:courier new;"> self.lastPad = time()</span><br /><span style="font-family:courier new;"> self.direction = 2</span><br /><span style="font-family:courier new;"> if self.posX - self.speed >= 0:</span><br /><span style="font-family:courier new;"> self.posX -= self.speed</span><br /><span style="font-family:courier new;"> self.boolSprite = not self.boolSprite</span><br /><span style="font-family:courier new;"> elif pad.right and (not self.lastPad or time() - self.lastPad >= 0.05):</span><br /><span style="font-family:courier new;"> #Draw the player facing east:</span><br /><span style="font-family:courier new;"> self.lastPad = time()</span><br /><span style="font-family:courier new;"> self.direction = 3</span><br /><span style="font-family:courier new;"> if self.posX + self.sprite.width + self.speed <><br /><span style="font-family:courier new;"> self.posX += self.speed</span><br /><span style="font-family:courier new;"> self.boolSprite = not self.boolSprite</span><br /><br /><span style="font-family:courier new;">class NPC(Agent):</span><br /><span style="font-family:courier new;"> def __init__(self, rend):</span><br /><span style="font-family:courier new;"> Agent.__init__(self)</span><br /><span style="font-family:courier new;"> self.rend = rend</span><br /><span style="font-family:courier new;"> self.boolSprite = False</span><br /><span style="font-family:courier new;"> self.direction = 0</span><br /><span style="font-family:courier new;"> self.speed = 5</span><br /><span style="font-family:courier new;"> self.posX = 230</span><br /><span style="font-family:courier new;"> self.posY = 230</span><br /><span style="font-family:courier new;"> self.lastPad = time()</span><br /><span style="font-family:courier new;"> self.rend.agents.append(self)</span><br /><span style="font-family:courier new;"> self.sprite = spriteImages[self.direction][int(self.boolSprite)]</span><br /><span style="font-family:courier new;"> self.count = 20</span><br /><br /><span style="font-family:courier new;"> def action(self):</span><br /><span style="font-family:courier new;"> # This NPC runs around the screen changing its direction when touches the border.</span><br /><span style="font-family:courier new;"> self.sprite = spriteImages[self.direction][int(self.boolSprite)]</span><br /><span style="font-family:courier new;"> if self.direction == 0 and (not self.lastPad or time() - self.lastPad >= 0.05):</span><br /><span style="font-family:courier new;"> self.lastPad = time()</span><br /><span style="font-family:courier new;"> if self.posY - self.speed >= 20:</span><br /><span style="font-family:courier new;"> self.posY -= self.speed</span><br /><span style="font-family:courier new;"> self.boolSprite = not self.boolSprite</span><br /><span style="font-family:courier new;"> else:</span><br /><span style="font-family:courier new;"> self.direction = 2</span><br /><span style="font-family:courier new;"> if self.direction == 2 and (not self.lastPad or time() - self.lastPad >= 0.05):</span><br /><span style="font-family:courier new;"> self.lastPad = time()</span><br /><span style="font-family:courier new;"> if self.posX - self.speed > 0:</span><br /><span style="font-family:courier new;"> self.posX -= self.speed</span><br /><span style="font-family:courier new;"> self.boolSprite = not self.boolSprite</span><br /><span style="font-family:courier new;"> else:</span><br /><span style="font-family:courier new;"> self.direction = 1</span><br /><span style="font-family:courier new;"> if self.direction == 1 and (not self.lastPad or time() - self.lastPad >= 0.05):</span><br /><span style="font-family:courier new;"> self.lastPad = time()</span><br /><span style="font-family:courier new;"> if self.posY + self.sprite.height + self.speed <><br /><span style="font-family:courier new;"> self.posY += self.speed</span><br /><span style="font-family:courier new;"> self.boolSprite = not self.boolSprite</span><br /><span style="font-family:courier new;"> else:</span><br /><span style="font-family:courier new;"> self.direction = 3</span><br /><span style="font-family:courier new;"> if self.direction == 3 and (not self.lastPad or time() - self.lastPad >= 0.05):</span><br /><span style="font-family:courier new;"> self.lastPad = time()</span><br /><span style="font-family:courier new;"> if self.posX + self.sprite.width + self.speed <><br /><span style="font-family:courier new;"> self.posX += self.speed</span><br /><span style="font-family:courier new;"> self.boolSprite = not self.boolSprite</span><br /><span style="font-family:courier new;"> else:</span><br /><span style="font-family:courier new;"> self.direction = 0</span><br /><br /><br /><span style="font-family:courier new;">class render(Agent):</span><br /><span style="font-family:courier new;"> # This is the renderer agent</span><br /><span style="font-family:courier new;"> def __init__(self):</span><br /><span style="font-family:courier new;"> Agent.__init__(self)</span><br /><span style="font-family:courier new;"> self.agents = []</span><br /><br /><span style="font-family:courier new;"> def exit(self):</span><br /><span style="font-family:courier new;"> # When the player calls the exit, tell all Agents to stop running</span><br /><span style="font-family:courier new;"> for agent in self.agents:</span><br /><span style="font-family:courier new;"> agent.running = False</span><br /><span style="font-family:courier new;"> self.running = False</span><br /><br /><span style="font-family:courier new;"> def action(self):</span><br /><span style="font-family:courier new;"> # Each frame the renderer clears the screen, writes the text and draws each</span><br /><span style="font-family:courier new;"> # registered agent.</span><br /><span style="font-family:courier new;"> screen.clear(psp2d.Color(0,0,0,255))</span><br /><span style="font-family:courier new;"> font.drawText(screen, 10, 225, "Move your character with directional")</span><br /><span style="font-family:courier new;"> font.drawText(screen, 10, 240, "Triangle takes screenshot")</span><br /><span style="font-family:courier new;"> font.drawText(screen, 10, 255, "Press X to exit")</span><br /><span style="font-family:courier new;"> for agent in self.agents:</span><br /><span style="font-family:courier new;"> screen.blit(agent.sprite, 0, 0, agent.sprite.width, agent.sprite.height, agent.posX, agent.posY, True)</span><br /><span style="font-family:courier new;"> screen.swap()</span><br /><br /><br /><span style="font-family:courier new;"># Creates the renderer object</span><br /><span style="font-family:courier new;">rend = render()</span><br /><span style="font-family:courier new;"># Creates a player Agent</span><br /><span style="font-family:courier new;">play = player(rend)</span><br /><span style="font-family:courier new;"># Creates one NPC that runs around the screen</span><br /><span style="font-family:courier new;">NPC1 = NPC(rend)</span><br /><br /><span style="font-family:courier new;"># Starts the game loop</span><br /><span style="font-family:courier new;">stackless.run()</span><br /><br /></span><br /><br /><br /><br /></span></span></span></span>Carlos Eduardohttp://www.blogger.com/profile/00674164975841007118noreply@blogger.com2tag:blogger.com,1999:blog-6035667965789416859.post-31417714696682038772007-06-18T15:07:00.000-03:002007-06-25T10:51:26.504-03:00Stackless Python port for Sony PSPAbout 3 weeks ago, I got a Sony PSP, since only playing games isnt enought for me, I started fiddling around for so called "Homebrew" software for it.<br /><br />The <a href="http://ps2dev.org/">homebrew</a> community for PSP is quite big and mostly around C coding but surprisingly I found that a <a href="http://fraca7.free.fr/blog/index.php">guy named Jerome</a> made <a href="http://fraca7.homeunix.net/trac/">Python-psp, awesome port</a> of Python 2.4.3 and PSP graphic, sound and network API to Python modules.<br /><br />Based on that and my bare knowledge of C, I decided to start working on a <a href="http://www.stackless.com/">Stackless Python</a> port for it.<br /><br />I recently saw the great work from <a href="http://nameless-sorrows.blogspot.com/">Richard Tew</a> in porting <a href="http://nameless-sorrows.blogspot.com/search/label/nintendo%20ds">Stackless to Nintendo DS</a> and decided to give a try. Checked out the 2.4.3 PSP port from python-psp repository and merged the Stackless 2.4.4 tag into it.<br /><br />The first thing to be done, was fixing up some conflicts mostly related to IO and threads. Next Richard pointed me out that the Stackless needs to save and restore stack pointers and this is done in assembly.<br /><br />Based on trial and error, it took me a day to figure out and have a compiled interpreter.<br /><br />To finish it all, I ran the stackless unittests and some Stackless applications from the <a href="http://code.google.com/p/stacklessexamples/">Stackless Examples Project</a> and found that its all working.<br /><br />I hope other people could try it out and maybe find some bugs, probably I will make the source available and the diff patches too.<br /><br />The next thing in my roadmap is porting Python and Stackless Python 2.5.1 to PSP, hope it wont be much trouble.<br /><br />The download is temporarily stored on Stackless Examples project. As soon as I decide to host it or anyone else do, it will be here:<br /><br /><a href="http://stacklessexamples.googlecode.com/files/PSP-Stackless-2.4.4.zip">http://stacklessexamples.googlecode.com/files/PSP-Stackless-2.4.4.zip</a><br /><br />To install just create a folder in your /PSP/GAME150 folder and place the EBOOT.PBP there.<br />The python folder is the libraries and must be placed on your memory stick root.<br /><br />For more information check the Python-psp page.<br /><br />Thanks a lot for Jerome for the amazing work on the Python port and Richard Tew for the Stackless porting!<br /><br />Any questions contact me directly.Carlos Eduardohttp://www.blogger.com/profile/00674164975841007118noreply@blogger.com13tag:blogger.com,1999:blog-6035667965789416859.post-80645418913519150482007-05-22T09:17:00.000-03:002007-06-25T10:51:49.598-03:00Creating C++ modules for pythonIn the last days, i've been committed to learn C++ so I can port performance critical methods in my Python apps to it. I found a great site - <a href="http://www.cplusplus.com/">www.cplusplus.com</a> with a nice tutorial worth a look.<br /><br />I started reading thru a lot of <a href="http://docs.python.org/ext/ext.html">documentation</a> on how to create Python C modules but all those PyObjects and all made a mess in my head.<br /><br />Looking in the <a href="http://www.python-ogre.org/">Python-Ogre</a> (Python bindings for the wonderful <a href="http://www.ogre3d.org/">Ogre3D engine</a>), I found that they use a new code generator for <a href="http://boost.org/libs/python/doc/index.html">boost-python</a> called <a href="http://www.language-binding.net/pyplusplus">Py++</a>.<br /><br />I heard a lot about boost and its qualities so I figured out that this was the best option and with Py++ to create the wrapper files it became easier.<br /><br />The problem was not how to create the wrapper files and generate the modules but and install that bunch of packages and modules on windows was a pain.<br /><br />What you will need:<br /><br />- <a href="http://msdn.microsoft.com/vstudio/express/downloads/">Compiler</a> (I'm using VS2005 Express since its free)<br />- <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=0BAF2B35-C656-4969-ACE8-E4C0C0716ADB&displaylang=en">Platform SDK R2</a> (Windows headers)<br />- <a href="http://www.blogger.com/www.Python.org">Python </a>(Of course...)<br />- 2 eggs ... oops... forget this one<br />- <a href="http://www.boost-consulting.com/products/free">Boost installer for Windows</a> Easier to install, better than compile yourself.<br />- <a href="http://sourceforge.net/project/showfiles.php?group_id=118209&package_id=146545">GCC-XML</a><br />- <a href="https://sourceforge.net/project/showfiles.php?group_id=118209">Pygccxml </a><br /><span style="font-size:85%;"></span><br />The resumed installation procedure is:<br /><br />- Install the compiler and the platform SDK<br />- Configure your compiler to use the 'libs', 'includes' and 'bins' from the SDK<br />- Configure the vcvars32.bat file to add the SDK paths to it so the Compile console finds the headers.<br />- Run the boost installer, it will download the needed packages from a mirror. I installed the base packages and the Python lib.<br />- Unpack and run 'python setup.py install' on GCC-XML. In my case, it have not compiled with VC2005 so I unpacked myself and followed the instructions <a href="http://www.gccxml.org/HTML/Install.html">here</a>. Then I compiled using the generated solution file.<br />- Install the pygccxml package 'python setup.py build install'<br />- Install the py++ package 'python setup.py build install'<br /><br />Thats it for now... in my next post I will post some examples and procedures for generating the C++ modules.Carlos Eduardohttp://www.blogger.com/profile/00674164975841007118noreply@blogger.com4tag:blogger.com,1999:blog-6035667965789416859.post-45687305646026427492007-05-11T15:35:00.000-03:002007-05-11T17:59:54.612-03:00Playing with list comprehensionsReading a post from a Planet PythonBrasil blog today, our friend Rodrigo Cacilhas has proposed some approaches on the Oddwords puzzle where the objective is to invert the odd words in a phrase.<br /><br />The post can be seen here: <a href="http://kodumaro.blogspot.com/2007/05/oddwording.html">http://kodumaro.blogspot.com/2007/05/oddwording.html</a><br /><br />I created a small solution based on list comprehension and the and-or trick. It´s like this:<br /><br /><span style="font-family:courier new;">text= "abc def ghi"<br /><br /></span><span style="font-family:courier new;">print " ".join([(x%2 == 0 and y or y[::-1]) for x,y in enumerate(text.split())])<br /><br /></span>It shows how powerful list comprehensions can be.Carlos Eduardohttp://www.blogger.com/profile/00674164975841007118noreply@blogger.com0tag:blogger.com,1999:blog-6035667965789416859.post-46343080736217122212007-05-11T15:30:00.001-03:002007-05-11T15:30:40.533-03:00New blog...First post, new blog.... well, this will be the place where i will write about programming, tech and discoveries I find around the internet.<br /><br />Keep your eyes here for great content.Carlos Eduardohttp://www.blogger.com/profile/00674164975841007118noreply@blogger.com0