About work, open source and commitment

With this post, I want to take some time to explain my commitment to open source, especially to Symfony and how it is tangled with my everyday work.

What do I do?

I am currently developing for my new startup I founded with two of my associates and friends. We knew each other at engineer school ECE Paris, and were always hungry for entrepreneurship. We worked together for years now, and had some ideas on the way. Some were bad, some were better, and one was genial enough to deserve a real leap into the world of startup creation.

And so we created BestComparator.

BestComparator?

BestComparatorIt is service that helps everyday consumer to choose the best product according to his profile, his urges, and the general quality vs. price value of the products available on the market.

Our ultimate goal is to make the best product recommendation answering this simple sentence: “I am Michel, I am a 23 years old nerd, I need a new Laptop, and most of my time I develop, listen to podcasts and surf on the web.”

We worked really hard, developing the service, creating partnership with price comparison services, and defining exactly how the UX/algorithm would look like. We starting working full time on September 2011. We released an early private preview on October and a public beta on March 2012.

The service is finally online since July 2012 and we already have some nice recommendations and the business is smoothly starting.

This is just a start and many thing could be, and will be, better in the coming months. We also have a heavy roadmap, containing very nice (killer) features, more products, better recommendations, an ecosystem, and some other surprises.

So what do I do in that venture?

BestComparator is a 3 men job. While my associates work on the business and the UX, I spend my time coding the foundations of the service. I am the Data, Architecture, Algorithm, Information System guy. AKA the CTO/Lead developer/Cofounder.

The challenge is quite big. We have to aggregate, consolidate and extract meaning from a gigantic amount of data, from products specifications to our member’s behaviors and desires. Those are coming through various funnel, from our partners, the socials networks, what the users say and don’t say… I needed a solid base with a solid promise.

Three years ago I was already a symfony 1.4 junky. This was with tremendous thrill that I started working with Symfony2 nearly two years ago when the first preview appeared. I saw in Symfony2 a very powerful tool moving at a fast pace, bringing many new core concepts to the PHP world (bundles, annotation, DI…), and gathering a very prolific community. Symfony2 is scalable, fast, flexible and stable. Most of all, it made PHP better with a modern architecture and better practices. Its strength is well known and since we adopted it Drupal, eZ Publish, phpBB and many more followed the way.

As a proof of or commitment you can have a look at the credit page at BestComparator.

As you can see we have a quite exhaustive architecture, composed around Symfony2.1 we are running on Doctrine2.3, ElasticSearch, Behat, Sonata, Assetic, Twig and many more.

I also committed to a community

Of course we started when Symfony2 was young, and in some ways it still is young. Along the way, I was involved in some features of the framework (especially around the translation components), and I pushed into the Sonata project for instance. I also developed some standalone bundles such as the BCCExtraToolsBundle, the BCCCronManagerBundle… which are quite famous now.

Developing such bundles requires time. I love to spend it working on open source projects, especially when it matters to people. Thus, I am very happy today when I can work on BCC Bundles, designed for BestComparator and pushed to the open world.

As a bonus I also develop some C# apps for Windows Phone 7: Gi7 and Readr7. They are open source, and some other might come around the Windows 8 platform.

I try to allocate as much energy that I can, following, debugging and improving these projects. That’s my second commitment.

How about a third commitment

Also I am getting married teaching programming at ECE Paris for a year now. Mostly C and C#, I also have some involvement in some web development and Java courses.

I do it partly because it allow me to earn enough money to pursue my work at BestComparator and mostly because I like to share.

I can also tell you that committing to a hundreds of students is not a so easy commitment and it requires time and patience (and patience too).

Follow up

First of all I enquire to go on BestComparator, things are French for the moment, as long as we need some contracts with local resellers. Here are the common way of getting updates on the venture: twitter, facebook, g+.

You can watch and fork my work on github, and pack your PHP projects on packagist. My windows apps are on the market place.

And if you are interesting in a very prolific and fast growing engineer school (with very talent teachers of course), go have a look on the ECE Paris website.

symfony

Symfony 1.4 vs. sfGuardUserPlugin : understand credentials and permissions

