Showing posts with label with. Show all posts
Showing posts with label with. Show all posts

Thursday, March 12, 2015

Help users find your app with MIME type based Chrome Web Store marketing

Note from editor: The syntax for this feature has changed since this was first posted. The posted has been edited to reflect the change.

Try to think back to when the word “viral” had only negative connotations . . . if you are a web developer trying to market your app on a minimal budget, you may not remember those dark days at all! Viral marketing is currently not just the cheapest but arguably the most effective way to spread the word about your app and to drive user adoption. Through file sharing and MIME type-filtered upsells, Google Drive integration gives apps some powerful “viral” marketing capabilities.

Users love to share files. Google Drive makes this easy for them to do, and we know from experience that they do it often. When users share or sync files that they can’t open using an installed viewer, Drive displays a link to a Chrome Web Store list of apps that can open that file type -- potentially, your app. This can be a powerful mechanism for distributing your app to the users that actually need it.

For example, let’s say someone asks me to review a project plan saved in an .mpp file. I currently don’t have a viewer to open such a file. Am I out of luck? No — help is right there for me at the bottom left of the screen:

If I click on this link, I’m redirected to a Chrome Web Store list of installable apps that have registered themselves to open .mpp files. Currently, this includes some excellent options for Drive-integrated project management web apps:

