eXcetra http://dev.saranyan.com code, dev stuff, hacking, design, etc posterous.com Sat, 12 May 2012 21:12:00 -0700 Cross domain API calls using Sinatra + pmxdr http://dev.saranyan.com/cross-domain-api-calls-using-sinatra-pmxdr http://dev.saranyan.com/cross-domain-api-calls-using-sinatra-pmxdr

You have an API server running and want to enable people to make cross domain XHR requests using javascript. How do you do that? There are bunch of methods that exist. I will present a technique to achieve this using HTML5's awesome postMessage API. I used pmxdr library, which is a pure javascript library that leverages HTML5's postMessage functionality without needing Flash or anything of that sort. Very neat!

Some setup details -

  1. My remote server is running on mylocal.name:9393 (mylocal.name -> localhosts in the /etc/hosts file). This server provides a POST operation on /api/token and returns a JSON object on a successful POST operation.
  2. My client is running on localhost:9494. It will make a cross domain request for the JSON token data from the remote server.
  3. Both my servers are powered by Sinatra.

Server settings

There are two things the server has to do before anything else.

  1. Have a valid route /pmxdr/api which loads the pmxdr-host.js file from the library. We need to add the approved domains to this file, but more on this later.
    get '/pmxdr/api' do
      p "got a get on pmxdr/api"
      erb :pmxdr
    end
    The view pmxdr.erb just loads the pmxdr-hosts.js file.
  2. The server must allow cross domain through X-Frame-Options header. For Sinatra, which automatically addes X-Frame-Options header, you can configure it by
  3. #x-frame-options allow sinatra
    configure do
      set :protection, :except => :frame_options
    end

These two things will get us started on the server side. The API token call is show here to give a context. 

post '/api/token' do
  p "post operation"
  content_type :json
    { :token => '9238928fkjkjkdjfser'}.to_json
end

In the pmxdr-hosts.js (which is rendered by pmxdr view in this example), allow localhost with any port to access its resources.

var alwaysTrustedOrigins = [ 

   /^[\w-]+:(?:\/\/)?(?:[\w\.-]+\.)?localhost\:\d+(?::\d+)?$/ // any origin on any protocol that has a domain that ends in localhost:anyport
  
    
  ];

If you don't do this, the logs in the server will show a POST operation, but pmxdr host will not return the data and give a disallowed-origin error.

{pmxdr: true, error: "DISALLOWED_ORIGIN", id:"123", status:200, statusText:"OK"}

Making API calls through Client

In this example, when you navigate to the client, an API call is made and the token is returned.

Load the pmxdr client code - <script src="pmxdr-client.js" type="text/javascript"></script>

The actual client side code is very simple.

var pmxdrInterface = new pmxdr("http://mylocal.name:9393/");
pmxdrInterface. function() {
    this.request([{
        method  : "post",
        uri     : "/api/token",
        data    : "",
        callback: handleResponse,
        headers : {},
        timeout : 30000 /* == 30 seconds*/
    }]);
 
}
function handleResponse(response) {
          //alert(response.data);
    // do stuff with response
                console.log(response);
                var code;
                codeContainer = document.createElement("pre");
                if ( !response.error ) {
         code += "\n\ndata:\n"+response.data;
       } else code += (errorIsGood? "(PASS) " : "(FAIL) ")+"Error: "+response.error;
       
       //codeContainer.appendChild(document.createTextNode(code));
       results.appendChild(document.createTextNode(code));
       //results.appendChild(document.createElement("hr"));
                //
    pmxdrInterface.unload();
}
pmxdrInterface.init();

This is what happens in the above code -

  1. When pmxdr is initialized, a temporary iFrame is setup, that has a source of http://mylocal.name:9393/pmxdr/api. Remember - When we were setting up the server, we made sure that the API end point was "gettable" and it loaded the host library code.
  2. After the iFrame is intialized, it sends a GET request with a uri parameter is http://mylocal.name:9393/api/token and a randomly generated id.
  3. After this request, the pmxdr host checks if the requesting window (in this case localhost:9494) is allowed to view the data. Remember - the entry we added to the hosts.js file.
  4. A temporary iFrame, which is setup gets deleted after a successful response or the timeout that is specified in the above code.

The great thing is that you can send any kind of custom headers that your API call should respond to (for authentication or anything like that).

You can download the entire code from my git repo https://github.com/saranyan/pmxdr-sinatra

 

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1414446/C360_2011-08-20_12-10-28.jpg http://posterous.com/users/5AqlNVDQseaZ Saranyan Vigraham saranyan Saranyan Vigraham
Thu, 05 Apr 2012 11:53:00 -0700 Cloudfoundry, X.commerce, Ruby http://dev.saranyan.com/cloudfoundry-xcommerce-ruby http://dev.saranyan.com/cloudfoundry-xcommerce-ruby

I am right now at the awesome CloudFoundry open tour (Austin). I am hearing @ciberch talk about how one can use CloudFoundry to deploy ruby application, I decided to hack on something of my own. My first ruby/sinatra application using X.commerce platform and CloudFoundry.

In the last post, I posted an example in ruby about how two capabilities can compute a Fibonacci sequence between themselves. Recap - user initiates the computation by vising a url/ping, the capability computes the next number in the sequence and sends a message on /message/ping which gets handled by the other guy. He sends a message back with the next sequence on /message/pong. This goes on until 10 numbers in the sequence are computed after which the application terminates.

This is what I did to change my old code - The new code is found here

  1. Moved the client1 and client2 into different folders and created a Gemfile so that they can use Bundler instead.
  2. Changed my endpoints in X.commerce devportal (fibclient1-x.cloudfoundry.com, fibclient2-x.cloudfoundry.com)
  3. Pushed my apps to cloudfoundry. (Assuming you have setup your account already. more details here. create an account. Install the awesome vmc command line tool.)

There it is. My app works on CloudFoundry.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
vmc logs fibclient1-x

---

No RabbitMQ service bound to app. Skipping auto-reconfiguration.

Ping received on /message/ping
-----
Fibonacci sequence
---------
0,1


Ping received on /message/ping
-----
Fibonacci sequence
---------
0,1,1,2


Ping received on /message/ping
-----
Fibonacci sequence
---------
0,1,1,2,3,5