I am currently dealing with a project that has strong requirements on how the user authorizations are given amount the users.
If you are familiar with the symphony 1.4 jobeet tutorial you should have seen first authorizations and then a quick introduction to the sfGuardUserPlugin. Let’s get around that first:
Credentials
They are a nice way to define borders to you application. You can place them on every action very easily by editing the security.yml file of the zone where you are setting your rights.
[yml]
all:
is_secure: false
new:
is_secure: true
credentials: manager
create:
is_secure: true
credentials: manager
[/yml]
Here I simply said that my module is accessible for everyone, except the new and create actions where the user needs to be logged and evermore he need to have the manager credential.
The action workflow checks the needed credentials just before loading the action, and if the user has it, it executes the actions, if not, a 403 page is given. The function of the user that is used is called hasCredential.
The first thing you have to know is that credentials are given to the sf_user, even if he is not logged. This means that thay are session dependent and cannot be persists amount sessions. Given credentials are not mean to be stored in your database.
Permissions
They came with the sfGuarduserPlugin. The plugin gives you the sfGuardSecurityUser, which extends the sf_user and which can be persisted. You can also give to him permissions or groups. Groups can have permissions in such a way that a user automatically gets the permissions of his group.
Moreover, the User, Groups and Permissions can be stored in your database.
[php]
// add a group
$sfGuardSecurityUser->addGroupByName(‘manager’);
// add permission
$sfGuardSecurityUser->addPermissionByName(‘manager’);
// get permissions (direct permissions and also group permissions)
$sfGuardSecurityUser->getAllPermissions();
[/php]
The matter now is that the controller workflow does not use the permissions in order to compare them to the needed credentials for an action.
How to check credentials using the permissions
If we want to combine the nice yaml credential description and the powerful permission system, we need to override the hasCredential method.
The cool thing here is that the instance of the user used in this case is the myUser class defined in your application folder. This way our can override the method in a non-obtrusive manner:
[php]
// /apps/frontend/lib/myUser.class.php
class myUser extends sfGuardSecurityUser {
public function hasCredential($credential, $useAnd = true) {
// combine the credential and the permission check
return (parent::hasCredential($credential, $useAnd) || parent::hasPermission($credential));
}
}
[/php]
Upgrade the 403 page
What I like to do sometimes is to tell the user what credentials he misses. In order to do that, we will need to change the secure function that redirects to the 403 page.
Go to the sfGuardPlugin and look for the sfGuardAuthActions.class.php file :
[php]
// /plugins/sfDoctrineGuardPlugin/modules/sfGuardAuth/actions/actions.class.php
class sfGuardAuthActions extends BasesfGuardAuthActions
{
public function executeSecure($request) {
parent::executeSecure($request);
// retrieve the needed credentials
$this->credentials = $this->getContext()->getActionStack()->getFirstEntry()->getActionInstance()->getCredential();
// make sure the credentials are an array (in case of unique non-array credential)
if(!is_array($this->credentials))
$this->credentials = array($this->credentials);
}
}
[/php]
You noticed here that I use the first controller called in the action stack. You have to do that in order to retrieve credentials of the first action that tried to reach the user. If not, you will only retrieve the credentials of the current controller which does not have any.
You now have the credentials that you can display in your template.
[php]
// /plugins/sfDoctrineGuardPlugin/modules/sfGuardAuth/tempates/secureSuccess.php
You have to meet the following requirements to have access to this action:
<ul>
<?php foreach($credentials as $credential): ?>
<li>
<?php switch ($credential){
case ‘manager':
echo ‘You need to be a manager';
break;
}?>
</li>
<?php endforeach;?>
</ul>
[/php]
And voila, you have now a nice and powerful user authorization management on your symphony website.

symfony

How to use filters on custom fields with symfony 1.4

I recently continued to use my particular relationship that embeds some properties. This time I wanted to add some filters to my student request using the pre-generated filter used in the backend.

Here again, is our example:

N to N relationship with properties

N to N relationship with properties

And the pre-coded filter is here:
[php]
// lib/filter/doctrine/StudentFormFilter.class.php
class StudentFormFilter extends BaseStudentFormFilter
{
public function configure()
{
}
}
[/php]

Here the filter already includes fields for every field on Student objects (id and name). It is a regular form, so you can override the predefined widgets and validator or even unset some of them. Let’s unset the id:

[php]
// lib/filter/doctrine/StudentFormFilter.class.php
class StudentFormFilter extends BaseStudentFormFilter
{
public function configure(){
unset($this[‘id’]);
}
}
[/php]