Interested in getting your app in a list like this? It’s not difficult. First, add a special web intent to your Chrome Web Store manifest. This intent should include the MIME types and extensions youd like your app to be searchable by. Though the type field accepts only MIME types, it allows you to model file extensions as the special type application/vnd.google.drive.ext-type.<EXTENSION>.


 
{
"name" : "ProjectManagmentApp",
"version" : "1",
"description" : "A web app to manage projects",
"container" : "GOOGLE_DRIVE",
"api_console_project_id" : "1234567891011",
"gdrive_mime_types": {
"http://drive.google.com/intents/opendrivedoc": [
{
"type": ["application/vnd.ms-project",
"application/vnd.google.drive.ext-type.mpp"],
"href": "http://projectapp_web_url/",
"title" : "Open",
"disposition" : "window"
}
]
},
...
 

Once an intent like this is published in your app listing, you’ll be featured in Chrome Web Store “upsell” lists like the one depicted above, and users viewing the list will be a click away from installing your app. For full detail on adding this web intent to your manifest and testing it for your Chrome Web Store listing, see Help Users Find your App in the Drive SDK documentation.

We recommend that any and all listed apps should list their MIME types for filtering in this way. However, doing so is especially beneficial for apps that can open any of these following types, for which there is currently no registered viewer at all:

  • message/rfc822 -- Email
  • text/x-vcard -- Electronic business cards
  • application/x-font-ttf -- Fonts
  • image/gif -- Animated GIFs

Inevitably, users who lack valid viewers will end up with shared files of these MIME types. And just when they are about to throw up their hands, they’ll find your app at the top of the list of apps that can help them open the file. This creates the conditions for a very positive first user experience for your app.

If you have questions or comments about how to add this feature to your app, don’t hesitate to let us know on our Stack Overflow tag, google-drive-sdk.

Eric Gilmore

Eric is a technical writer working with the Developer Relations group. Previously dedicated to Google Apps APIs, he is now busy writing about all aspects of the Google Drive SDK.

Read more »

Tuesday, March 10, 2015

Integrating your Rails application with Google Apps and the Apps Marketplace

Editor’s note: Vincent Van Gemert is a software engineer at Floorplanner, an online floor planning application which launched in June on the Google Apps Marketplace.

In this article you will find a step-by-step guide to integrating your Ruby on Rails application with Google Apps and launching it on the Google Apps Marketplace. The Google Apps Marketplace is a great platform to get new clients, show off our product and integrate Floorplanner with the services Google provides. At the beginning of the summer we tried to launch our application on the Marketplace. We found out that a lot of people were struggling with the existing Rails libraries and the OAuth authorization method, therefore we would like to provide this tutorial to help other developers. I would like to thank DuĊĦan Maliarik for building this implementation with me and finding the solution for using the two-legged OAuth authorization.

1. The initial setup

Before you start programming there is some required setup. You first have to add a new application on the Google Apps Marketplace. You will need a Vendor Profile for this and a Google account. Sign In to the Marketplace with your Google account and go to your Vendor Profile using the link at the top-right of the Marketplace homepage.

After you enter some information about your company, there will be a list of your applications called “Listings.” You need to create a new listing to develop and test your application. When you create a new listing, check the box which says “My product may be directly installed into Google Apps domains.” This is necessary if you want the application to have an “Add it Now” button on the listing page, and allows you to add a Manifest to describe the application.

A Manifest describes all the settings of your application, like the name, URL’s and required permissions. Below you can find an example manifest. You will need to change all fields surrounded by brackets [ ].
<?xml version="1.0" encoding="UTF-8" ?>
<ApplicationManifest xmlns="http://schemas.google.com/ApplicationManifest/2009">

<Name>[ApplicationName]</Name>
<Description>[Description]</Description>

<!-- Administrators and users will be sent to this URL for application support -->
<Support>
<!-- URL for application setup as an optional redirect during the install -->
<Link rel="setup" href="[ApplicationSetupUrl]?domain=${DOMAIN_NAME}" />

<!-- URL for application configuration, accessed from the app settings page in the control panel -->
<Link rel="manage" href="[ApplicationAdminUrl]?domain=${DOMAIN_NAME}" />

<!-- URL explaining how customers get support. -->
<Link rel="support" href="[ApplicationHelpUrl]" />

<!-- URL that is displayed to admins during the deletion process, to specify policies such as data retention, how to claim accounts, etc. -->
<Link rel="deletion-policy" href="[ApplicationPolicyUrl]" />
</Support>

<!-- Show this link in Googles universal navigation for all users -->
<Extension id="navLink" type="link">
<Name>[ApplicationName]</Name>
<Url>[ApplicationLoginUrl]?domain=${DOMAIN_NAME}</Url>
<!-- Used APIs -->
<Scope ref="contactFeed"/>
<Scope ref="spreadsheetFeed"/>
<Scope ref="doclistFeed"/>
</Extension>

<!-- Declare our OpenID realm so our app is white listed -->
<Extension id="realm" type="openIdRealm">
<Url>[ApplicationRealm]</Url>
</Extension>

<Scope id="doclistFeed">
<Url>https://docs.google.com/feeds/</Url>
<Reason>[Reason]</Reason>
</Scope>

<Scope id="contactFeed">
<Url>https://www.google.com/m8/feeds/</Url>
<Reason>[Reason]</Reason>
</Scope>

</ApplicationManifest>

You should decide whether you want to create a setup page. During the installation process of the application you will be redirected to the URL you specified in the manifest under “setup”. This is useful for collecting additional information necessary for configuring the app, or setting up a new umbrella account for the company. The umbrella account allows you to use other users of the domain as sub-users. You can also retrieve other information, like the administrators of the domain, the logo of the Google Apps account, or the domain name of the Google Apps account. If you don’t want to redirect customers to your site during the installation process, then just remove the line from your manifest.

2. Rails libraries and OpenID

The code you’re going to use relies on several Rails plugins and gems. The plugins/gems needed for this tutorial are listed below.
  • OAuth Gem
  • Ruby-openid
  • Rack-openid
  • Ruby-openid-apps-discovery
After installing these, you will be able to use OpenID, OAuth and the Google Data APIs in your Rails application. First you are going to authenticate the user with OpenID. This way you can retrieve the user’s email address and other information like First and Last name. The OpenID implementation is straight-forward. When using OpenID, a connection will be made to Google’s OpenID service and will check if the user granted access to your application. In typical OpenID, a ‘grant access’ page or login page is presented if the user hasn’t granted access to the app, though this won’t happen if you have a Google Apps Marketplace application installed with a properly configured realm as access is granted by the administrator for all of their users. This process can be found in the example code below.

def login

# The domain needs to be set. For example with params[:domain]
authenticate_with_open_id(params[:domain]),
{ :required => ["http://axschema.org/contact/email"], :return_to => /login}) do |result, identity_url, registration|

if result.successful?
# Succesfully logged in, retrieve email address
email = get_email(registration)
else
# Failed to login
end
end

end

def get_email(registration)

ax_response = OpenID::AX::FetchResponse.from_success_response(
request.env[Rack::OpenID::RESPONSE])
ax_response.data["http://axschema.org/contact/email"].first

end