Ping received on /message/ping
-----
Fibonacci sequence
---------
0,1,1,2,3,5,8,13


Ping received on /message/ping
-----
Fibonacci sequence
---------
0,1,1,2,3,5,8,13,21,34

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1414446/C360_2011-08-20_12-10-28.jpg http://posterous.com/users/5AqlNVDQseaZ Saranyan Vigraham saranyan Saranyan Vigraham
Mon, 02 Apr 2012 11:57:00 -0700 Fibonacci over Fabric http://dev.saranyan.com/fibonacci-over-fabric http://dev.saranyan.com/fibonacci-over-fabric

Today, I wrote the most complicated Fibonacci algorithm I have ever written. It reminds of the episode from "The Big Bang Theory", where Howard controls a light bulb in the room by routing the instructions over cables and satellites and back. (Check it out, very neat sequence http://www.youtube.com/watch?v=BW9FbjjkKo4). This is definitely not that complex and definitely has a strong use case in terms of conveying how to communicate with the X.commerce Fabric.

A refresher - An X.commerce capability is something that solves a commerce need. In simple terms, it can be visualized as an application that communicates with the X.commerce Fabric. While applications are generally limited to helping users perform some tasks, a capability can accomplish more in terms of helping businesses execute complex commerce operations. For instance, a capability might help a store front with order processing, inventory management, or even analytics. Unlike applications that usually communicate only with its end users, a capability can interact with other capabilities to accomplish its objectives.

In this example, we are going to rely on two capabilities to compute the Fibonacci sequence together. The computation begins with an intial sequence by GETting a URL /ping from capability 2. This in turn POSTs on /message/ping with a destination ID of the capability 1. Capability 1, which is already subscribed to the topic deserializes the message, computes the next number in the sequence and POSTs on /message/pong back on the Fabric with the destination ID as the original publisher ID. The pong action sends a message back on ping and this goes on. This example illustrates some great concepts about the X.commerce Fabric.

  • Communication is asynchronous. 
  • There should be a relationship (tenancy relationship) between a publisher and a listener. Though a listener is subscribed to receive on a topic, he will not get the message posted by the publisher on that topic unless the publisher is authorized to send messages to the listener.
  • If a capability wants the messages to be restricted/directed to one listener, they should specify the destination ID header (X-XC-DESTINATION-ID).
  • A receiving capability can respond just to the publishing capability by getting the destination ID from the incoming header X-XC-PUBLISHER (this will change in upcoming versions to X-XC-PUBLISHER-PSEUDONYM)

I created two capabilties in Ruby. The general flow and authorization follows the flow diagram provided below. Check out this link on how to build capabilities using the sandbox.

Fibonacci_flow

Here are some quick steps to get your capabilities configured correctly using the sandbox -

  • The sandbox end point is {https://api.sandbox.x.com/fabric}. 
  • Create a test merchant and make sure both your capabilities have authroized the same test merchant (this ensures that both the capabilities have a tenancy relationship with each other).
  • Use the tenant specific token as the authroization header when publishing to the fabric.
  • Use the fabric credentials to compare against the authorization header of an incoming message from the Fabric.

Fabric_snapshot

The code works as shown in the following diagram. 

Drawing1

With every ping pong message that gets sent to the Fabric, the respective capabilities add the next number of the Fibonacci sequence to the payload.

You can download the entire code for this sample from the X.commerce git repo.

 

 

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1414446/C360_2011-08-20_12-10-28.jpg http://posterous.com/users/5AqlNVDQseaZ Saranyan Vigraham saranyan Saranyan Vigraham
Wed, 14 Mar 2012 09:02:00 -0700 A rails bundle for testing X.commerce capability http://dev.saranyan.com/a-rails-bundle-for-testing-xcommerce-capabili http://dev.saranyan.com/a-rails-bundle-for-testing-xcommerce-capabili

Using Rails 3.2 and Twitter bootstrap, I created a Ruby on Rails bundle that one can use to get started with X.commerce fabric. Using this bundle

  • you can send and receive messages to the Xfabric sandbox
  • you can create sample messages automatically for any valid schema hosted on the x.commerce cloud.

The entire code can be downloaded from github. The demo can be found at http://quiet-sword-2317.herokuapp.com/. Some steps you can follow to quickly get started using this bundle -

  • Clone the repository
  • Do a heroku create --stack cedar to create a heroku repo on the cedar stack
  • Go to https://devportal.x.com/ and register a new capability
  • Use the heroku application url as the end point
  • Register for an experimental topic /experimental/rails_bundle/test, which is the default topic that the message console uses. You can actually register any custom experimental topic.
  • Make sure your capability is subscribed to receive on that experimental topic you create.
  • Register a tenant and authorize your capability to send messages on behalf of that tenant. Copy the bearer token.
  • Now, you can use the bearer token and experimental topic in the message console to send and receive messages to the fabric. 

If you have any questions on using this, shoot a tweet @saranyan

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1414446/C360_2011-08-20_12-10-28.jpg http://posterous.com/users/5AqlNVDQseaZ Saranyan Vigraham saranyan Saranyan Vigraham
Wed, 07 Mar 2012 11:19:38 -0800 magento extension to publish product data to x.commerce capability http://dev.saranyan.com/108837673 http://dev.saranyan.com/108837673

In my continuing exploration of Magento, this is what I attempted - "Add a menu item in the admin dashboard, which when clicked, publishes the store product catalog to a X.commerce capability".

The goal was to understand what it takes to build this flow and roughly the things I learned from this exercise was the general structure of Magento folders to write custom extensions, and how to publish it to a X.commerce capability. As a refresher, X.commerce is the new open commerce platform pioneered by eBay. A capability is central to X.commerce technology, and in general, is anything technology or service that solves a commerce problem. A great overview is here

In a nutshell, a capability receives messages posted on a "topic" it is subscribed to. When it receives a message, it validates the schema using Avro contracts. I have written in detail about this in a previous blog post. In this blog post, we make use of all these numbing details, to publish a Magento catalog to a X.commerce topic (/cse/offers/create). The entire code can be downloaded from https://github.com/xcommerce/Sample-capabilities.

The first step was setting up the config files and folder structure (for extension). My folder structure looks like the following.

Screen_shot_2012-03-07_at_10

As you can see, the module name is Xcommerce_Cse. Under app/etc/modules I have created Xcommerce_All.xml file, which defines the Xcommerce module.

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0"?>
<config>
<modules>
   <Xcommerce_Cse>
      <active>true</active>
      <codePool>local</codePool>
      <version>0.1.0</version>
   </Xcommerce_Cse>
</modules>
</config>

In Magento, config file plays a big part. The config files related to the extension we are defining contains all the details about blocks, helpers, events, etc. I created a sample config file like shown below, that can be extended to add more stuff -

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<?xml version="1.0"?>
<config>
<modules>
<Xcommerce_Cse>
<version>0.1.0</version>
</Xcommerce_Cse>
</modules>

<global>
<models>
<Xcommerce_Cse>
<class>Xcommerce_Cse_Model</class>
</Xcommerce_Cse>

</models>

<blocks>
<cse>
<class>Xcommerce_Cse_Block</class>
</cse>
</blocks>

<helpers>
<cse><class>Xcommerce_Cse_Helper</class></cse>
</helpers>

<events>
<catalog_product_save_after>
<observers>
<Xcommerce_Cse_observer>
<class>xcommerce_cse/observer</class>
<method>saveInventoryData</method>
</Xcommerce_Cse_observer>
</observers>
</catalog_product_save_after>
</events>

</global>

<adminhtml>
<menu>
<cse translate="title" module="cse">
<title>Xcommerce</title>
<sort_order>100</sort_order>

<children>
<newchildmenu translate="title">
<title>Send store data to CSE</title>
<action>cse/admin</action>
</newchildmenu>
</children>
</cse>
</menu>
</adminhtml>

<frontend>
<routers>
<Xcommerce_Cse>
<use>standard</use>
<args>
<module>Xcommerce_Cse</module>
<frontName>cse</frontName>
</args>
</Xcommerce_Cse>
</routers>
</frontend>

</config>

The intention is to add a menu item it the dashboard. That part of the declaration can be seen in the config file under adminhtml/menu. When the user clicks this menu item, it should trigger an action that publishes the products from the catalog.

1
2
3
4
5
6
7
8
9
10
11
<?php
class Xcommerce_Cse_AdminController extends Mage_Adminhtml_Controller_Action
{
    public function indexAction()
           {
        $this->loadLayout()
        ->_addContent($this->getLayout()->createBlock('cse/listProducts'))
        ->renderLayout();
           }

}

This triggers the code in Block/ListProducts.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php

class Xcommerce_Cse_Block_ListProducts extends Mage_Core_Block_Template
{
protected function _toHtml()
{
$message = Mage::helper('cse/data')->generateAvroCseMessage();
// Initialize a cURL session
$ch = curl_init();
try {
// Set the cURL options for this session (Change the URL)
curl_setopt($ch, CURLOPT_URL, "https://localhost:8080/cse/offers/create"); // URL of the target resource. This URL is the host:port of the Fabric, with the topic appended
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // stop cURL from verifying the peer's certificate when the https protocol is used
curl_setopt($ch, CURLOPT_HEADER, true); // TRUE to include the header in the output
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // TRUE to return the transfer as a string of the return value of curl_exec() instead of outputting it out directly.
curl_setopt($ch, CURLOPT_TIMEOUT, 10); // maximum number of seconds to allow cURL functions to execute
curl_setopt($ch, CURLOPT_POST, true); // TRUE to do a regular HTTP POST. This POST is the normal application/x-www-form-urlencoded kind, most commonly used by HTML forms.
                //update the bearer token
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: avro/binary", "Authorization: Bearer YOUR TOKEN HERE","X-XC-SCHEMA-VERSION: 1.0.0", "X-XC-SCHEMA-URI: http://localhost/fabric_post/contracts/cse.avpr")); // An array of HTTP header fields to set, in the format array('Content-type: text/plain', 'Content-length: 100')

// Add the binary-encoded, serialized CSE message to the HTTP message as the message body
curl_setopt($ch, CURLOPT_POSTFIELDS, $message); // The full data to post in an HTTP "POST" operation.

// POST the HTTP request to the Fabric and print the response returned by the Fabric
$response = curl_exec($ch);
echo $response;
}
catch (Exception $e) {
echo "Error POSTing message to Fabric!";
echo "Exception object:" . $e;
} // end - try block
return "Done!";
}


}

This code does the following things -

  1. Calls the helper function that encodes the list of products from the store in Avro binary.
  2. Posts to the X.commerce Fabric.

The helper function Helper/Data.php is shown below. Please include the avro php lib files into Magento's lib folder -

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<?php
include_once 'avro.php';
class Xcommerce_Cse_Helper_Data extends Mage_Core_Helper_Abstract
{
public function generateAvroCseMessage() {
$collection = Mage::getModel('catalog/product')
->getCollection()
->addAttributeToSelect('*');
$cse_product_details = array();
foreach ($collection as $p) {
//Convert the product details into the schema supported by the contract.
                        //for convenience, I am using dummy values for the fields that are not
                        //not part of the attributes. Ideally, one can create an attribute set with
                        //new attributes and use that here.
$cse_product_detail = array(
"sku" => $p->getSku(),
"title" => $p->getName(),
"description" => $p->getDescription(),
"manufacturer" => "NA",
"MPN" => "NA",
"GTIN" => "NA",
"brand" => "NA",
"category" => "NA",
"images" => array(),//$product["images"],
"link" => $p->getUrlPath(),
"condition"=>"New",
"salePrice" => array("amount" => floatval($p->getPrice()), "code" =>"USD"),
"originalPrice" => array("amount" => floatval($p->getPrice()), "code" =>"USD"),
"availability" => "InStock",
"taxRate" =>array("country" => "US", "region" => "TX", "rate"=> 8.5, "taxShipping" => false),
"shipping" => array("country" => "US", "region" => "TX", "service" => "UPS", "price" => array("amount" => 3.99, "code" =>"USD")),
"shippingWeight" => floatval($p->getWeight()),
"attributes" => array(),
"variations" => array(),
"offerId" => "NA",
"cpc" => array("amount" => 0.0, "code" =>"USD"));

// Push the product info for the current product into the the $cse_product_details array
array_push($cse_product_details, $cse_product_detail);
//Mage::log($cse_product_details);
}
$content = file_get_contents("http://workshop.dev/fabric_post/contracts/cse.avpr");
if ($content == false) {
echo "Error reading schema!\n";
}

// Parse the CSE Avro schema and place results in an AvroSchema object
$schema = AvroSchema::parse($content);

// Create an AvroIODataWriter object for the supplied AvroSchema.
// An AvroIODataWriter object handles schema-specific writing of data to the encoder and
// ensures that each datum written is consistent with the writer's schema.
$datum_writer = new AvroIODatumWriter($schema);

// Create an AvroStringIO object - this is an AvroIO wrapper for string I/O
$write_io = new AvroStringIO();

// Create an AvroIOBinaryEncoder object.
// This object encodes and writes Avro data to the supplied AvroIO object using Avro binary encoding.
$encoder = new AvroIOBinaryEncoder($write_io);

// The result is stored in the AvroStringIO object $write_io created above
$message = array("products" => $cse_product_details, "productFeedType" => "Full");

$datum_writer->write($message, $encoder);
Mage::log($message);
return $write_io->string();
}
}

Screen_shot_2012-03-07_at_1

This publishes the product feed to the X.commerce fabric on the topic /cse/offers/create.

Screen_shot_2012-03-07_at_1

 

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1414446/C360_2011-08-20_12-10-28.jpg http://posterous.com/users/5AqlNVDQseaZ Saranyan Vigraham saranyan Saranyan Vigraham
Wed, 07 Mar 2012 06:31:00 -0800 Using Ruby Instapaper Gem http://dev.saranyan.com/using-ruby-instapaper-gem http://dev.saranyan.com/using-ruby-instapaper-gem

https://github.com/spagalloco/instapaper is a decent instapaper gem for Ruby. The error handling can be better. If you are using this gem, this is what you need to do -

  1. From the README.md, it looks like, one needs to get an access token first through xAuth, by using Instapaper.access_token(username, password)
  2. Once you get the token, you should be able to configure the settings. 

 

Instapaper.configure do |config|
  config.consumer_key = YOUR_CONSUMER_KEY
  config.consumer_secret = YOUR_CONSUMER_SECRET
  config.oauth_token = YOUR_OAUTH_TOKEN
  config.oauth_token_secret = YOUR_OAUTH_TOKEN_SECRET
end

This does not work exactly this way, as instapaper expects a consumer key with the xAuth request. When I inspected the params, I saw that Consumer Key was not being sent. This makes sense, but the above code is slightly counter intuitive. You can get this working by setting a partial config before sending the access_token request.

Instapaper.configure do |config|
  config.consumer_key = YOUR_CONSUMER_KEY
  config.consumer_secret = YOUR_CONSUMER_SECRET
end

Now,  Instapaper.access_token(username, password) will work.

The challenge I was having was that, the error was not being caught properly in the gem, it was throwing a Hash argumenterror, which didn't make any sense, unless I started looking at the response body. I will probably update the gem and submit a pull request. But, it is an useful gem.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1414446/C360_2011-08-20_12-10-28.jpg http://posterous.com/users/5AqlNVDQseaZ Saranyan Vigraham saranyan Saranyan Vigraham
Tue, 06 Mar 2012 15:50:00 -0800 Magento Product Catalog data from GPS http://dev.saranyan.com/magento-product-catalog-data-from-gps http://dev.saranyan.com/magento-product-catalog-data-from-gps

Magento is interesting! As I dig deeper, I am more intrigued by its power, ambiguity and just the community around it. This is my first week into exploring Magento in depth and I already had to do some automation to get a fairly decent product catalog in place. 

I came across a blog post on creating products programmatically which was nice. I extended that script to pull data from Google shopping API and automatically populate my store running on localhost. 

Feel free to use the code. By the way, is there any thing that automatically sets my store with fake data? A plugin or something...? If there is an easy way, I want to hear about it.

Remeber to use your own Google API key and Magento installation locations before running the code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<?php
//Based and modified from
//http://www.idriss.us/web-development/php/programmatically-creating-products-magento-14x/


// This function gets product information from the Google product search site using the supplied API key and query string
function getGoogleProducts($apikey, $query)
{
    // model URL - https://www.googleapis.com/shopping/search/v1/public/products/?key=KEY&q=QUERY&country=US
$url = "https://www.googleapis.com/shopping/search/v1/public/products/?key=".$apikey."&q=".$query."&country=US";

// Initialize a cURL session
$ch = curl_init();

// Set cURL transfer options
curl_setopt($ch, CURLOPT_URL, $url); // URL of the target resource. This URL is the host of the Google product search API + a query string
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // TRUE to return the transfer as a string of the return value of curl_exec() instead of outputting it directly.
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // stop cURL from verifying the peer's certificate when the https protocol is used

    // If the request is successful, the returned product information is saved in $json.
$json = curl_exec($ch);
curl_close($ch);
$data = json_decode($json, true);
return $data["items"];
} // end - getGoogleProducts


// First we load Magento. This applies to loading magento if you are not going to be making some sort of extension/module to accomplish this for you.
require_once('/Library/WebServer/Documents/mage2/app/Mage.php');
umask(0);

// Set an Admin Session
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
Mage::getSingleton('core/session', array('name'=>'adminhtml'));
$userModel = Mage::getModel('admin/user');
$userModel->setUserId(1);
$session = Mage::getSingleton('admin/session');
$session->setUser($userModel);
$session->setAcl(Mage::getResourceModel('admin/acl')->loadAcl());

//put your API key here
$testGoogleAPIKey = "PUT YOUR KEY HERE";

// Get a product list from the Google Products server
$product_array = getGoogleProducts($testGoogleAPIKey, "droid");

foreach ($product_array as $item) {

$inventory_item = array_shift($item["product"]["inventories"]);
$price = $inventory_item["price"];

// Then we see if the product exists already, by SKU since that is unique to each product
$product = Mage::getModel('catalog/product')
->loadByAttribute('sku',$_product['sku']);
//print_r($item["product"]);
if(!$product){

$product = new Mage_Catalog_Model_Product();

$product->setTypeId('simple');
$product->setWeight(1.0000);
$product->setVisibility(Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH);
$product->setStatus(1);
$product->setSku($item["product"]["googleId"]);

$product->setStockData(array(
'is_in_stock' => 1,
'qty' => 99999,
'manage_stock' => 0,
));
$product->setAttributeSetId(4); // the product attribute set to use
$product->setName($item["product"]["title"]);

$product->setDescription($item["product"]['description']);
$product->setShortDescription(substr($item["product"]['description'], 0, 100));
$product->setPrice($price);

// set the rest of the product information here that can be set on either new/update
//$product->setCategoryIds(array(0,1,2,3)); // array of categories it will relate to
//$product->setTaxClassId(0);
//$product->setWebsiteIDs(array(0)); // your website ids
//$product->setStoreIDs(array(0)); // your store ids

// set the product images as such
//$image = '/Library/WebServer/Documents/mage2/media/import/test.jpg';

//$product->setMediaGallery (array('images'=>array (), 'values'=>array ()));
//$product->addImageToMediaGallery ($image, array ('image'), false, false);
//$product->addImageToMediaGallery ($image, array ('small_image'), false, false);
//$product->addImageToMediaGallery ($image, array ('thumbnail'), false, false);

// setting custom attributes. for example for a custom attribute called special_attribute
// special_attribute will be used on all examples below for the various attribute types
//$product->setSpecialAttribute('xyz');

// setting a Yes/No Attribute
//$product->setSpecialField(1);

// setting a Selection Attribute
//$product->setSpecialAttribute($idOfAttributeOption); //specify the ID of the attribute option, eg you creteated an option called Blue in special_attribute it was assigned an ID of some number. Use that number.

// setting a Mutli-Selection Attribute
//$data['special_attribute'] = '101 , 102 , 103'; // coma separated string of option IDs. As ID , ID (mind the spaces before and after coma, it worked for me like that)
//$product->setData($data);

try{
$product->save();

} catch(Exception $e){
echo $e->getMessage();
//handle your error
}
}


}

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1414446/C360_2011-08-20_12-10-28.jpg http://posterous.com/users/5AqlNVDQseaZ Saranyan Vigraham saranyan Saranyan Vigraham
Thu, 01 Mar 2012 09:51:00 -0800 mcrypt extension on snow leopard (php 5.3.8) http://dev.saranyan.com/mcrypt-extension-on-snow-leopard-php-538 http://dev.saranyan.com/mcrypt-extension-on-snow-leopard-php-538

Modified from this article http://michaelgracie.com/2009/09/23/plugging-mcrypt-into-php-on-mac-os-x-snow...

  1. Download libmcrypt ( http://sourceforge.net/projects/mcrypt/files/)
  2. Compile mcrypt. Unpack the archive and execute  MACOSX_DEPLOYMENT_TARGET=10.6 CFLAGS='-O3 -fno-common -arch i386 -arch x86_64' LDFLAGS='-O3 -arch i386 -arch x86_64' CXXFLAGS='-O3 -fno-common -arch i386 -arch x86_64' ./configure --disable-dependency-tracking
  3. make -j6; sudo make install
  4. Download PHP 5.3.6 (This is not a typo. You need to download the source for 5.3.6) from http://us.php.net/get/php-5.3.6.tar.bz2/from/a/mirror
  5. goto ext/mcrypt directory and execute /usr/bin/phpize
  6. Execute  MACOSX_DEPLOYMENT_TARGET=10.6 CFLAGS='-O3 -fno-common -arch i386 -arch x86_64' LDFLAGS='-O3 -arch i386 -arch x86_64' CXXFLAGS='-O3 -fno-common -arch i386 -arch x86_64' ./configure --with-php-config=/Developer/SDKs/MacOSX10.6.sdk/usr/bin/php-config
  7. make -j6; sudo make install
  8. Add the extension to the php.ini file (typically located /etc/php.ini)
  9. Restart apache (sudo /usr/sbin/apachectl restart)

 

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1414446/C360_2011-08-20_12-10-28.jpg http://posterous.com/users/5AqlNVDQseaZ Saranyan Vigraham saranyan Saranyan Vigraham
Tue, 07 Feb 2012 11:08:00 -0800 Sending and Receiving messages to the X.commerce Fabric http://dev.saranyan.com/sending-and-receiving-messages-to-the-xcommer http://dev.saranyan.com/sending-and-receiving-messages-to-the-xcommer

The post first appeared on x.com. https://www.x.com/developers/community/blogs/saranyan/sending-and-receiving-messages-fabric

Publishing/Sending

The X.commerce fabric expects capabilities to communicate via Avro binary messages. Avro is a data serialization system that relies on schemas. When Avro data is read, the schema used for writing should be available. It can be sometimes part of the message payload itself. However, in the case of X.commerce, the schema is not part of the message payload, but is made available through a reference URI. This is a conscious design decision that provides some significant advantages, few of which are listed below -

  • Better support for handling JSON and other formats that do not have an embedded schema.
  • Smaller message payloads and an ability to cache the schemas, thereby improving the performance.

As mentioned, an additional header is employed to provide a reference to the schema. There are two headers that we need to be aware of in this context. If a publishing capability is using contracts that are approved by the X.commerce team (https://github.com/xcommerce/X.commerce-Contracts), then they are publishing to known topics. In production environments, it is mandatory to publish only to approved topics. For instance, a capability might be using a marketplace contract and publishing to a topic like /marketplace/profile/delete. When such a known topic is used, the publishing capability needs to set a header called X-XC-SCHEMA-VERSION to the contract's version (eg., 1.0.0). This version number will be a value that corresponds to the schema definition found in the Open Commerce Language or X.commerce ontology.

The Fabric, in turn, will convert this and the topic information to a URI in the form of https://<host>/<namespace>/<topic>/<version> that uniquely identifies the that was used to create the message. The receiver of the message just has to look at the header called X-XC-SCHEMA-URI header to fetch the schema. 

In sandbox environment, the capabilities are allowed to experiment with custom topics and schemas. To send a message serialized through a custom schema, the capabilities can directly set the schema uri header. For instance, a capability can set the X-XC-SCHEMA-URI to a publicly hosted message contract and the Fabric will not overwrite it, but pass it on to the receiving capability. We need to remember that this is only allowed in development/sandbox mode.

Let us visit a simple example of a publishing capability that publishes a message to the Fabric. Let us use the marketplace contract and send a message to a known topic:  /marketplace/profile/delete. I will be showing both Ruby and PHP samples along the way. Let us assume that the capability has been registered with the sandbox and we have a bearer token for authorizing our messages. You can find all about registering capabilities here.

We post messages to the fabric url followed by topic name. The headers that are important to understand are

  • Content-Type: Set the content type to avro/binary, which is the type of message that the Fabric expects to communicate in.
  • Authorization: When a capability is registered and a tenant authorization is completed, a bearer token is generated. Use that bearer token. You are always communicating on behalf of a tenant. That tenant can sometimes be you, in that case, the SELF bearer token should be used. This is to prove that the publisher has a valid relationship with the tenant. This document talks in greater detail about capabilities and bearer tokens.  
  • X-XC-SCHEMA-VERSION: This is a numeric value that corresponds to the version of the contract being used

Before the message is posted, it needs to be encoded in Avro/binary using the schema

Error Message

When a capability is registered, it is automatically subscribed to the topic /message/failed. The capability cannot unsubscribe from this topic. The Fabric sends all message delivery errors back to a capability on this topic. Capabilities may not use this topic to deliver application-specific errors. However, if a capability wishes to send an error message to another capability, for instance, a bad field or invalid data, it needs to use X.commerce defined topics to communicate an error. In this example, if we send a message to delete a non-existent profile, the capability can publish back on a topic called /marketplace/profile/delete/failed which can used to indicate a business logic error.

Subscribing/Receiving

We saw a publishing capability send a message to the /marketplace/profile/delete topic, which was delivered to a marketplace capability, which was managing its profile. Logically, this capability needs to know someway if its request was successfully processed. It subscribes to a topic defined in the contract called /markeplace/profile/deleted and /marketplace/profile/delete/failed. When the marketplace capability, receives a message to delete the profile, assuming that the action was successful, it sends a message on /marketplace/profile/deleted. Now, the publisher capability from the previous example sees the following headers -

Using the schema URI, this message can be decoded from Avro binary. Sample code from PHP and Ruby is included -

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1414446/C360_2011-08-20_12-10-28.jpg http://posterous.com/users/5AqlNVDQseaZ Saranyan Vigraham saranyan Saranyan Vigraham
Tue, 31 Jan 2012 06:21:00 -0800 Using Ruby FFI http://dev.saranyan.com/using-ruby-ffi http://dev.saranyan.com/using-ruby-ffi

This week, I had to work with a core C library and there was no reason for me to port it to Ruby. I came across the wonderful FFI gem/library. With FFI, calling external libraries is very easy. I think one of the real powers of FFI is to leverage native C libraries. However, it is also possible to port custom libraries or projects. There is a little bit of work to write the wrappers, which can be slightly tedius depending upon the size of the library/number of functions that we want to use, but still worth the time. There are few good documentation resources on the wiki page that are helpful - ffi examples was especially useful to get started fast.

These are the steps -

1. Create a shared library object for the C code that you want to port. On a unix based system the following commands will help. You might have to link additional libraries based on the code dependencies.

gcc -fPIC -c mylibrary.c
gcc -shared -o mylibrary.so mylibrary.o

2. Create a ruby wrapper based on your h file.

3. Start using your function calls. 

I have come up with a few use cases that covers some of the more used function call types. Let us see some test functions. For the lack of better name, mylibrary.h is defined as -

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "mylibrary.h"
#include <stdio.h>

double calculate_something(int a, float b)
{
 return a+b;
}

const char* test_function_1(const char *w)
{
    return w;
}

int test_function_2(double w,double *x, char *y) {
    
    return ((int) w + (int) *x);
}
void test_function_3(){
    printf("printing...x\n");
}

void test_function_4(double *x){
    x[0] = 1.0;
    x[1] = 2.0;
    x[3] = 3.0;
}

I have created four test functions, which show different argument flavors. Using the above commands, I have compiled my shared library object into say, a file called mylibrary.so. 

The ruby wrapper follows the structure outlined below -

module MyLibrary
  extend FFI::Library
  attach_function ...
end

In simple terms, attach_function call is used to redefine the function to enable its use in Ruby land. For the above code, my wrapper file looks as below -

1
2
3
4
5
6
7
8
9
10
11
# mylibrary.rb
TESTVAR = 2
module MyLibrary
  extend FFI::Library
  ffi_lib "mylibrary.so"
  attach_function :calculate_something, [:int, :float], :double
  attach_function :test_function_1, [:string], :string
  attach_function :test_function_2, [:double, :pointer, :string], :int
  attach_function :test_function_3, [], :void
  attach_function :test_function_4, [:pointer], :void
end

The attach_function follows the pattern of name, input arg types, output arg type. It seems straight forward. (char *) resolves to string, (double *) is a pointer, (int) is an int...etc. You can find a list of types from the git repo of FFI. (https://github.com/ffi/ffi/blob/master/lib/ffi/types.rb)

Let us look at the sample code for calling these functions in both C and Ruby.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include "mylibrary.h"

int main(){
    
    char x[10];
    double d = 10.0;
    double *dp = &d;
    double dd[3];
    printf("tf0 - %lf\n",calculate_something(1,2.33));
    printf("tf1 - %s\n", test_function_1("hello"));
    printf("tf2 - %d\n", test_function_2(10.0,dp,x));
    test_function_3();
    test_function_4(dd);
    printf("tf4 - %lf, %lf, %lf", dd[0], dd[1], dd[2]);
    return 1;
}

In C, using these functions are straight forward. In Ruby, most of them are straight forward except the last function test_function_4. This function takes an array and assigns the first few elements to some values. In Ruby, this array has to be declared FFI::MemoryPointer, which takes three arguments -

dd = FFI::MemoryPointer.new(:double,4, true)

I can pass this object to my function that expected the array. But, one thing that stumped me was that I was trying to access the values using get_double method (eg. dd.get_double(0), dd.get_double(1)...) it was not right. I found out that the right way to access this is using the get_array_of_double method.

The entire code can be downloaded from this git repo.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1414446/C360_2011-08-20_12-10-28.jpg http://posterous.com/users/5AqlNVDQseaZ Saranyan Vigraham saranyan Saranyan Vigraham
Tue, 24 Jan 2012 21:39:00 -0800 Binary data over HTTP in ruby http://dev.saranyan.com/binary-data-over-http-in-ruby http://dev.saranyan.com/binary-data-over-http-in-ruby

Today, I had to read a binary file and transmit it over HTTP post. Here is what I did, which worked perfectly on my localhost (?) but had wierdness all over it on Heroku/Production.

contents = open("#{Rails.root}/tmp/#{fname}.data", "rb") {|io| io.read }
HTTParty.post("#{params["url"]}", {:body => contents, :headers => {'Content-Type' => 'avro/binary',  'Authorization' => params["token"]}})

On the other end, I was dumping this binary data into a file for post processing. In development, this worked fine. However, in production, I was getting a wierd error when I tried to read the data from the binary file. The error was something along the lines of -

ArgumentError ("negative length" -

After much digging, I traced it down to an encoding issue because the data was getting modified someway during the POST operation. The right way to do this is to encode the data using Base64.

contents = open("#{Rails.root}/tmp/#{fname}.data", "rb") {|io| Base64.encode64(io.read) }
HTTParty.post("#{params["url"]}", {:body => contents, :headers => {'Content-Type' => 'avro/binary',  'Authorization' => params["token"]}})

This preserves the data. This makes sense. I still am not sure, why it was working on my localhost. 

 

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1414446/C360_2011-08-20_12-10-28.jpg http://posterous.com/users/5AqlNVDQseaZ Saranyan Vigraham saranyan Saranyan Vigraham
Mon, 23 Jan 2012 09:18:00 -0800 Dabbling with Avro http://dev.saranyan.com/dabbling-with-avro http://dev.saranyan.com/dabbling-with-avro

Avro is a data serialization system that is impressive in terms of the data structures it provides. Avro relies on schemas. An Avro data includes schemas during writing and the same schema is always available when reading or de-serializing this data. This makes it a really cool feature. This means that the serialized data is completely described as it includes its schema. In addition to this, the serialization can be very fast. There are few good examples and discussions on using Avro with Ruby. Check it out.

X.commerce uses Avro for defining message contracts, which makes it possible to describe and validate messages easily. However, the message contracts are defined as an Avro protocol and directly as a schema. Avro supports RPC, where both client and server exchange schemas with a handshaking protocol. But, we don't want to do that. We want to parse the X.commerce contracts as Avro schemas.

I was dabbling with the Avro ruby gem (https://github.com/apache/avro/tree/trunk/lang/ruby) to understand how it operates and how I can directly use that gem to serialize/de-serialize messages. I started with a sample schema -

SCHEMA = <<-JSON
[{ "type": "record",
  "name": "Product",
  "fields" : [
    {"name": "id", "type": "string"},
    {"name": "product_url", "type": "string"},
    {"name": "product_purchased", "type": "boolean", "default": "false"}
  ]},
  { "type": "record",
    "name": "Review",
    "fields" : [
      {"name": "id", "type": "string"},
      {"name": "review_url", "type": "string"},
      {"name": "review_verified", "type": "boolean", "default": "false"}
    ]}
JSON

To serialize this schema, we can do the following -

file = File.open('data.avr', 'wb')
schema = Avro::Schema.parse(SCHEMA)
writer = Avro::IO::DatumWriter.new(schema)
encoder = Avro::IO::BinaryEncoder.new(writer)


dw = Avro::DataFile::Writer.new(file, writer, schema)
dw << {"id" => "product123", "product_url" => "http://ebay.com/some_product", "product_purchased" => true}
dw << {"id" => "review123", "review_url" => "http://yelp.com/some_review", "review_verified" => false}
dw.close

If you look at the schema, I have intentionally used "id" as the name for both the records (Product and Review). This is to illustrate what I think is a bad practice. While, the fields are relative to the particular record, it might be better to have a proper identifier as this helps us easily correlate the data during de-serialization, which we might do the following way.

file = File.open('data.avr', 'r')
reader = Avro::IO::DatumReader.new(nil, Avro::Schema.parse(SCHEMA))
dr = Avro::DataFile::Reader.new(file, reader)
dr.each { |record| p record }

The output is -

$output -> 
 {"id"=>"product123", "product_url"=>"http://ebay.com/some_product", "product_purchased"=>true}
{"id"=>"review123", "review_url"=>"http://yelp.com/some_review", "review_verified"=>false}

If you try to serialize a data using improper schema, it gets flagged immediately. This is the error dump. A better way to display is to catch it and throw an error. Again, this is more for ilustrative purposes -

Avro::IO::AvroTypeError (The datum {"id"=>"foo", "value"=>"1001010"} is not an example of schema'

With X.commerce contracts, read them as schemas and not as RPC protocols. I will post a rails working example of a message console, that sends/receives an Avro message using the above approach.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1414446/C360_2011-08-20_12-10-28.jpg http://posterous.com/users/5AqlNVDQseaZ Saranyan Vigraham saranyan Saranyan Vigraham
Fri, 06 Jan 2012 10:15:00 -0800 Using dot notation on a Ruby Hash http://dev.saranyan.com/using-dot-notation-on-a-ruby-hash http://dev.saranyan.com/using-dot-notation-on-a-ruby-hash
require 'ostruct'

_user = {:first_name => "saran", :last_name => "vigraham"}
@user = OpenStruct.new _user

Now, you can access the @user hash by dot noation. @user.first_name, @user.last_name.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1414446/C360_2011-08-20_12-10-28.jpg http://posterous.com/users/5AqlNVDQseaZ Saranyan Vigraham saranyan Saranyan Vigraham
Thu, 05 Jan 2012 12:21:00 -0800 Jquery Range Slider using Coffeescript http://dev.saranyan.com/jquery-range-slider-using-coffeescript http://dev.saranyan.com/jquery-range-slider-using-coffeescript

I was playing around with coffeescript, a language that compiles into JavaScript. Here is a code for getting Jquery Range Sliders to work in Coffee Script (slider-range is the div ID of my slider element) -

 

$ ->
        $("#slider-range").slider({
                range:true,
                min: 0,
                max: 100,
                values: [0, 20],
                slide: (event, ui) ->
                    #function here
        })

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1414446/C360_2011-08-20_12-10-28.jpg http://posterous.com/users/5AqlNVDQseaZ Saranyan Vigraham saranyan Saranyan Vigraham
Tue, 20 Dec 2011 09:02:00 -0800 PayPal IPN using Rails 3.1 and Active Merchant http://dev.saranyan.com/87523420 http://dev.saranyan.com/87523420

Instant Payment Notification (IPN) is PayPal's message service that sends a notification when a transaction takes place. When IPN is enabled in a seller's account,  the sellergetThere are bunch of tutorials online using Active Merchant gem for implementing IPN. However, most of these tutorials need some modification to be up and running. I created an IPN example using Rails 3.1, hosted on Heroku. Feel free to download the code and integrate it in your rails applications.

The heroku demo link is http://ipnexample1.herokuapp.com 

 

There have been some issues with getting the active_merchant gem to work with Rails 3.1. Please install active_merchant as a plugin. You will find the instructions here (https://github.com/Shopify/active_merchant). The biggest gotcha, that took me a while to figure out is that, this plugin depends on active_utils from Shopify. You need to include that in your gem file. This will save you a few headaches.

 

Once this is done, initialize active merchant in config/intializers. When you set ActiveMerchant::Billing:: Base.mode = :test, you are ensuring that you will be using sandbox version for testing.

 

Active merchant provides a great helper to generate a PayPal submit button. To handle, IPN, you need to do two things - First specify the action in the view that needs to get triggered when notification happens. Enable this in your PayPal seller account (sandbox in this case). This setting is actually hidden under Profile/more options/IPN settings. Note that  if you are using localhost, it is hard to test the IPN as PayPal cannot send IPN to localhost or any flavor of that (lvh.me, smakckaho.st, etc). In the notify action in your controller, you can handle the necessary backend operations like saving to the database, etc.

 

Also, when you create a pre-configured sandbox account, create a pro account if you want to test IPN. I found that even using a seller account does not send me IPN responses. I needed a pro account to receive notifications. This might be a sandbox issue, I am not sure. 

 

You can download the entire code from my git repo - https://github.com/saranyan/PayPal-Code-Examples

 

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1414446/C360_2011-08-20_12-10-28.jpg http://posterous.com/users/5AqlNVDQseaZ Saranyan Vigraham saranyan Saranyan Vigraham
Tue, 18 Oct 2011 09:56:00 -0700 Hello world http://dev.saranyan.com/hello-world http://dev.saranyan.com/hello-world

This post first appeared on x.com (https://www.x.com/developers/community/blogs/saranyan/hello-x.world)

To me, as a developer, "Hello world" is significant. It announces to the world the birth of a new developer, who is going to change the world with code. Code is a light saber that only a developer Jedi can wield. And "Hello world" is the baptism of a person with ideas to change the world to a responsible developer, who WILL change the world. After the magical "Hello world" appears on a screen and reflects the joy in the eyes of the developer, the real deal begins. It is just not baptism, it is baptism of fire. Questions start pounding the head - What is next after "hello world"? How do I build this now? This is too tough, is it worth it? The developer who successfully navigates this overwhelming technology and programming maze becomes the true master of "Hello world". He/She becomes part of the unique community of programming Jedi(s) who can build anything they want and in doing so, become the torch bearers and problem solvers.

 

I have been a developer all my life. From the time I got my PhD in Computer Science to dabbling with multiple startup ideas, I have worked with new technology and code all the time, and that means, several hello worlds. I am particularly thrilled and excited to be part of this awesome open commerce technology, which I believe is going to be a great leveler. There has never been a true open commerce platform that connects developers and merchants with each other and themselves. In addition to the competitive advantage this offers to merchants and developers, x.commerce introduces a "collaborative advantage". Now, merchants will have access to the best capabilities that will help them run their business better. Developers will have access to real people and real problems for which they can build solutions.

I met Nikelii during the x.commerce innovate developer's camp. He is an awesome person to talk to. I spent a long time chatting with him. Nikelii wants to build the next generation stock photography website. His idea is amazing. As a fitness instructor, he has attended camps and events where his astute photography skills are handy. People want to buy his photos, and he knows what is broken in the current stock photography market. For him, x.commerce is a powerful idea. He can get a store up and running without a lot of programming expertise. But, that does not satisfy him. He wants to build the "real thing". He wants to write capabilities that could completely transform the stock photography industry.  He is not a developer, he wants to be one. Because, Nikelii realizes that being a developer means being powerful enough to write the code that will change the world.

Dan is a great developer from San Francisco. He loves dabbling with new technology. He has written several iPhone and Android apps. He has been a programmer from the time he can remember. Dan was super excited about x.commerce. To him, this is like a commerce app store. He is looking forward to build some neat applications. He is a warrior who is looking to master yet another "hello world".

I believe that people Dan and Nikelii should connect and come together. It was not possible before. It is possible now with x.commerce, the world's first open commerce platform. I am a developer evangelist for x.commerce and I love how code and people can come together to build things that change the world in powerful ways. Keep watching this space for my thoughts on mastering the "hello world". If there is anything I can do to help you build cool things, do not hesitate to connect. My twitter handle is @saranyan. You can also write to me at saranyan@x.com

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1414446/C360_2011-08-20_12-10-28.jpg http://posterous.com/users/5AqlNVDQseaZ Saranyan Vigraham saranyan Saranyan Vigraham
Mon, 26 Sep 2011 13:52:00 -0700 Lion, ImageMagic error http://dev.saranyan.com/lion-imagemagic-error http://dev.saranyan.com/lion-imagemagic-error

If you are seeing an error like this on Mac OS X lion -

 

===

dyld: Library not loaded: /System/Library/Frameworks/OpenCL.framework/Versions/A/Libraries/libclparser.dylib

  Referenced from: /opt/local/bin/convert

  Reason: image not found

====

You are missing this file "libclparser.dylib". You need to copy this file into this folder to fix the error. Thanks - http://apple.stackexchange.com/questions/21562/installing-imagemagick-leads-to-weird-error-involving-opencl

 

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/1414446/C360_2011-08-20_12-10-28.jpg http://posterous.com/users/5AqlNVDQseaZ Saranyan Vigraham saranyan Saranyan Vigraham