Now we can use our filter like this in our controller:
[php]
// app/frontend/module/student/actions/actions.class.php
class studentActions extends sfActions {
public function executeIndex(sfWebRequest $request) {
//create a default query
$query = Doctrine::getTable(‘Student’)->getQuery();

//obtain the filter values that could have been submited
$filterValues = $request->getParameter(‘student_filters’);
//create the StudentFormFilter using the values, and giving it the query
$this->formFilter = new StudentFormFilter($filterValues);
$this->formFilter->setQuery($query);
//if the form have been submited
if($filterValues){
//bind the values
$this->formFilter->bind($filterValues);
//if valid, specialise the request using the form
if($this->formFilter->isValid())
$query = $this->formFilter->getQuery();
}

//finally get the students
$this->students = $query->execute();
}
}
[/php]

This code could seem a little weird but it is finally all you need to know in order to make a basic use of the auto generated filters. Thus, your template can look like this:

[php]
<?php echo form_tag(url_for(‘student_index’)) ; ?>
<table>
<?php echo $formFilter ; ?>
</table>
<input type="submit"/>
<?php echo ‘</form>’ ?>
// …
<ul>
<?php foreach($students as $student): ?>
<li><?php echo $student->getName(); ?></li>
<?php endforeach; ?>
</ul>
[/php]

Ok, everything is working quite well. But, let’s getting our filter trickier. I want to add a filter that permits me to select students that have a specific enrolment date.

First of all, we need to add a widget and a validator:
[php]
// lib/filter/doctrine/StudentFormFilter.class.php
class StudentFormFilter extends BaseStudentFormFilter
{
public function configure()
unset($this[‘id’]);

$this->setWidget(‘EnrolmentDate’, new sfWidgetFormFilterDate( array(
‘from_date’ => new sfWidgetFormDate(),
‘to_date’ => new sfWidgetFormDate(),
‘with_empty’ => false)));
$this->setValidator(‘EnrolmentDate’, new sfValidatorDateRange(array(
‘required’ => false,
‘from_date’ => new sfValidatorDateTime(array(
‘required’ => false,
‘datetime_output’ => ‘Y-m-d 00:00:00′)
),
‘to_date’ => new sfValidatorDateTime(array(
‘required’ => false,
‘datetime_output’ => ‘Y-m-d 23:59:59′)))));
}
}
[/php]

Here, our form will display properly, but the getQuery method used in the will simply ignore our new EnrolmentDate field.

Now the things are getting really uncommon. Symfony is not really built for this kind of behavior, and we will need to override some behavior in our StudentFormFilter to get thing to work. In order to do that I read the sfFormFilterDOctrine.class.php file and more specifically the doBuildQuery function where the request is built. Some of the things I’ll do are a bit ugly but it is the price to pay if we want not to spread our modifications into the core framework, thus I managed to keep everything in the StudentFormFilter.class.php file. This way our ugliness remains contained into a single file and does not impact the framework. So let’s go for it!

First of all we need to add the EnrolmentDate as a new field of the form, to do that we need to override the getFields function:
[php]
// lib/filter/doctrine/StudentFormFilter.class.php
class StudentFormFilter extends BaseStudentFormFilter
{
// …

public function getFields() {
return array_merge(parrent::getFields(), array(‘EnrolmentDate’=>’EnrolmentDate’));
}
}
[/php]

The very important thing here is to know that I added a field EnrolmentDate of type EnrolmentDate. It will be crucial later.

Also, the doBuildQuery method will get the Student table and check for the presence of the field EnrolmentDate. The workaround here is to make a stub table and override the getTable function in order to return this stub table.

[php]
// lib/filter/doctrine/StudentFormFilter.class.php
class StudentFormFilter extends BaseStudentFormFilter
{
// …

public function getTable() {
return new StudentStubTable();
}
}

// my stub table
class StudentStubTable extends StudentTable{
public function hasField($field) {
if($field == ‘EnrolmentDate’)
return true;
else
return parent::hasField($field);
}
public function getFieldName($field){
if($field == ‘EnrolmentDate’)
return ‘EnrolmentDate';
else
return parent::getFieldName($field);
}
}
[/php]