After reviewing this code sample you can alter it for using it with the setup page. Authenticate with OpenID when a user goes into the setup procedure and redirect them to the actual setup page after they are authenticated.

After your setup page is complete you can add your Google Apps Marketplace listing to your Google Apps account. Note that administrator privileges are necessary to add the application to your Google Apps account. You can add the application from the Vendor Profile when you click on your newly created application. A big blue button will appear on the right side of the listing’s information page. More information on this process can be found on the Creating a Listing page in the Marketplace developer documentation.

3. Using the Google Data APIs

When using the Google Data APIs outside of the Apps Marketplace you have to get access to a user’s data using three-legged OAuth, AuthSub or ClientLogin. These authorization methods require your application to redirect the user to Google’s site to request authorization. Because you’ve already authenticated the user by using OpenID and an administrator has granted authorization to the user’s data when they added your application to their Google Apps domain, you don’t want to use these methods.

For the Google Apps Marketplace there is another option-- two-legged OAuth. Two-legged OAuth allows your application to use a single consumer key and secret (available from the Vendor Profile) to access the data for all your customers who have installed the Marketplace app and granted the appropriate permissions. Because the administrators have granted permission on behalf of their users, each user does not need to be prompted individually.

The first thing you should try is to retrieve a contact list of a user. You could use it for auto completion on forms, or you can let users quickly add friends to your application.

CONSUMER_KEY = "Your-consumer-key"
CONSUMER_SECRET = "Your-consumer-secret"

def get_contacts

# Retrieve contacts
email = "user@email.com"
url = "https://www.google.com/m8/feeds/contacts/default/full?xoauth_requestor_id=#{email}"
contacts = gdata_request(url, :get)

end

def gdata_request(url, method, headers = {}, data = "")

uri = URI.parse(url)

# Setting up two-legged-oauth
consumer = OAuth::Consumer.new(CONSUMER_KEY, CONSUMER_SECRET)
oauth_params = {:consumer => consumer, :method => method, :request_uri => uri.to_s}

# Set Net:HTTP connection
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = (uri.port == 443)

if method == :post
req = Net::HTTP::Post.new(uri.request_uri)
req.body = data
else
req = Net::HTTP::Get.new(uri.request_uri)
end

# Set authorization header
oauth_helper = OAuth::Client::Helper.new(req, oauth_params)
req.initialize_http_header(headers.merge({Authorization => oauth_helper.header}))

# Execute request
response = http.request(req)
response.body

end

The feature we struggled with the most during the integration of Floorplanner was the two-legged OAuth authorization. There was no documentation available for the gems and it took some attempts to get it right. We turned to the OAuth Playground to find out the differences between our own request and the working request. After numerous tries we found out that we need to specify the HTTP method in order to get it working. It was important to use the Net::HTTP::Post request when sending information and Net::HTTP::Get request when retrieving information. This sounds logical, but it also needed to be done when retrieving the authorization header in the OAuth Client Helper, as well as in the Net HTTP request. Now we have this code, we can generate a request for almost every call in the Google Data API’s.

In the next example, you will use the Google Docs API to send a CSV file to a user’s Google Docs account. You need to do a POST request to the Google Docs feed. The request is almost the same as in the previous example, only you need to add two more headers. One is the Content-Type where you specify the MIME type you want to send. In this case, you’re uploading a CSV file so “text/csv” will do. Another header you need to send is the Slug. This value specifies the name you want for the document in Google Docs. Another way of doing this is adding meta-data to the body of the request. More information on this method can be found in the the Google Docs documentation.

def submit_csv_to_gdocs

email = user@email.com
url = https://docs.google.com/feeds/default/private/full?xoauth_requestor_id=#{email}

# Create new CSV
csv = StringIO.new

CSV::Writer.generate(csv, ,) do |line|
line << ["Example 1", "Example 2"]
end

csv.rewind

# Send request
gdata_request(url, :post,
{ Content-Type => text/csv,
Slug => test.csv,
GData-Version => 3.0 },
csv.read)

end