As you can see, two methods need to be overridden in my StudentStubTable class. Those two functions are used by the doBuildQuery function. Here i make the field EnrolmentDate exist and create his fieldName in the table is EnrolmentDate.

From here, all we need to know is that the doBuildQuery function will look for an addEnrolmentDateQuery function in our StudentFormFilter class. This function is called based on the type of the fields that I defined earlier in the getFields method. This call is made by the concatenation of ‘add’ + type of the field + ‘Query’.

So, let’s code the function and make it do our join with the Enrolment table.

[php]
// lib/filter/doctrine/StudentFormFilter.class.php
class StudentFormFilter extends BaseStudentFormFilter
{
// …

public function addEnrolmentDateQuery(Doctrine_Query $query, $field, $values) {
//add our join part
$query->leftJoin(sprintf(‘%s.Enrolment enrolment’,$query->getRootAlias()));

//set the where part depending on the value
if (isset($values[‘is_empty’]) && $values[‘is_empty’])
{
$query->addWhere(‘enrolment.EnrolmentDate IS NULL’);
}
else
{
if (null !== $values[‘from’] && null !== $values[‘to’])
{
$query->andWhere(‘enrolment.EnrolmentDate >= ?’, $values[‘from’]);
$query->andWhere(‘enrolment.EnrolmentDate <= ?’, $values[‘to’]);
}
else if (null !== $values[‘from’])
{
$query->andWhere(‘enrolment.EnrolmentDate >= ?’, $values[‘from’]);
}
else if (null !== $values[‘to’])
{
$query->andWhere(‘enrolment.EnrolmentDate <= ?’, $values[‘to’]);
}
}
}
}
[/php]

In this method, we retrieve the query as a parameter and we just have to build our method based on the values we receive. Everything here is about building a proper DQL query.

Now we have a nice filter that can filter on our property embedded into a relationship.

Here is the final code:

[php]
// lib/filter/doctrine/StudentFormFilter.class.php
class StudentFormFilter extends BaseStudentFormFilter
{
public function configure()
unset($this[‘id’]);

$this->setWidget(‘EnrolmentDate’, new sfWidgetFormFilterDate( array(
‘from_date’ => new sfWidgetFormDate(),
‘to_date’ => new sfWidgetFormDate(),
‘with_empty’ => false)));
$this->setValidator(‘EnrolmentDate’, new sfValidatorDateRange(array(
‘required’ => false,
‘from_date’ => new sfValidatorDateTime(array(
‘required’ => false,
‘datetime_output’ => ‘Y-m-d 00:00:00′)
),
‘to_date’ => new sfValidatorDateTime(array(
‘required’ => false,
‘datetime_output’ => ‘Y-m-d 23:59:59′)))));
}

public function addEnrolmentDateQuery(Doctrine_Query $query, $field, $values) {
//add our join part
$query->leftJoin(sprintf(‘%s.Enrolment enrolment’,$query->getRootAlias()));

//set the where part depending on the value
if (isset($values[‘is_empty’]) && $values[‘is_empty’])
{
$query->addWhere(‘enrolment.EnrolmentDate IS NULL’);
}
else
{
if (null !== $values[‘from’] && null !== $values[‘to’])
{
$query->andWhere(‘enrolment.EnrolmentDate >= ?’, $values[‘from’]);
$query->andWhere(‘enrolment.EnrolmentDate <= ?’, $values[‘to’]);
}
else if (null !== $values[‘from’])
{
$query->andWhere(‘enrolment.EnrolmentDate >= ?’, $values[‘from’]);
}
else if (null !== $values[‘to’])
{
$query->andWhere(‘enrolment.EnrolmentDate <= ?’, $values[‘to’]);
}
}
}

public function getFields() {
return array_merge(parrent::getFields(), array(‘EnrolmentDate’=>’EnrolmentDate’));
}

public function getTable() {
return new StudentStubTable();
}
}

// my stub table
class StudentStubTable extends StudentTable{
public function hasField($field) {
if($field == ‘EnrolmentDate’)
return true;
else
return parent::hasField($field);
}
public function getFieldName($field){
if($field == ‘EnrolmentDate’)
return ‘EnrolmentDate';
else
return parent::getFieldName($field);
}
}
[/php]

If you have any remarks about my implementation (I am sure you have) don’t hesitate to tell me about, I think this code can still be improved.

symfony

Add properties to a relationship – Dealing with forms in symfony 1.4

Lately, I showed how you can a simply add properties to a relationship:

Doctrine 1.2: Add properties to a relationship

I continued to use this solution until I recently faced some issue for it. In fact, I discovered what I thought was a weird behavior until I completely understood the full impact of the solution.

Let’s take back our example:

N to N relationship with properties

N to N relationship with properties

I am using it in the symfony Framework, and I want to make a student form that includes also the enrolment properties. To do that, I can just use the embedded relation:

[php]
class StudentForm extends BaseStudentForm {
public function configure() {
$this->embedRelation("Enrolments");
}
}
[/php]

This way, symfony automatically takes care about including the collection of enrolments into my form. And process it after the submission.

You can simply include it in your template:

[php]
$form = new StudentForm();
echo $form;
[/php]

This is working pretty well!

The matter is that I want to customize my form, and thus I template it:

[php]
<form action="./submit" method="post">
<table>
<tbody>
<tr>
<th>Name</th>
<td><?php echo $form[‘name’]->render() ?></td>
</tr>
<?php /* Include the collection of enrolments */ ?>
<?php foreach($form[‘Enrolments’] as $enrolment): ?>
<tr>
<?php echo $enrolment[‘enrolementDate’]->render() ?>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot>
<tr>
<td colspan="2">
<input type="submit" value="Save" />
</td>
</tr>
</tfoot>
</table>
<?php /* Don’t forget hidden fields */ ?>
<?php echo $form->renderHiddenFields() ?>
</form>
[/php]

Now, I have a fully customizable form… but it is not working when submit. Worse, it erases your enrolments!!! If you look into the doctrine log, I can see that you have a DELETE statement that should not be here. And then the update is done on your enrolments, even if they have been deleted.

At first, it is very strange. The reason why, is because when you embedded the enrolment relationship into your form, you also have indirectly embedded the course relationship. This is because the enrolment carries the course relationship. When symfony processes the form, it sees that you have enrolments, but you don’t have the courses that they should be bound to. So, it must be that your removed the course, and thus, the enrolments have no reason to exist anymore.

In order to work around this issue, you simply have to add the course into your form. I just did it with hidden inputs:

[php]
<?php foreach($form->getObject()->getCourses() as $course): ?>
<input type="hidden"
name="student[courses_list][]"
value="<?php echo $course->getid() ?>">
<?php endforeach; ?>
[/php]

Now, when symfony processes the form, it finds the courses ids and keeps the relationship intact.

You now have a good working form!

symfony

Adding actions to an auto generated admin in symfony 1.4

I know this functionality is nicely described in the symfony jobeet tutorial, but recalling this particular point emphasis the fact that symfony is definitely a good out of the box tool to easily generate powerful admin that should normally be very painful to code by hand.

In my example I will generate an admin for a system that deals with TV shows. The particular admin screen that I will customize is the TV Show list screen, in order to add it the “add season” action.
The “add season” action will simply add a season to my TV Show by retrieving the last season and increment the number and the year of the season.

Here is the UML for the TV Shows and the seasons:

UML of the tv show example

UML of the tv show example

We will first add the buttons to the admin interface, in order to do that I’ll just go to the generator.yml file and add the following lines:

[yml]
# /apps/backend/module/tvshow/config/generator.yml

generator:
class: sfDoctrineGenerator
param:
model_class: Tvshow
theme: admin
non_verbose_templates: true
with_show: false
singular: ~
plural: ~
route_prefix: tvshow
with_doctrine_route: true
actions_base_class: sfActions

config:
actions: ~
fields: ~
# customization of the list screen
list:
# header of the <table/>
display: [=Name]
# actions that will be in the combo box
batch_actions:
addSeason: ~
# actions that will be in the <table/>
object_actions:
addSeason: ~
_edit: ~
_delete: ~
filter: ~
form: ~
edit: ~
new: ~
[/yml]

You can note that the auto generated actions start with “_”, such as “_edit” and “_delete”. Moreover, the new “addSeason” action is automatically inserted in the screen and the routes and form submission are already working. You should obtain this:

Customized admin

Customized admin

Now we just need to code the actions that correspond to the route. Everything happens in the actions.calss.php dedicated to the tvshow generated module:

[php]
<?php

// /apps/backend/module/tvshow/actions/actions.class.php