Now, this is all you need to get started with the Google Data API’s. Be sure to check out the Google Apps Marketplace Developer overview for more information and to see which API’s you could use and how to use these. I would advise to check out the OAuth Playground if you have any problems with authorization. Using the playground with two-legged OAuth is very easy. Just follow these steps:
  1. Set the signature method to HMAC-SHA1
  2. Type in your consumer key and consumer secret (these can be found in your Vendor Profile)
  3. Set your Feed URL (step 6)
  4. Set GData-version to 3.0 unless the API only supports 2.0
  5. Click execute
Since the OAuth playground traffic isn’t over SSL, I’d only recommend using it with the consumer key and secret for a test application installed on test domains.

Thank you for reading this tutorial. I know this isn’t the best approach on using two-legged OAuth but it will give you some insight. The best way would be to build in two-legged OAuth support in the Google Data APIs Ruby Utility Library. I haven’t done that yet but am planning to look into that soon. If you have any questions or comments, I would love to hear from you. You can email me at vincent@floorplanner.com.

One last note: These code snippets are just examples of how to use the Google Apps Marketplace with Rails. I would advise you not to use these examples in a production environment.

Want to weigh in on this topic? Discuss on Buzz

Read more »

Wednesday, February 18, 2015

My Mouse is not Working How to Use Mouse With the Help of Keyboard

My Mouse is not Working: How to Use Mouse With the Help of Keyboard?


Hi friends, after a long time I am back again to share some tips and tricks with you. Many times it occurs that your mouse stop working due to some reasons, in that case you are unable to use the mouse pointer. You may face so many difficulties to work on your computer. In this post I am going to share a trick by which you can control the mouse pointer without actually using mouse. You can do this with the help of keyboard. Some simple steps are given below by which you can perform this trick.

Also Read: How to format an unformatable Pendrive
Also Read: How to install Hindi font in windows xp

How to Use Mouse Without Actually Using it?

1. First of all click on start button by pressing windows key  on your Keyboard.
2. Than with the help of arrow keys navigate to Control Panel option and than press enter.
3. Now again with the help of arrow keys navigate to Accessibility Options and than press enter.
4. In the next window, go to mouse option by pressing Tab button 9 times and than pressing right arrow key.
5. Now again press Tab button and than Space-bar to select Use Mouse Keys Option.
6. You can also change the mouse pointer options such as its speed, Acceleration by going to Settings option.
7. Than with the help of Tab button go to OK option and than press enter.
8. If every thing will be done correctly than you will be able to see a mouse icon in the system tray near the system time.

My Mouse is not Working: How to Use Mouse With the Help of Keyboard?

9. Now you can move mouse pointer with the help of buttons 7, 8, 9, 4, 6, 1, 2, 3 on the Numpad. Button 5 on the Numpad can be used to perform mouse’s left button function.

Note: To control mouse pointer with keyboard the Num Lock key must be on.

Update: Or you can try a simple way i.e. just press Alt+Shift+Num Lock at a time, then activate mouse keys in the dialogue box that appears and press ok.
Read more »

Tuesday, February 17, 2015

Creating Cubes with Oracle OLTP databases A test scenario with synonims

This is article is written based on below queries before I explore it.

1) Is it mandatory to have Star Schema based warehouse to create Cubes ?
2) In oracle if you have multiple users(lets say multiple schemes).. Is it possible t design a simple CUBE dimension from schema A of a table and measure from schema B of another table ?

The answer is , NO & Yes.

All the organizations may not maintain complete data ware housing solutions and run their transactional database using normalized OLTP models.

It is not mandatory to have a star schema based ware house to create OLAP cube to analyze your data but you can also use OLTP databases.


The new things I found while demonstrating a simple cube are..

1) Connecting to oracle database.
2) Fetching all the tables of all schemas.
3) Synonyms of a particular schema

 You will find a lot of time taking to load the database into PSW tool once you connected to a schema.. Using FILTER_SCHEMA_LIST at Options section of the database dialogue will take the control to load only specified schema tables.

By default the PSW engine assumes to load all the tables in all the schemes.


A scenario of Dimensions and measures.

Suppose in a case, if you have a measure coming from table defined in SchemaA, measure coming from a table defined in SchemaB... in that case while giving tables for fact and dimension tables, the synonyms will not appear in drop down boxes... 

You need to hard code the tables names ... Of course your dimensions & measures will be in X with red color, it will not affect your definition of hard coded table names.

Save the schema and publish it to the server... have tested it with Saiku plug-in ad-hoc editor and worked nicely.


Thank you.

References :
1) http://jira.pentaho.com/browse/PSW-135

2) http://forums.pentaho.com/showthread.php?162540-OLTP-tables-VS-RDBMS-tables-Designing-OLAP-cubes-Peformance-factors&p=374714#post374714

3) http://forums.pentaho.com/showthread.php?157997-Schema-Workbench-freeze-after-establishing-a-connection-in-db








 
Read more »

Monday, February 16, 2015

A first experiment on D3 bar chart in pentaho CDE Queried output on Bar Chart with few limitations

Hi Guys,

I love experimenting/Playing with Pentaho C-Tools where it took me to explore D3 bar chart with SQL query result set...

Not a big deal in implementing it, but want to share some thing with community folks.

What will you learn in this post ?
You will get an idea on how to implement D3 bar chart.
1) Passing query output to D3 chart code.



Limitations on the Example :
1) Query and Chart is not parametrized yet.
2) Y-Axis labels are not dynamic yet.
3) Tool tip is not implemented.
4) Not tested the bootstrap support.
5)  and more.....

Readers are encouraged add your support to improve the sample of this in comment box...


Software setup :
a) C-Tools(CDE,CDF,CDA,CGG) - Version14.06.18 stable with bootstrap support.
b) Database server for a sample query - In this example postgres - foodmart database.
3) Install D3 components plug-in from market Place


 Example 1 : 

 Step 1 : Layout : Create your layout .... Row---column--Html... Span 24 for this example
 Step 2 : Data Source : 
Driver : org.postgresql.Driver
URL : jdbc:postgresql://localhost:5432/foodmart
UserName/Password : postgres/postgres
Query : query1
select distinct first_name as letter,salary as frequency from employee where salary!=20 limit 20
Step 3: Components
D3 Components - D3 component -
In properties for Custom Chart Script write below code.
Datasoruce : query1


function f(dataset){
   

    
    var data = this.cdaResultToD3Array(dataset);
   
    
    var margin = {top: 20, right: 20, bottom: 30, left: 40},
        width = this.getWidth() - margin.left - margin.right,
        height = this.getHeight() - margin.top - margin.bottom;
   
    var formatPercent = d3.format(".0%");
   
    var x = d3.scale.ordinal()
        .rangeRoundBands([0, width], .1, 1);
   
    var y = d3.scale.linear()
        .range([height, 0]);
   
    var xAxis = d3.svg.axis()
        .scale(x)
        .orient("bottom");
   
    var yAxis = d3.svg.axis()
        .scale(y)
        .orient("left")
        .tickFormat(formatPercent);
  
  
    var svg = d3.select("#"+this.htmlObject).append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
      .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
       
       
 
   
    // Commenting this out, we have data already
    // d3.tsv("/pentaho/api/repos/d3ComponentLibrary/static/custom/data/data.tsv", function(error, data) {
   
      data.forEach(
                    function(d) {
                    d.frequency = +d.frequency;
                    }
      );
   
      x.domain(data.map(function(d) { return d.letter; }));
      y.domain([0, d3.max(data, function(d) { return d.frequency; })]);
   
      svg.append("g")
          .attr("class", "x axis")
          .attr("transform", "translate(0," + height + ")")
          .call(xAxis);
   
      svg.append("g")
          .attr("class", "y axis")
          .call(yAxis)
        .append("text")
          .attr("transform", "rotate(-90)")
          .attr("y", 6)
          .attr("dy", ".71em")
          .style("text-anchor", "end")
          .text("Frequency");
   
      svg.selectAll(".bar")
          .data(data)
        .enter().append("rect")
          .attr("class", "bar")
          .attr("x", function(d) { return x(d.letter); })
          .attr("width", x.rangeBand())
          .attr("y", function(d) { return y(d.frequency); })
          .attr("height", function(d) { return height - y(d.frequency); });
   
      d3.select("input").on("change", change);
   
      var sortTimeout = setTimeout(function() {
        d3.select("input").property("checked", true).each(change);
      }, 2000);
   
      function change() {
        clearTimeout(sortTimeout);
   
        // Copy-on-write since tweens are evaluated after a delay.
        var x0 = x.domain(data.sort(this.checked
            ? function(a, b) { return b.frequency - a.frequency; }
            : function(a, b) { return d3.ascending(a.letter, b.letter); })
            .map(function(d) { return d.letter; }))
            .copy();
   
        var transition = svg.transition().duration(750),
            delay = function(d, i) { return i * 50; };
   
        transition.selectAll(".bar")
            .delay(delay)
            .attr("x", function(d) { return x0(d.letter); }
           

            );
           
        transition.select(".x.axis")
            .call(xAxis)
          .selectAll("g")
            .delay(delay);
      }
    // });
   
}