require_once dirname(__FILE__).’/../lib/serieGeneratorConfiguration.class.php';
require_once dirname(__FILE__).’/../lib/serieGeneratorHelper.class.php';

class tvshowActions extends autoTvshowActions
{
/*
* Action executed when excecuting "addSeason" via the combo box
*/
public function executeBatchAddSeason(sfWebRequest $request)
{
// retrieving the ids correspondig to the checked boxes
$ids = $request->getParameter(‘ids’);

// query to retrieve the items via Doctrine
$q = Doctrine_Query::create()
->from(‘Tvshow t’)
->whereIn(‘t.id’, $ids);

// performing the addSeason on each TV show
foreach ($q->execute() as $tvshow)
$tvshow->addSeason();

// always inform the user
$this->getUser()->setFlash(‘notice’, ‘The selected TV Shows have been extended successfully.’);

// redirect to the auto generated module
$this->redirect(‘tvshow’);
}

/*
* Action executed when excecuting "addSeason" via the list directly
*/
public function executeListAddSeason(sfWebRequest $request)
{
// retrieving the tv show
$tvshow = $this->getRoute()->getObject();

// perform the addSeason
$tvshow->addSeason();

// always inform the user
$this->getUser()->setFlash(‘notice’, ‘The selected tv show have been extended successfully.’);

// redirect to the auto generated module
$this->redirect(‘tvshow’);
}
}
[/php]

Here we just miss the addSeason function:

[php]
<?php
// /lib/model/doctine/Tvshow.class.php

class Tvshow extends BaseTvshow {

/*
* Add a season the the TV show
*/
public function addSeason(){
// retrieve the last season via Doctrine
$last = Doctrine::getTable(‘Season’)
->createQuery()
->where(‘tvshowId=?’, $this->getId())
->orderBy(‘number DESC’)
->fetchOne();

// create the new one
$season = new Season();
$season->setTvshowId($this->getId());
$season->setYear($last->getYear() + 1);
$season->setNumber($last->getNumber() + 1);
$season->setNumberOfEpisodes($last->getNumberOfEpisodes());

// save it
$season->save();
}
}
[/php]

And everything is set. We now have a perfectly working new action included in our auto generated admin. This showing how symfony is highly customizable despite great functionalities in auto generated code.

About me…

As you know, I am a student in ECE Paris. It is an engineer school with a 5 year program. I am going through the last year and I took a specialization in software development and security. My courses also contain some management, software design, user experience, marketing and other useful skills.

I also enjoyed traveling during my studies. I went for a full semester in Canada where I discovered new techniques and way to approach management and software development issues. Also I am currently packing for a seminar in California which will last for a month.

About my skills, I developed a lot for web applications with two main platforms. I have a personal big project on a community web site which I am developing with some friends of mine. It is based on the symphony framework with the Doctrine ORM. I was already familiar with web development in php but this framework made me go on a whole new scale. I took advantage of this project to put into practice Extreme Programming which was a really good experience, not easy at all but definitely interesting.

Also, I am currently finishing an internship that I voluntary spend on a complete different technology: .NET. At the beginning I wasn’t used to the Microsoft platform but I learned and I finally took part in the development as regular member of the team. We are developing a fully configurable web application designed for HR services that should fit the need of many customers. It is a very complex project based on several key technologies of the .NET framework such as asp.mvc, entity framework and unity. The architecture that we are developing also challenges major issues of nowadays developments. Again another agile methodology, we are practicing scrum.

In my personal life I also enjoy playing the guitar, movies, and reading. Well, I just don’t like getting bored.

Welcome to my new blog !

Hi, welcome to my new blog!

Until recently I kept developing my own website based on the symphony framework but I realized that I didn’t have enough time to make it as good as I wanted. Also, with my current internship over the .NET framework and my personal big project on symphony I was really starting to become schizophrenic.

I was considering starting a real pro-blogging activity thus I decided to switch to a real tool: WordPress. Less time loosing reinventing the wheel, more time to share my experience. Some of you might notice that my old work is still available at perso.michelsalib.com.

With this blog, I intend to share on various subjects over several technologies. Symfony, of course, Doctrine, jQuery, but also Microsoft technologies such as asp.mvc, entity, and I hope Silverlight and WM7 development…

Yea, I am schizophrenic!