NOTE :
1)  As the code is a replica of build in Example in Pentaho D3 plug-in , the code depends on 2 column result set of data.....

Step 4: Save dashboard and test the output
Image 1 : With sort enabled - For this you need to write below HTML code for the column of this chart in layout section .

<label><input type="checkbox"> Sort values</label>  


Image 2 : With sort check box disable


Example 2:

Why to wait ? Lets have a look at this static bar chart example in CDE( check this : http://jsfiddle.net/enigmarm/3HL4a/13/ )

Image 1:  Ascending

Image 2 : Descending
Default:

To get the above static charts on CDE output... lets do this..

Hmmmm...!!! the same  code I used from http://jsfiddle.net/enigmarm/3HL4a/13/ in CDE as an experiment..

Add HTML code at Row-Column-HTML
Add Css code at : Code Sinppet Css
Add D3 chart script code at : Custom chart script for D3 component.
Save your dashboard and preview it..


Are you eager to check it in CDE ? Download the examples here 

Click Me folk...!!! :-) 


References : 
1) http://bl.ocks.org/Caged/6476579
2) http://bl.ocks.org/mbostock/raw/3885705/
3) http://bl.ocks.org/mbostock/3885304
4) http://bl.ocks.org/mbostock/raw/3885304/
5) http://jsfiddle.net/gregfedorov/Qh9X5/9/
6) http://jsfiddle.net/uedatakuya/tXPEV/light/
7) http://jsfiddle.net/weXNd/6/










Read more »

Tuesday, February 10, 2015

Internet Download Manager IDM 6 17 Build 9 full version with crack


Review:
Internet Download Manager (IDM) is a tool to increase download speeds by up to 5 times, resume and schedule downloads. Comprehensive error recovery and resume capability will restart broken or interrupted downloads due to lost connections, network problems, computer shutdowns, or unexpected power outages. Simple graphic user interface makes IDM user friendly and easy to use.Internet Download Manager has a smart download logic accelerator that features intelligent dynamic file segmentation and safe multipart downloading technology to accelerate your downloads. Unlike other download managers and accelerators Internet Download Manager segments downloaded files dynamically during download process and reuses available connections without additional connect and login stages to achieve best acceleration performance.

Internet Download Manager supports proxy servers, ftp and http protocols, firewalls, redirects, cookies, authorization, MP3 audio and MPEG video content processing. IDM integrates seamlessly into Microsoft Internet Explorer, Netscape, MSN Explorer, AOL, Opera, Mozilla, Mozilla Firefox, Mozilla Firebird, Avant Browser, MyIE2, and all other popular browsers to automatically handle your downloads. You can also drag and drop files, or use Internet Download Manager from command line. Internet Download Manager can dial your modem at the set time, download the files you want, then hang up or even shut down your computer when its done.

Other features include multilingual support, zip preview, download categories, scheduler pro, sounds on different events, HTTPS support, queue processor, html help and tutorial, enhanced virus protection on download completion, progressive downloading with quotas (useful for connections that use some kind of fair access policy or FAP like Direcway, Direct PC, Hughes, etc.), built-in download accelerator, and many others.

Version 6.17 adds Windows 8 compatibility, adds IDM download panel for web-players that can be used to download flash videos from sites like MySpaceTV, and others. It also features complete Windows 7 and Vista support, video page grabber, redeveloped scheduler, and MMS protocol support. The new version also adds improved integration for IE 10 and IE based browsers, redesigned and enhanced download engine, the unique advanced integration into all latest browsers, improved toolbar, and a wealth of other improvements and new features.

Screen Shots:

How to Create full version IDM 6.17: Video Tutorial




Download Internet Download Manager 6.17 Build 8

Download

click to begin

6.0 MB

Password: 4hbest.blogspot.com
I hope you like it......!
Read more »