tag:blogger.com,1999:blog-59238877519698986712024-03-05T16:44:07.640+05:30blog.pleb.inLife of AppsDaneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.comBlogger31125tag:blogger.com,1999:blog-5923887751969898671.post-47946306734424387262017-12-25T23:31:00.001+05:302017-12-26T12:48:49.635+05:30A Cursory Look at Auth0<div dir="ltr" style="text-align: left;" trbidi="on">
<a href="https://auth0.com/" target="_blank">Auth0</a> provides an identity infrastructure for applications helping them authenticate users. Auth0 supports authentication using OAuth using social media providers, username/password and other means. Auth0 offers a free trial and supports signup using social media. I signed up using my github account. It offers good tutorials to setup the central dashboard that has a host of features, I only tried two basic features: setting up clients and APIs.<br />
<br />
<b>Setting up clients</b> that would use Auth0 for authentication: I used single page webapps as they pointed to a node implementation. Native iOS apps and non-interactive apps are supported.<br />
<br />
<b>APIs </b>can be protected using JWT and other means. These can be defined in the dashboard.<br />
<br />
<b>Users </b>that want to use your app can signup using the Auth0 endpoint shared. The signing up as mentioned earlier would be primarily through social media accounts and username/password. The users signed up are displayed in the dashboard.<br />
<br />
Auth0 supports both SAML and OAuth. It also supports OAuth using JWT. <a href="https://jwt.io/introduction/" target="_blank">JWT or JSON Web Tokens</a> offer a compact way to authenticate users and the flow is as follows:<br />
<br />
<div style="text-align: left;">
</div>
<ul>
<li>User authenticates using username/password</li>
<li>Receives a JWT token </li>
<li>Uses the JWT token until it expires for further server interaction by passing it in the header</li>
</ul>
<br />
<div style="text-align: left;">
<br /></div>
JWT is more compact than SAML as SAML is more lengthy due it being XML based. I had initially thought of writing a post on JWT authentication but found that this post by <a href="https://jonathanmh.com/express-passport-json-web-token-jwt-authentication-beginners/" target="_blank">Jonathan</a> explains it well.<br />
<div>
<br /></div>
</div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-13540850173747022722017-12-24T22:08:00.001+05:302017-12-24T22:08:54.725+05:30Classy Promises with Arrows in Scope - Quick look at some ES6 features<div dir="ltr" style="text-align: left;" trbidi="on">
Having seen some code with arrow functions all over and unable to understand it, I decided to spend some time and learn the new features in ES6. I attended <a href="https://classroom.udacity.com/courses/ud356" target="_blank">Udacity's ES6 course</a>, which had lots of examples and was helpful. Apart from arrow functions, the other features that I was keen on learning were variable scoping with const and let keywords, classes and promises. Here is a quick look at what I learnt.<br />
<br />
<b>Arrow Functions</b><br />
My requirement was only to understand how to read code written with arrow functions as there were quite a few examples using them. Suffice to say, <code>(parameters) => { statements }</code>.<br />
<br />
In the code snippet below, where I am using only a single line function, there is no need to encapsulate the code with curly braces. <a href="https://codeburst.io/javascript-arrow-functions-for-beginners-926947fc0cdc" target="_blank">JavaScript: Arrow Functions for Beginners</a> is a good article that describes the arrow functions well.<br />
<br />
<script src="https://gist.github.com/daneshzaki/c578319f74e71fad07f4122625c6ce69.js"></script><br />
<b>const and let</b><br />
The const keyword fixes the value of the variable to what is assigned during declaration. This is useful when importing (requiring) libraries as they do not change in the course of the program. In the code snippet below, variables express and app are declared with const as their values do not change in this course of the program.<br />
<br />
<script src="https://gist.github.com/daneshzaki/352c4768f1ef8de329cb08ac65438735.js"></script><br />
When a variable is defined with let, it makes the variable local to the block in which it is defined. In the code snippet above, isError's scope is limited to inside the getCustomer promise block only.<br />
<br />
<b>Classes</b><br />
Coming from a Java background, I wanted to see ES6 classes more out of curiosity than anything else. Not being an expert in JavaScript ES5 helped here as it was easy to relate to Java classes (I did not have to relate it prototypes etc.). In the code snippet below, I create a customer class with attributes for id, name, level and since.<br />
<br />
<script src="https://gist.github.com/daneshzaki/77b6c82aea54059b1f5e6024ff8d5da5.js"></script><br />
<b>Promises</b><br />
Finally, promises. I learnt promises from the ES6 Udacity course that I mentioned above and also looking at this useful article on <a href="https://scotch.io/tutorials/javascript-promises-for-dummies">scotch.io</a>. A quick summary is in order. Promises are for best suited for avoidance of <a href="https://en.wikipedia.org/wiki/Pyramid_of_doom_(programming)" target="_blank">"pyramid of doom"</a> that happens when you execute code with callbacks. In promises, there are four states:<br />
<div style="text-align: left;">
</div>
<ul>
<li>success: resolved/fulfilled</li>
<li>failure: rejected</li>
<li>pending</li>
<li>complete</li>
</ul>
<br />
<div style="text-align: left;">
<b>Creating promises</b></div>
In the code creating the Promise, success is notified through a resolve function call and failure is notified through a reject function call. In the getCustomer promise below, I return an error through the reject function call if the variable isError is true. I return customer records for the success criteria through the resolve function.<br />
<br />
<script src="https://gist.github.com/daneshzaki/e7005306f60bf352c63addb365c8a0bc.js"></script><br />
<b>Calling promises</b><br />
In the arrow function code where the promise is invoked, the then method notifies us if the method executed successfully or failed. It also has a chained catch method that catches the exception/error. If we set isError to true in the code and return an error, the catch method will get executed. <br />
<br />
<script src="https://gist.github.com/daneshzaki/c578319f74e71fad07f4122625c6ce69.js"></script><br />
<br /></div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-20138628594307582982017-11-25T15:50:00.000+05:302017-11-25T15:50:11.949+05:30Compensation Logic using RabbitMQ<div dir="ltr" style="text-align: left;" trbidi="on">
After listening to <a href="https://www.youtube.com/watch?v=xDuwrtwYHu8" target="_blank">Caitie McCaffrey on the Saga pattern</a>, I added basic compensation logic to the rudimentary order management flow described in this <a href="http://blog.pleb.in/2017/11/understanding-microservices.html" target="_blank">post</a>.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxJTvzIpK-hdDyPeTJJUq49l9BvXmF8LznGrl3roUJbRPQAck9cAWCimczFtDrnusL7gL3vDE_ypGIcym5C-Ia_iXvA5eVy9JtTh2TSqt27yDKQxLD3LZIpV9iwCmaHzqyApP-baV-NcI/s1600/compensation.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="720" data-original-width="1280" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxJTvzIpK-hdDyPeTJJUq49l9BvXmF8LznGrl3roUJbRPQAck9cAWCimczFtDrnusL7gL3vDE_ypGIcym5C-Ia_iXvA5eVy9JtTh2TSqt27yDKQxLD3LZIpV9iwCmaHzqyApP-baV-NcI/s640/compensation.png" width="640" /></a></div>
<br />
<ul style="text-align: left;">
<li>To recap, the flow starts with an order being placed through a POST request</li>
<li>Then each microservice posts a message on a RabbitMQ Exchange (type: direct) with the completion status as the routing key </li>
<li>The microservice that has to be executed next listens on the "topic" with the binding key for triggering it and starts executing on receipt of a matching message</li>
<li>On error, the microservice posts a message with the error text as the routing key e.g. "Order Processing Error". The message payload could contain further details about the error</li>
<li>Each microservice also listens on a "topic" with a binding key containing an error and on receipt of a message, it executes the compensation logic </li>
</ul>
<br />
<script src="https://gist.github.com/daneshzaki/bffe7b8a8b0dc59da5d27ccbebc00878.js"></script>
The complete flow with transaction is as follows:<br />
<br />
1. Order Creation<br />
- trigger: POST request<br />
- success: order placed, check inventory<br />
- failure: no order placed, inform and stop execution<br />
- compensation: order cancel, inform and stop execution<br />
<br />
2. Inventory Check<br />
- trigger: check inventory message<br />
- success: inventory available, notify shipment (or) inventory unavailable, notify stock replenishment<br />
- failure: inventory unavailable and cannot be replenished notify order creation<br />
- compensation: reset inventory, notify order creation<br />
<br />
3. Stock Replenishment<br />
- trigger: stock replenish message<br />
- success: stock replenished, notify shipment<br />
- failure: stock not replenished, notify inventory check<br />
- compensation: none<br />
<br />
4. Order Shipment<br />
- trigger: ship order message<br />
- success: order shipped, inform and stop execution<br />
- failure: order not shipped, notify inventory check (for inventory reset)<br />
- compensation: none<br />
<div>
<br /></div>
<div>
Full code is available <a href="https://github.com/daneshzaki/tashkent" target="_blank">here</a>.</div>
</div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-3750740521495272582017-11-13T20:55:00.000+05:302017-11-13T20:55:41.961+05:30Node.js Utility Modules & Configuration<div dir="ltr" style="text-align: left;" trbidi="on">
As I learn and understand Node.js better, I try to organize the code better. Some of the changes that I did to the code that does <a href="http://blog.pleb.in/2017/11/understanding-microservices.html" target="_blank">microservices orchestration</a> are:<br />
<br />
<ul style="text-align: left;">
<li>Organized helper code for RabbitMQ and HTTP methods into a separate module by following this useful <a href="https://www.hacksparrow.com/how-to-write-node-js-modules.html" target="_blank">article</a></li>
<li>Moved the URL details for RabbitMQ to a separate js file following this <a href="https://stackoverflow.com/questions/5869216/how-to-store-node-js-deployment-settings-configuration-files" target="_blank">stackoverflow response</a></li>
<li>Closed RabbitMQ connections on process exit trapping kill & Ctrl-C signals using the morbidly titled npm module called <a href="https://www.npmjs.com/package/death" target="_blank">death</a> </li>
</ul>
</div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com1tag:blogger.com,1999:blog-5923887751969898671.post-6824466240422323412017-11-11T19:21:00.000+05:302017-11-25T15:51:39.485+05:30Understanding MicroServices Choreography using RabbitMQ & Node.js <div dir="ltr" style="text-align: left;" trbidi="on">
A colleague and I had discussed on <a href="https://www.linkedin.com/pulse/making-services-dance-microservices-world-danesh-zaki/" target="_blank">choreography of microservices</a> a while ago and the topic came up for discussion again recently. In order to ensure that I understood the nuances correctly, I decided to write some code to implement the approach. Here are the tools/technologies that I chose:<br />
<br />
<ul style="text-align: left;">
<li><a href="http://nodejs.org/">Node.js</a> for building the microservices </li>
<li><a href="http://www.restify.com/" target="_blank">Restify</a> for exposing Restful APIs</li>
<li><a href="http://www.cloudamqp.com/" target="_blank">CloudAMQP</a> - a RabbitMQ as a service offering as the integration bus</li>
<li><a href="https://github.com/squaremo/amqp.node" target="_blank">amqp.node</a> - a Node.js client library for RabbitMQ. </li>
</ul>
<br />
CloudAMQP offers a free tier good enough for learning and trying things out. It also comes with an easy to use management console that gives good statistics. The tutorials and articles are useful too.<br />
<br />
There is a host of options for the Node.js RabbitMQ client libraries. I tried a few and then settled with amqp.node as the RabbitMQ site had their tutorials on it. The library comes in two flavours, one with callbacks and the other with promises. Being comfortable with callbacks, I opted for it.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeKvzEgNyXNlxOeCJcWoRFNyV7YCxKYgAorQuDgL_yQB3ta4esYI51cDeTokFrd3VqJNAESXYhyphenhyphen_bmB7WwgVkxDD_kMvPgZIl4p-z-LqV6r1EANONvEXhg_3Ou1jTJSopY93sOakdOKN8/s1600/choreoflow-upd.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="720" data-original-width="1280" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeKvzEgNyXNlxOeCJcWoRFNyV7YCxKYgAorQuDgL_yQB3ta4esYI51cDeTokFrd3VqJNAESXYhyphenhyphen_bmB7WwgVkxDD_kMvPgZIl4p-z-LqV6r1EANONvEXhg_3Ou1jTJSopY93sOakdOKN8/s640/choreoflow-upd.png" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
The approach that I followed was to mimic a part of the order management process where a POST method triggers the order creation service. The service processes the order, creates an entry in the order management database and sends a message to a RabbitMQ topic. Following is the code snippet.<br />
<br />
<script src="https://gist.github.com/daneshzaki/03439aa45bc1056d2fdeefb056eefcd8.js"></script>
<br />
<div>
<br />
Another service listens to the topic for a specific key that denotes that the order creation is complete and gets triggered when a message with that key is published. This service checks for inventory and either calls a service to replenish stock if it is low or calls an order shipment service if the stock is available. It too publishes a message on the topic with the respective keys to trigger the following services. Following is the code snippet.<br />
<br />
<script src="https://gist.github.com/daneshzaki/370d4ef604fc2c95d82136523bfb400b.js"></script>
</div>
<div>
The code below publishes and consumes from a RabbitMQ topic. <a href="http://kafka.apache.org/" target="_blank">Apache Kafka</a> can be used as an alternative to RabbitMQ as an event bus. <br />
<br />
<script src="https://gist.github.com/daneshzaki/e01bbe9903329edf0a8552963bbb57a1.js"></script>
<script src="https://gist.github.com/daneshzaki/90eb1b8f0af333bdf2dc8d794b378243.js"></script>
This approach will work while creating new microservices as they can be made to start on the basis of an event.<br />
<br />
As can be seen from the code, it is heavily work in progress. I am hoping to do the following tasks:<br />
<br />
<ul style="text-align: left;">
<li><strike>Figuring out a good way of closing RabbitMQ connections</strike> Done:Updated the code to use <a href="https://www.npmjs.com/package/death" target="_blank">npm module death</a> to run a function on process kill to close RabbitMQ connections</li>
<li><strike>Making modules out of some common code functions</strike> Done: moved the helper functions for HTTP methods and RabbitMQ to a module. </li>
<li><strike>Add compensation logic</strike> Done: this <a href="http://blog.pleb.in/2017/11/compensation-logic-using-rabbitmq.html" target="_blank">post</a> explains the compensation logic </li>
<li><strike>Add an OpenAPI (Swagger) spec</strike> Done: added a spec for Order Creation <a href="https://github.com/daneshzaki/tashkent/blob/master/OrderCreation/swagger.yaml" target="_blank">here</a></li>
<li>Create Docker containers </li>
</ul>
Full code is available <a href="https://github.com/daneshzaki/tashkent" target="_blank">here</a>.<br />
<br /></div>
</div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-27883903532719346242017-11-01T22:57:00.004+05:302017-11-01T22:57:45.244+05:30Node.js Code Organization <div dir="ltr" style="text-align: left;" trbidi="on">
As mentioned in my previous <a href="http://blog.pleb.in/2017/10/learning-nodejs-on-udemy.html" target="_blank">post</a>, I learnt Node.js and Restify through the Udemy <span style="background-color: white; color: #404040; font-family: Arimo, sans-serif; font-size: 15px;">course titled<a href="https://www.udemy.com/a-simple-nodejs-api/" target="_blank"> </a></span><span style="color: #426e95; font-family: Arimo, sans-serif;"><span style="background: 0px 0px rgb(255, 255, 255); box-sizing: border-box; font-size: 15px;"><a href="https://www.udemy.com/a-simple-nodejs-api/" target="_blank">"A Simple Node.js/Mongo/Restify API in Less Than 3 Hours"</a></span></span><span style="background-color: white; color: #404040; font-family: Arimo, sans-serif; font-size: 15px;"> by Jim Hlad. I made a copy of the Node.js API sample app that was taught in the course and called it Cwitiq. This app would manage reviews instead of users. </span><br />
<span style="background-color: white; color: #404040; font-family: Arimo, sans-serif; font-size: 15px;"><br /></span>
<span style="background-color: white; color: #404040; font-family: Arimo, sans-serif; font-size: 15px;">A rough diagram of the code is depicted below. On the right, the directories for the various layers are shown. </span><br />
<span style="background-color: white; color: #404040; font-family: Arimo, sans-serif; font-size: 15px;"><br /></span>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtAQOq0XE8nSHzIfeSheUn9HXNbx-v08Vas9GTqv98KoKkEOqvUZXxLBBj7PHnechEvPs4-er9IC9MXSAsAwNEvbMdcIhBhE-YJsqHK-CsDabSyJZRKQxb-Zks9-38OVkdIUx1zCloSFA/s1600/CwitiqClassDiagram.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="720" data-original-width="1280" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtAQOq0XE8nSHzIfeSheUn9HXNbx-v08Vas9GTqv98KoKkEOqvUZXxLBBj7PHnechEvPs4-er9IC9MXSAsAwNEvbMdcIhBhE-YJsqHK-CsDabSyJZRKQxb-Zks9-38OVkdIUx1zCloSFA/s1600/CwitiqClassDiagram.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<ul style="text-align: left;">
<li>include (require) the restify, restify plugins, validator and mongoose modules</li>
<li>create a restify server using the createServer function</li>
<li>the config directory has the db connection and helper functions to provide responses (output, error etc.)</li>
<li>the models directory has the schema and model for storing the reviews in MongoDB using Mongoose</li>
<li>the business logic is in the reviewController that is present in the controllers directory along with setupController that utilizes Restify features to control APIs - authorization, whitelisting, throttling</li>
</ul>
<div>
I have been using this layout and code organization while creating other apps in Node.js.</div>
<br />
<span style="background-color: white; color: #404040; font-family: Arimo, sans-serif; font-size: 15px;"></span></div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-45425126614342825792017-10-31T15:34:00.000+05:302017-10-31T15:34:23.633+05:30Learning Node.js on Udemy<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
After a bit of a struggle, I finally would like to believe that I have become comfortable with Node.js. I had initially tried learning Node.js through the course titled <a href="https://www.udemy.com/understand-nodejs/" target="_blank">"Learn and Understand NodeJS"</a> on Udemy by Anthony Alicea. The course is a bit unconventional as it goes deep into the guts of Node.js right at the start instead of providing an overview. I lost interest in it after a few lectures and almost gave up learning Node.js.<br />
<br />
After a while, I decided to look for courses of shorter duration and found a course titled <a href="https://www.udemy.com/a-simple-nodejs-api/" target="_blank">"A Simple Node.js/Mongo/Restify API in Less Than 3 Hours"</a> by Jim Hlad. The USP of this course is that the lectures are of a short duration ~5-7 min. This helps in assimilating the content learned easily. The instructor explains the concepts while coding, instead of talking theory first, making the lectures short and crisp.<br />
<br />
This course helped me grasp the basics of Node.js and try out things such as Web Sockets using <a href="http://socket.io/">Socket.io</a>. It would be nicer if the instructor offers this course with Express or other more popular libraries instead of Restify. Also, it is worth noting that this course is aimed at building APIs using Node.js rather than a complete application thereby skipping the UI layer.<br />
<div>
<br /></div>
</div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-1509650658201494042017-05-05T22:50:00.000+05:302017-05-05T22:50:05.386+05:30First Look at Google's API.AI <div dir="ltr" style="text-align: left;" trbidi="on">
API.AI is a chatbot development platform bought by Google last September. This is one of the prominent chatbot development platforms along with Facebook's Wit.ai and Microsoft's BotFramework. What I found unique about API.AI is that you can build a basic bot without writing any code. All the development happens within the browser and you can test it there.<br />
<br />
So, what does it take to build a bot in API.AI?<br />
<br />
Here are the key concepts that you need to build a bot in API.AI.<br />
<br />
<b>Intents</b>: Intents are actions that perform a task and are defining them is usually the first step to build a bot. If I were to build a bot that gives me recommendations on tourist attractions. I would define intents such as recommendations for beaches, hill stations etc. So, a typical conversation could be:<br />
<br />
<blockquote class="tr_bq">
User: show me some beaches in India <br />
Bot: Here are some nice beaches - (may show pictures)</blockquote>
<br />
<b>Entities</b>: From the user's sentence above, beach would be identified as an entity. Hill station could be another. These would then be abstracted as an entity type called tourist attraction. This makes the conversation extensible as more entities and corresponding intents can be added. When the user requests a recommendation on beaches, the bot understands beach as a type of tourist attraction entity and invokes the beach recommendation intent. Again, no code is required to do this, just point and click to link the two.<br />
<br />
<b>Training</b>: Once the intents and entities are defined, the bot is to be trained. This can be done through the test console within the browser's "console", which is the DEV environment. Each conversation is logged, it can be reviewed and the erroneous responses corrected. Sometimes, the bots can behave pretty poorly. For instance,<br />
<br />
<blockquote class="tr_bq">
User: show me hills in India (instead of hill stations)<br />
Bot: I am sorry I did not understand that</blockquote>
<br />
To make the bot respond, hills need to be included in the synonym for the hill stations entity. All such synonyms need to be entered to ensure that the bot responds correctly. Once added, repeat the training and correct the errors till there are none.<br />
<br />
<b>Integration</b>: Once the bot is ready, it can be integrated with Facebook Messenger, Skype, Twitter, Slack, Google Assistant and many other platforms. Before making the bot public, the integrations make it easy to test the bot on the go through a mobile device.<br />
<br />
<b>Prebuilt Agents</b>: API.AI provides prebuilt agents that range from engaging in small talk to helping book restaurants, flights and control home appliances. These agents come with prebuilt intents and entities that you can use to start from instead of building from scratch.<br />
<br />
<b>Fulfillment</b>: In order to extend the functionality of bots such as invoking external APIs to check weather, make hotel bookings etc., API.ai provides integration capabilities through web hooks. Web hooks can point to external endpoints such as third party APIs or your own API hosted elsewhere.<br />
<br />
The bot can be hosted on API.AI itself or any other platform with support for node.js. The interaction with the bot could be using HTTP RESTful calls or through one of the many languages that are supported through the SDKs.<br />
<br />
Overall, I am impressed with the ease of use of the API.AI platform and will continue spending time with it in building a bot that can keep me amused :) </div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-32339875106527061442017-04-30T23:36:00.000+05:302017-04-30T23:36:06.670+05:30Nadget New Version Released!<div dir="ltr" style="text-align: left;" trbidi="on">
I released a new version of <a href="https://play.google.com/store/apps/details?id=in.pleb.nadget" target="_blank">Nadget</a> in the Google Play Store. It now supports notifications allowing the user to choose a time to be notified; on selecting the notification, the app opens and gets refreshed. There a few UI changes, a new icon and a rewritten drawer.<br />
<br />
Check out the screenshots below.<br />
<br />
The new icon designed using <a href="https://www.figma.com/files/recent" target="_blank">Figma</a>, an excellent online graphics editor with easy-to-use layers support.<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfTCrqpQrL8_JoolV18Z2eZA_NqMCNKeqbrQdxt_EmTaErHcokR2H1x0lB38kLskVQ1tvjzOilBbv5utk8YFbwFHfooIy-kxUw9vunYsusjKxTFIWcGrOqZXbQTGz5mGUIS0LFKP2MrIY/s1600/ic_launcher-web.png" imageanchor="1"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfTCrqpQrL8_JoolV18Z2eZA_NqMCNKeqbrQdxt_EmTaErHcokR2H1x0lB38kLskVQ1tvjzOilBbv5utk8YFbwFHfooIy-kxUw9vunYsusjKxTFIWcGrOqZXbQTGz5mGUIS0LFKP2MrIY/s200/ic_launcher-web.png" width="200" /></a><br />
Main screen with a shortcut menu to change to dark theme and get to settings<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBuYy_SbY765Y1gbED0vLCGd38qucWTRGXe5BxC9-xau57Rqh4tSqH5fi0IyTrY_1f4UxBuET4vik8g__xwZq5it6kjCaM3zYmjWYRLLOdRUNwwUHKLUMQe-2_kLnPEnYQYNK9qvCw_8I/s1600/main.png" imageanchor="1"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBuYy_SbY765Y1gbED0vLCGd38qucWTRGXe5BxC9-xau57Rqh4tSqH5fi0IyTrY_1f4UxBuET4vik8g__xwZq5it6kjCaM3zYmjWYRLLOdRUNwwUHKLUMQe-2_kLnPEnYQYNK9qvCw_8I/s400/main.png" width="215" /></a><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDxN5HAu9oCWvFsr-oeOPzGFlWraJ-eWKB8Iw_9pw3unB2rA3eTwX9LT65tBwGUkMnHPL7B9thnBC-u3JUlknRwEqS_rwQrxyaFsK3h-jek1PsljgBSdNPXwgicSiyTiXHwxdIjVS12WI/s1600/main-dark.png" imageanchor="1"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDxN5HAu9oCWvFsr-oeOPzGFlWraJ-eWKB8Iw_9pw3unB2rA3eTwX9LT65tBwGUkMnHPL7B9thnBC-u3JUlknRwEqS_rwQrxyaFsK3h-jek1PsljgBSdNPXwgicSiyTiXHwxdIjVS12WI/s400/main-dark.png" width="215" /></a><br />
Notifications<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoK8J_c0_5e86sQoBgZkbojLc3_-EYB6t0qdDRXydcHGyltxOcxP-U0NOl4rgqrggPuxd54CjHDn7FhHWPj4kBbYVqZTOeiHO7eZzaF5odZYHRjzXgjcKRFqN7LkT42FcnXpkyrXPOxdM/s1600/notifications.png" imageanchor="1"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoK8J_c0_5e86sQoBgZkbojLc3_-EYB6t0qdDRXydcHGyltxOcxP-U0NOl4rgqrggPuxd54CjHDn7FhHWPj4kBbYVqZTOeiHO7eZzaF5odZYHRjzXgjcKRFqN7LkT42FcnXpkyrXPOxdM/s400/notifications.png" width="215" /></a><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcHAuJWjaH_dZEFNRAx1L7RoGYcIUOfWuDnz_5lS15NT1wYLIknsydsWsQKU7i4YMSUYgJrLVPTRg5De4a8NHb3UTiPZhgwALjpPd_-jWuJ6JMxZHu6KN4llmTn5a37l7e015JlOfKPJI/s1600/settings-dark.png" imageanchor="1"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcHAuJWjaH_dZEFNRAx1L7RoGYcIUOfWuDnz_5lS15NT1wYLIknsydsWsQKU7i4YMSUYgJrLVPTRg5De4a8NHb3UTiPZhgwALjpPd_-jWuJ6JMxZHu6KN4llmTn5a37l7e015JlOfKPJI/s400/settings-dark.png" width="215" /></a><br />
The redesigned drawer<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTLVDicusSbi-m6wmhQcJUIVTbGyMsUgo8IuwOVT0Lv-CzRnZVnxrY7eFvbMTs_JwJp2Ouh4EM-ABeQPzLhAFR3m49avyiEBWD7rT3Lhi_3FaLkjN7znYuttoYcvpp_3Et7ptm6CTikac/s1600/drawer-dark.png" imageanchor="1"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTLVDicusSbi-m6wmhQcJUIVTbGyMsUgo8IuwOVT0Lv-CzRnZVnxrY7eFvbMTs_JwJp2Ouh4EM-ABeQPzLhAFR3m49avyiEBWD7rT3Lhi_3FaLkjN7znYuttoYcvpp_3Et7ptm6CTikac/s400/drawer-dark.png" width="215" /></a><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqXTGYxnyPtdIz0tkAcrYCNl0iTwHPP73MRncPeQLtygETShUx_T4-u6zymeZVGWoIAWGuMPiZlrzn6WATol6dThzNTbO12JImKSrKLwewZH1ByVPRv0p1Zmyjn3vRfz3Mqe0lJW3s-tA/s1600/drawer.png" imageanchor="1"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqXTGYxnyPtdIz0tkAcrYCNl0iTwHPP73MRncPeQLtygETShUx_T4-u6zymeZVGWoIAWGuMPiZlrzn6WATol6dThzNTbO12JImKSrKLwewZH1ByVPRv0p1Zmyjn3vRfz3Mqe0lJW3s-tA/s400/drawer.png" width="215" /></a><br />
<br />
<br />
<br /></div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-79413244845251620802017-04-09T15:06:00.000+05:302017-04-09T15:06:16.292+05:30Is GraphQL the SQL of the Web?<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
I was told by a friend that GraphQL was the next big thing, I wondered why and decided to take a look at it. GraphQL developed by Facebook, provides a SQL-like access to REST resources. Consider the following snippet:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">{</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> customer(id: "1140") {</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> name</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> type</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
This will provide the name and type of the customer with id 1140. In a traditional REST based setup, one would have to make two calls, to get the name and the type of the customer. Or would get a full customer object and then parse it to extract the fields. In GraphQL, we can specify the fields needed in the query and get it in one call. This would reduce the number of requests and consequently the load on the server.<br />
<br />
GraphQL features Fragments where two queries are executed to get details, such as for comparison, has its own schema with data types, Unions, abstract types and more.<br />
<br />
<b>Sounds good. How do we get started? </b><br />
<br />
There are a few libraries available that help handle the server side conversation. <a href="https://facebook.github.io/relay/" target="_blank">Relay </a>from Facebook and <a href="http://dev.apollodata.com/react/" target="_blank">React Apollo</a> are some of the popular ones. For more, check out the <a href="http://graphql.org/code/" target="_blank">GraphQL</a> site.<br />
<br />
While it may seem like too much of work changing the server side to start using GraphQL, it would definitely make sense to do so where the number of calls are high and of a relational nature. The GraphQL spec is currently a working draft but a few early adopters have already started using it in production. Enterprise adoption might take a while to do so. But once they do, it will most likely become the SQL of the web.</div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-51274192587311240712017-03-17T10:04:00.001+05:302017-03-17T10:05:52.243+05:30Building Bots with Bottr<div dir="ltr" style="text-align: left;" trbidi="on">
It has been a while since I posted to this blog. What have I been up to? I have been looking at some chatbot frameworks, <a href="http://bottr.co/" target="_blank">Bottr</a> being one of them. Bottr is a simple JavaScript framework that allows you to quickly build a chatbot. It runs on node.js and can be tested on your local desktop.<br />
<br />
Bottr is available as a npm module. After installing the module, you can use it like so<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">var Bottr = require('bottr');</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">var BottrApp = require('bottr-app');</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">var bot = new Bottr.Bot();</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">//BottrApp for local server</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">bot.use(new BottrApp());</span><br />
<br />
It has functions to listen to messages received and do some processing. The function below will fire on each message and when done with processing, will invoke the next function using the next() function.<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">bot.on('message_received', function(message, session, next) {</span><br />
<div style="text-align: left;">
<span style="font-family: "courier new" , "courier" , monospace;"> //function code here</span></div>
<div style="text-align: left;">
<span style="font-family: "courier new" , "courier" , monospace;"> //invoke other handlers to process the message</span></div>
<div style="text-align: left;">
<span style="font-family: "courier new" , "courier" , monospace;"> next();</span></div>
<div style="text-align: left;">
<span style="font-family: "courier new" , "courier" , monospace;">}</span></div>
<br />
It also has functions that can listen to specific message types/patterns and respond. The function below listens to all messages and echoes them back using the send function. The listen function at the end starts the bot to listen.<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">bot.hears([/.+/], function(message, session) {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> // Echo the user's message </span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> session.send(message.text)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">});</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">bot.listen();</span><br />
<br />
The framework's documentation provides clear instructions on deploying the code in Heroku and integrating with Facebook Messenger. Within a matter of minutes, I was available to deploy the code and use it in Facebook Messenger. However, as the framework is relatively new, the documentation is not exhaustive. This makes it a bit tough to use the framework for building complex bots. As the framework gains popularity and more people start using it, hopefully the documentation will also mature. And we can see more bots built using Bottr. </div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-71191790755300964852016-09-11T16:09:00.000+05:302016-09-11T16:09:02.700+05:30Nadget New Version Available!<div dir="ltr" style="text-align: left;" trbidi="on">
I released a new version of Nadget on Google Play yesterday. The new version features a dark theme for easy reading at night and an option to switch off image loading in the main list (useful if you have a bad connection or want to conserve data).<br />
<br />
Do check it out on <a href="https://play.google.com/store/apps/details?id=in.pleb.nadget&rdid=in.pleb.nadget" target="_blank">Google Play</a>, or <a href="https://www.amazon.com/Nadget-Gadget-and-Mobile-News/dp/B01LBKYFXK" target="_blank">Amazon Appstore for Android</a> or <a href="http://www.getjar.com/categories/news-and-weather-apps/more-news-apps/Nadget-Gadget-and-Mobile-News-899865" target="_blank">GetJar</a><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihQ0QPForEAtjot5ryQfYx0DAoiVJoqoQyNGwLBPG8juHKSqUQjgIj7LSowllMkIwUnaEcrh6sAA_z1Rlrg_Njlskd7rY714_K_E8LXIdArHduYnEgV7HCZVxYpWNlNOjs39uzzsPxt-A/s1600/main-dark.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihQ0QPForEAtjot5ryQfYx0DAoiVJoqoQyNGwLBPG8juHKSqUQjgIj7LSowllMkIwUnaEcrh6sAA_z1Rlrg_Njlskd7rY714_K_E8LXIdArHduYnEgV7HCZVxYpWNlNOjs39uzzsPxt-A/s320/main-dark.png" width="196"/></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTbQ6KnE-YETgzbJkzz8xjeqxjXnL4qjJWWyUESyYMui1rjN5dU9wL2Pu6qU34Rvdi4Jf9ORLsnf9QCSKbW3JikQ46rHT732o2tMhZtX0mbR4bgFDtXHy3yiqaa63CAmmideayFdP4qL0/s1600/main-dark-tab.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTbQ6KnE-YETgzbJkzz8xjeqxjXnL4qjJWWyUESyYMui1rjN5dU9wL2Pu6qU34Rvdi4Jf9ORLsnf9QCSKbW3JikQ46rHT732o2tMhZtX0mbR4bgFDtXHy3yiqaa63CAmmideayFdP4qL0/s320/main-dark-tab.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOAjCb3d7kQbanqGf_fqjdyZqb8nEP0nZlM8dkQslATiF_el-hpoDpwo-CYFr0u_EkD9dCVJFyffCTCL2nP_aQwozJfxQtF9aVqIWNJUtXkciTohrHlXcdMhusGcHTlorU1hOMHK6xPkQ/s1600/settings.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOAjCb3d7kQbanqGf_fqjdyZqb8nEP0nZlM8dkQslATiF_el-hpoDpwo-CYFr0u_EkD9dCVJFyffCTCL2nP_aQwozJfxQtF9aVqIWNJUtXkciTohrHlXcdMhusGcHTlorU1hOMHK6xPkQ/s320/settings.png" width="196" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
<br />
<br />
<br /></div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-32017064319334727632016-09-02T18:03:00.001+05:302016-09-02T18:03:15.899+05:30ELK for Data Analysis<div dir="ltr" style="text-align: left;" trbidi="on">
Apps that mine data and provide insights are very popular as they help in planning the next course of action. Trend analysis, sentiment analysis, event prediction etc. are common applications of data mining. As they say, data is the next oil.<br />
<br />
ELK stack comprising of Elasticsearch, Logstash and Kibana is a popular stack to analyze data. In a nutshell:<br />
<br />
<ul style="text-align: left;">
<li>Logstash gathers data from structured and unstructured sources</li>
<li>Elasticsearch indexes and keeps it ready for searching</li>
<li>Kibana uses the data for visualization </li>
</ul>
<br />
After installation, a few quick tasks that one would do to get started with the stack are:<br />
<br />
<ul style="text-align: left;">
<li>Load data (log files/JSON/anything) using the Logstash conf file into Elasticsearch (default port:9200) </li>
<ul>
<li>the conf file should include input, filter (blank is okay) and output</li>
<li>the input block can be file, twitter, or any of the several sources that Logstash supports</li>
<li>the Elasticsearch block in the output block should include the index name (this will match inside Kibana)</li>
</ul>
<li>In Kibana (default port:5601), create the index using the index name mentioned above</li>
<li>Go to Discover and select new search, this will throw some results. If it does not, then change the time range until results are shown</li>
<li>Next, go to Visualize - and create a visualization</li>
<li>Inside the visualization, select the index that you created, select some fields from inside the indexed schema and you are done!</li>
</ul>
<br />
Some of the common commands used are:<br />
To list indices <span style="font-family: Courier New, Courier, monospace;"> http://localhost:9200/_cat/indices?v</span><br />
To delete an index <span style="font-family: Courier New, Courier, monospace;">curl -XDELETE localhost:9200/shakespeare</span><br />
To check Elasticsearch version <span style="font-family: Courier New, Courier, monospace;">curl -XGET localhost:9200</span><br />
<div>
<br /></div>
</div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-47251098335445418932016-08-13T15:42:00.000+05:302016-08-13T15:42:20.874+05:30Promoting Android Apps for Free<div dir="ltr" style="text-align: left;" trbidi="on">
I always thought that realizing an idea into code was the toughest part of app development. Having completed development and <a href="https://play.google.com/store/apps/details?id=in.pleb.nadget" target="_blank">published</a> the app in the Play store, I realize that promoting an app is no mean task. With little or no promotion, the app is just a drop in the ocean in the Play store. More so, if you are offering an app with no ads. In the past few weeks, while I have been trying to publicize <a href="https://play.google.com/store/apps/details?id=in.pleb.nadget" target="_blank">my app</a> for free, I found the following resources useful:<br />
<br />
<ul style="text-align: left;">
<li><a href="http://cpimobi.com/" target="_blank">cpimobi.com</a> gives 50 free installs of your app, thereafter you would be charged per install. This is a good place to start with.</li>
<li>There are many review exchange sites such as <a href="http://reviewsmotion.com/" target="_blank">ReviewsMotion </a>and <a href="https://android.favorr.io/" target="_blank">Favorr </a>that help developers review each others' apps. Developers join these sites and list their apps. You select an app to review, use it and publish a review in the Play store. The user whose app was reviewed is notified and does the same. </li>
<li><a href="http://forum.xda-developers.com/android/apps-games/app-nadget-t3425802" target="_blank">XDA </a>is considered a forum for Android experts. Several developers visit the forum to list and check out apps. You can create a thread and submit your app <a href="http://forum.xda-developers.com/android/apps-games/app-nadget-t3425802" target="_blank">there</a> </li>
<li><a href="http://www.appszoom.com/android-app/nadget-wpqff.html" target="_blank">Appszoom </a>is an app aggregation site that lists the apps with a good summary page </li>
</ul>
<div>
<br /></div>
<div>
Apart from the above, do not forget to list or promote your app in the usual social media sites: Twitter, Facebook and Google Plus.</div>
<ul style="text-align: left;">
<li>Send out a tweet announcing your app: if you have many followers, then this might be effective </li>
<li>Facebook and <a href="https://plus.google.com/+DaneshZaki/posts/jAmTAhN4K43" target="_blank">Google Plus</a> Android groups: there are too many of them, pick the one with the most recent activities and post there</li>
<li>If you have developed using Android Material design, you can submit it in the <a href="https://plus.google.com/+DaneshZaki/posts/4GuTMrXaRon" target="_blank">Google Plus Material Style Apps</a> group. If you have joined <a href="http://blog.pleb.in/2016/08/nadget-featured-in-materialup.html" target="_blank">MaterialUp</a>, a site for promoting Material design, listing your app in this group might lead it to be <a href="http://blog.pleb.in/2016/08/nadget-featured-in-materialup.html" target="_blank">featured </a>in the site. </li>
</ul>
<br />
Never forget to track threads and comments in the groups and forums where you have your app listed. People hate non-responsive developers who are cold to bugs or feedback.<br />
<br /></div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-8247849665539589152016-08-06T22:22:00.000+05:302016-08-19T11:33:02.728+05:30Nadget Featured in MaterialUp!<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeQCZl8fSlyVF8ZTyKdQwduPb_5yMcD-nRgkfLkqSq5_5zNdeAQ3nuzQSwiGbmw8EsXxe1bhMfJRJyxV-rdwTtKDAb36I9TvVTcJ9FGtRbOhF5IGuL2YJ0uxTqHw1EgRjNF27oN1nwH8w/s1600/nadget-512-icon.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeQCZl8fSlyVF8ZTyKdQwduPb_5yMcD-nRgkfLkqSq5_5zNdeAQ3nuzQSwiGbmw8EsXxe1bhMfJRJyxV-rdwTtKDAb36I9TvVTcJ9FGtRbOhF5IGuL2YJ0uxTqHw1EgRjNF27oN1nwH8w/s200/nadget-512-icon.png" width="200" /></a></div>
<br />
<a href="https://play.google.com/store/apps/details?id=in.pleb.nadget" target="_blank">Nadget </a>has been featured on <a href="http://www.materialup.com/posts/nadget-android-app" target="_blank">MaterialUp </a>- a site that showcases apps, UI kits, icons and other UX components built following Material design guidelines. This is a great a honor to me as I have looked to MaterialUp for inspiration while designing the app. Do checkout the <a href="http://www.materialup.com/posts/nadget-android-app" target="_blank">site</a>. <br />
<br />
<br /></div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-18191461269422830412016-08-03T22:32:00.001+05:302016-08-03T22:32:14.754+05:30Nadget - Curated Indian Gadget & Tech News<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguGsHYH0EdxVxfzhK9gKqUSAkJyPIyMyBKIHytJCV_A5wUstvVBafD_d7szwR0hUE5S18pcWf0SqphK_78rlbfkw3FrM2EC_67zhyphenhyphen2wJmkQhu0ZKS3VFK0SCJpMOqmXevtv0jnALzsggU/s1600/mainscreen.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguGsHYH0EdxVxfzhK9gKqUSAkJyPIyMyBKIHytJCV_A5wUstvVBafD_d7szwR0hUE5S18pcWf0SqphK_78rlbfkw3FrM2EC_67zhyphenhyphen2wJmkQhu0ZKS3VFK0SCJpMOqmXevtv0jnALzsggU/s320/mainscreen.png" width="196" /></a></div>
<br />
After months of development, I finally completed and published my app, <a href="https://play.google.com/store/apps/details?id=in.pleb.nadget" target="_blank">Nadget on Google Play</a>. The app offers a selection of feeds from Indian gadget and technology sites. The UI follows Material design guidelines and provides for an uninterrupted reading experience.<br />
<br />
Posts can be shared or saved for later reading. I have also integrated with Dropbox to export the list of selected feeds and saved articles in case you are moving to a new device or restoring from a hard reset. For users who would like to suggest other feeds, I have included an option to do so.<br />
<div>
<br />
I have not included any ads as this was developed as a hobby. The app is available for download on <a href="https://play.google.com/store/apps/details?id=in.pleb.nadget" target="_blank">Google Play</a>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJdbY3xyi0UMnHnORi8Jw86mCHl5fpW_Znbs3KQ_Kil82nx1fqA8qs9qt9hP4WOicCdx5sZ1gGkcts3AQDSVlLDJsvwP_81CLGgS9czYqz4gLS_Tz4EABCy0EFz3pvHdjrna6s4wjzUsA/s1600/drawer.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJdbY3xyi0UMnHnORi8Jw86mCHl5fpW_Znbs3KQ_Kil82nx1fqA8qs9qt9hP4WOicCdx5sZ1gGkcts3AQDSVlLDJsvwP_81CLGgS9czYqz4gLS_Tz4EABCy0EFz3pvHdjrna6s4wjzUsA/s320/drawer.png" width="196" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjW4eUdsT-7e5XGke-NOrHYXedfWFXQKfTjsLb8c3Npm4WRXADIqWBwNTom22UdXD2wBMPBFvHgNVvtBEtXQhEDdMLv1EldyCM2d5A2OG9s7hE1HGDVPCYxMfBY0u8opK-uPTJ-82tiQb4/s1600/savedarticles.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjW4eUdsT-7e5XGke-NOrHYXedfWFXQKfTjsLb8c3Npm4WRXADIqWBwNTom22UdXD2wBMPBFvHgNVvtBEtXQhEDdMLv1EldyCM2d5A2OG9s7hE1HGDVPCYxMfBY0u8opK-uPTJ-82tiQb4/s320/savedarticles.png" width="196" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqcoMZaeaL4W1WAS1kXaSxH7HIqevhIpKHi9RgSjv0vwHRaZwY9ubCwXHldQn_RL5fzB4X02AetHv8SFf51r6r-PqX_MHBMzYPBHh8Wfpz8EUvJxQbeG7HVH1NRdDLfqssqpRaqsANwSs/s1600/selectedfeeds.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqcoMZaeaL4W1WAS1kXaSxH7HIqevhIpKHi9RgSjv0vwHRaZwY9ubCwXHldQn_RL5fzB4X02AetHv8SFf51r6r-PqX_MHBMzYPBHh8Wfpz8EUvJxQbeG7HVH1NRdDLfqssqpRaqsANwSs/s320/selectedfeeds.png" width="196" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6Gb5HF35Ol7G9D5EGiw9LcpOg4K4aoPeUy5dZBkE-rqOKzelUxTaAhyc4GMJmcQ1klNu7dzlS8fXQuMGaVFryQEAd6HEUEPETXw_r6_mdjHlDA_G8Eq_v8igJNcqIWceA-uYP1ysBRZE/s1600/settings.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6Gb5HF35Ol7G9D5EGiw9LcpOg4K4aoPeUy5dZBkE-rqOKzelUxTaAhyc4GMJmcQ1klNu7dzlS8fXQuMGaVFryQEAd6HEUEPETXw_r6_mdjHlDA_G8Eq_v8igJNcqIWceA-uYP1ysBRZE/s320/settings.png" width="196" /></a></div>
<br /></div>
</div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-50622605508430619982016-07-30T16:04:00.000+05:302017-05-02T15:08:10.292+05:30Google Play Android App Publishing Tips <div dir="ltr" style="text-align: left;" trbidi="on">
Coding done, testing done, testing on multiple devices done. What next? Publishing the app on the Google Play store. Publishing on the Play store is not a complex process but it is helpful to be prepared about a few things. Publishing is done through the Google Play Developer Console and the process is straightforward.<br />
<br />
<ul style="text-align: left;">
<li>After paying the fees of 25$, you enter the app details and upload its APK file. The device compatibility of the app will be shown. </li>
<li>The next step is the most important: store listing. This is how the world will see your app. </li>
<ul>
<li><b>Fill the short description </b>- keep it <b>catchy </b>to interest the user; if you can't, then keep it <b>short </b></li>
<li><b>Fill the full description</b> - while there is no fixed format, it is better to enter <b>bullets </b>here instead of paragraphs. There is no automatic bulleting so add hyphens at the beginning of each point. As with screenshots, remember to keep the important points at the top </li>
<li><b>Upload the app's screenshots </b>- make sure to <b>highlight the main screen and the best parts </b>of the app (if you are building for tablets, you have to upload separate screenshots in tablet form)</li>
<li><b>Upload a high resolution icon (512x512)</b> - It is never enough to emphasize the importance of a good app icon in high resolution as this is the face of the app, even before it is downloaded. <a href="http://romannurik.github.io/AndroidAssetStudio/" target="_blank">Roman Nurik's Android Asset Studio</a> was used to create the app's launcher icon and it generates icons similar to Google's own apps</li>
<li><b>Upload a feature graphic</b> in JPG or PNG of size 1024 x 500 dimensions - be creative and add any messages that you want to highlight; this is like a banner ad. <a href="http://www.norio.be/android-feature-graphic-generator/" target="_blank">Norio's Android Feature Graphic Generator</a> is easy to use and was used to create the feature graphic </li>
<li><b>Upload a promo graphic </b>in JPG or PNG of dimensions 180 x 120- a smaller one which is probably used in older Play stores</li>
<li><b>Upload a promo video</b> uploaded to YouTube - a simple way to create a promo video is using the adb. Connect your device to a PC, then on a command shell type the command: <span style="background-color: whitesmoke; color: #333333; font-size: 13px; line-height: 1.42857;">adb shell screenrecord /sdcard/videos/demo.mp4 </span>and run your app on your device. A video of your screenshots will be recorded and stored in the location mentioned.The video should be uploaded to youtube and the link should be provided. Note that the full youtube link such as <a href="https://www.youtube.com/watch?v=cpUPzmlh7PA" target="_blank">https://www.youtube.com/watch?v=cpUPzmlh7PA </a>should be entered instead of <a href="https://youtu.be/cpUPzmlh7PA">https://youtu.be/cpUPzmlh7PA</a>. This is important otherwise your video will not appear on Play.</li>
<li>While the video and promo graphic are optional, it is important to upload them as they help in marketing the app. </li>
</ul>
<li>If you are app supports multiple languages, do the steps above for each of the language that it supports </li>
<li>The next step is to complete a questionnaire on the content of the app which generates the rating of the app. </li>
<li>Finally choose the category for the app, fill your contact details and submit.</li>
</ul>
<br />
My <a href="https://play.google.com/store/apps/details?id=in.pleb.nadget" target="_blank">app Nadget</a>, was live within a few hours of publishing of it. Some users have said that it could take a few days too. This is dependant on the permissions that the app requests and possibly its content rating. In most cases, the app should be live on the Google Play Store in less than half a day. But make sure you spend time in creating the promotional graphics so that your app gets the attention it deserves in the Google Play store.<br />
<br />
<br />
<br />
<br />
<br />
<div>
<br /></div>
</div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com1tag:blogger.com,1999:blog-5923887751969898671.post-47986383073679840212016-07-23T16:00:00.000+05:302016-07-23T16:00:13.835+05:30App Integration with Dropbox<div dir="ltr" style="text-align: left;" trbidi="on">
Storing user data on a location other than the device has become a mandatory for a few years now. There are many options to do so and one of the quick and easy ones is using Dropbox. I integrated my app with Dropbox to allow users to store their Preferences (Shared Preferences). This would help them to continue using the app easily when they switch to a different device or reset the current one. While Dropbox provides fairly detailed <a href="https://www.dropbox.com/developers-v1/core/start/android" target="_blank">instructions</a> to do the integration, I would like to share a summarize the steps and add a few points to keep in mind:<br />
<br />
The steps to integrate with Dropbox are:<br />
<br />
<br />
<ol style="text-align: left;">
<li>Register for an app with Dropbox at the <a href="https://www.dropbox.com/developers-v1/apps" target="_blank">app console</a> to get an app key and secret </li>
<li>Download the <a href="https://www.dropbox.com/developers-v1/core/sdks/android" target="_blank">Dropbox Android SDK</a>. A zip containing the jar file is provided. The jar has to be added to the project in the Android Studio. It is a bit disappointing that there is no Gradle option available yet.</li>
<li>Copy paste the following code in the AndroidManifest.xml:</li>
<div style="text-align: left;">
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: "courier new" , "courier" , monospace;"><activity</span></div>
<span style="font-family: "courier new" , "courier" , monospace;"><div style="text-align: left;">
android:name="com.dropbox.client2.android.AuthActivity"</div>
<div style="text-align: left;">
android:launchMode="singleTask"</div>
<div style="text-align: left;">
android:theme="@android:style/Theme.Translucent.NoTitleBar"</div>
<div style="text-align: left;">
android:configChanges="orientation|keyboard"></div>
<div style="text-align: left;">
<intent-filter></div>
<div style="text-align: left;">
<!-- Change this to be db- followed by your app key --></div>
<div style="text-align: left;">
<data android:scheme="db-INSERT_APP_KEY" /></div>
<div style="text-align: left;">
<action android:name="android.intent.action.VIEW" /></div>
<div style="text-align: left;">
<category android:name="android.intent.category.BROWSABLE"/></div>
<div style="text-align: left;">
<category android:name="android.intent.category.DEFAULT" /></div>
<div style="text-align: left;">
</intent-filter></div>
<div style="text-align: left;">
</activity></div>
</span><br />
This will either open the Dropbox app (if you have it installed on your app) or open the Dropbox page on Chrome/browser for authentication.<br />
<br />
<li>In the code, you need to perform authentication which will invoke the activity listed above. Then you can use the Dropbox API to either put or get files from the user's Dropbox. A folder with the app name is created once the user authenticates the app in step 3. The code snippets are provided <a href="https://www.dropbox.com/developers-v1/core/start/android" target="_blank">here</a>.</li>
</ol>
<br />
<b>Points to Note</b><br />
<ul style="text-align: left;">
<li>Dropbox user authentication and app authorization call can be on the main thread. The <span style="font-family: Courier New, Courier, monospace;"><b>onResume </b></span>method of the activity becomes very important here as the control returns to that method once the authorization process is complete. So, any processing post authentication should start from onResume.</li>
<li>Reading and writing files to Dropbox are network activities and Android will throw an exception when you do this on the main thread. You need to use an <b><span style="font-family: Courier New, Courier, monospace;">AsyncTask </span></b>to do these tasks. I have used two <b><span style="font-family: Courier New, Courier, monospace;">AsyncTasks </span></b>to do read and write to Dropbox respectively. Both these are called from the <b><span style="font-family: Courier New, Courier, monospace;">onResume </span></b>method. If called from elsewhere, a <span style="font-family: Courier New, Courier, monospace;"><b>DropboxUnlinkedException </b></span>will be thrown.</li>
<li>If the Dropbox API's <b><span style="font-family: Courier New, Courier, monospace;">putFile </span></b>method is used to add files to the user's Dropbox, it will create multiple files with the same name, such as Prefs1, Prefs2 etc. If you would rather have only one file, then <span style="font-family: Courier New, Courier, monospace;"><b>putFileOverwriteRequest </b></span>should be used.</li>
</ul>
The post here summarizes the points from the Dropbox Android tutorial and a few other points that I found during the implementation. Following the steps here should help you integrate with Dropbox without much difficulty.<br />
<br /></div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-74747932169035813492016-05-15T16:50:00.000+05:302016-05-15T16:52:21.691+05:30Extracting the Main Image from an Article/Web Page<div dir="ltr" style="text-align: left;" trbidi="on">
For an app that I am building, I have been looking to extract the main image for an article from a webpage. Search on the net indicated that <a href="http://jsoup.org/" target="_blank">JSoup </a>was probably <b>"the"</b> library to do it. But it too does not mention how to get the main image associated with the article. Any modern webpage has several images in it - advertising banners, site logo, social media sharing icons, article related images and more advertising. How do we extract the main image from an article? I was not willing to think and write code to do this; partly because I am lazy and also because I knew that this was done before and code should be available for this.<br />
<br />
My initial search took me to <a href="https://market.mashape.com/explore" target="_blank">Mashape</a>. Searching through the APIs there, I found the free <a href="https://market.mashape.com/adlegant/article-analysis" target="_blank">Article Analysis API by adlegant</a>. While not required, I also decided to use the <a href="http://unirest.io/java.html" target="_blank">Unirest Java library by Mashape</a> to access the API. My initial tests with the API were all positive, a simple call to the API endpoint with the URL to be analyzed and the credentials provided by Mashape was all that was required. It provided a JSON response similar to the one below:<br />
<span style="background-color: #f3f3f3;"><br /></span>
<br />
<pre class="ps-container ps-active-x ps-active-y" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: 0px 0px; background-repeat: initial; background-size: initial; border-radius: 4px; border: none; box-sizing: border-box; color: #f0f2f3; font-family: 'Source Code Pro', 'Courier New', monospace; font-size: 14px; height: 986px; line-height: 1.42857; overflow: hidden; padding: 0px; position: relative; word-break: break-all; word-wrap: normal;"><span style="background-color: #f3f3f3;">{
"<span class="hljs-attribute" style="box-sizing: border-box; color: #b58900;">author</span>": <span class="hljs-value" style="box-sizing: border-box;">[
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"Verge Staff"</span>
]</span>,
"<span class="hljs-attribute" style="box-sizing: border-box; color: #b58900;">categories</span>": <span class="hljs-value" style="box-sizing: border-box;">[
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"economy, business and finance"</span>
]</span>,
"<span class="hljs-attribute" style="box-sizing: border-box; color: #b58900;">cleaned_text</span>": <span class="hljs-value" style="box-sizing: border-box;"><span class="hljs-string" style="box-sizing: border-box; color: #468966;">"Black Friday is right around the corner, and there are plenty of great deals to be had. We've been covering the deals for weeks now, but if you want to cut through the mess and just score the best deals you can find, you've come to the right place.\n\nAs to be expected, this year there are lots of deals to be had on TVs small and large, 1080p to 4K. You can also get a great price on last year's iPads, which are still better tablets than pretty much anything save for this year's iPads. If you're in the market for a smartwatch or fitness tracker, you can save some money on some really great options this weekend. And if you want to pick up a laptop or new headphones, there are deals to be found too.\n\nKeep in mind that the best deals won't last long and many of them are limited to Friday itself (or in rare occasions, Thursday too). To win the Black Friday game, you have to be aggressive and quick, there's no time to sleep when deals are to be had. That said, here are the 20 best Black Friday deals this year. Warm up your credit cards and get a good night's sleep, it's time to make the consumer machine work."</span></span>,
"<span class="hljs-attribute" style="box-sizing: border-box; color: #b58900;">date</span>": <span class="hljs-value" style="box-sizing: border-box;"><span class="hljs-string" style="box-sizing: border-box; color: #468966;">"2014-11-26T19:15:45Z"</span></span>,
"<span class="hljs-attribute" style="box-sizing: border-box; color: #b58900;">entities</span>": <span class="hljs-value" style="box-sizing: border-box;">[
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"Warm"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"Black"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"TVs"</span>
]</span>,
"<span class="hljs-attribute" style="box-sizing: border-box; color: #b58900;">image</span>": <span class="hljs-value" style="box-sizing: border-box;"><span class="hljs-string" style="box-sizing: border-box; color: #468966;">"https://cdn1.vox-cdn.com/thumbor/IkFo5ddhDEXA2t_mUfezCdvGbUI=/35x0:606x381/1280x854/cdn0.vox-cdn.com/uploads/chorus_image/image/44236174/black-friday-branding-jc3.0.png"</span></span>,
"<span class="hljs-attribute" style="box-sizing: border-box; color: #b58900;">language</span>": <span class="hljs-value" style="box-sizing: border-box;"><span class="hljs-string" style="box-sizing: border-box; color: #468966;">"en"</span></span>,
"<span class="hljs-attribute" style="box-sizing: border-box; color: #b58900;">link</span>": <span class="hljs-value" style="box-sizing: border-box;"><span class="hljs-string" style="box-sizing: border-box; color: #468966;">"http://www.theverge.com/2014/11/26/7292895/best-black-friday-deals"</span></span>,
"<span class="hljs-attribute" style="box-sizing: border-box; color: #b58900;">main_body</span>": <span class="hljs-value" style="box-sizing: border-box;"><span class="hljs-string" style="box-sizing: border-box; color: #468966;">"<div class=\"m-article__entry\" gravityScore=\"204\" gravityNodes=\"3\"><p>Black Friday is right around the corner, and there are plenty of great deals to be had. We've been&#160;covering the deals for weeks now, but if you want to cut through the mess and just score the best deals you can find, you've come to the right place.</p>&#13;\n<p>As to be expected, this year there are lots of deals to be had on TVs small and large, 1080p to 4K. You can also get a great price on last year's iPads, which are still better tablets than pretty much anything save for this year's iPads. If you're in the market for a smartwatch or fitness tracker, you can save some money on some really great options this weekend. And if you want to pick up a laptop or new headphones, there are deals to be found too.</p>\n \n&#13;\n<p>Keep in mind that the best deals won't last long and many of them are limited to Friday itself (or in rare occasions, Thursday too). To win the Black Friday game, you have to be aggressive and quick, there's no time to sleep when deals are to be had. That said, here are the 20 best Black Friday deals this year. Warm up your credit cards and get a good night's sleep, it's time to make the consumer machine work.</p>&#13;\n &#13;\n &#13;\n &#13;\n &#13;\n &#13;\n &#13;\n \n \n\n </div>\n "</span></span>,
"<span class="hljs-attribute" style="box-sizing: border-box; color: #b58900;">summary</span>": <span class="hljs-value" style="box-sizing: border-box;">[
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"That said, here are the 20 best Black Friday deals this year."</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"Black Friday is right around the corner, and there are plenty of great deals to be had."</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"We've been covering the deals for weeks now, but if you want to cut through the mess and just score the best deals you can find, you've come to the right place."</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"Keep in mind that the best deals won't last long and many of them are limited to Friday itself (or in rare occasions, Thursday too)."</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"To win the Black Friday game, you have to be aggressive and quick, there's no time to sleep when deals are to be had."</span>
]</span>,
"<span class="hljs-attribute" style="box-sizing: border-box; color: #b58900;">tags</span>": <span class="hljs-value" style="box-sizing: border-box;">[
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"best deals"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"laptop"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"expected year"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"said 20"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"sleep"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"best"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"nights"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"20"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"tracker"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"black"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"friday game"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"time make"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"save"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"mess"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"right corner"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"friday"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"really great"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"save money"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"year ipads"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"friday deals"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"great"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"headphones"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"deals"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"best black"</span>,
<span class="hljs-string" style="box-sizing: border-box; color: #468966;">"black friday"</span>
]</span>,
"<span class="hljs-attribute" style="box-sizing: border-box; color: #b58900;">text_sentiment</span>": <span class="hljs-value" style="box-sizing: border-box;">{
"<span class="hljs-attribute" style="box-sizing: border-box; color: #b58900;">sentiment</span>": <span class="hljs-value" style="box-sizing: border-box;"><span class="hljs-number" style="box-sizing: border-box; color: #468966;">0.2986327561327561</span></span>,
"<span class="hljs-attribute" style="box-sizing: border-box; color: #b58900;">subjectivity</span>": <span class="hljs-value" style="box-sizing: border-box;"><span class="hljs-number" style="box-sizing: border-box; color: #468966;">0.4551911976911977</span></span>,
"<span class="hljs-attribute" style="box-sizing: border-box; color: #b58900;">word</span>": <span class="hljs-value" style="box-sizing: border-box;"><span class="hljs-string" style="box-sizing: border-box; color: #468966;">"positive"</span>
</span>}</span>,
"<span class="hljs-attribute" style="box-sizing: border-box; color: #b58900;">title</span>": <span class="hljs-value" style="box-sizing: border-box;"><span class="hljs-string" style="box-sizing: border-box; color: #468966;">"The 20 best Black Friday deals"</span>
</span>}</span></pre>
<br />
It perfectly extracts the main image associated with the article and provides the link. All one needs to do is to use the<span style="font-family: "courier new" , "courier" , monospace;"> org.json </span>package and get the image's value. Nice and clean!<br />
<br />
But... as I was testing the API inside the app for extracting the images, I found that most of the time it was unavailable. I agree that it is free and there should be no expectation from my side, yet I felt that the downtime was too much. As I type this post, I see that it seems to fail for a few URLs that are perfectly valid. While Mashape provides some basic support for even free APIs, I did not utilize it.<br />
<br />
Instead, I decided to go with a parser based code to get the main image. I found a class called <a href="https://gist.github.com/Daenyth/4742267" target="_blank">ImageExtractor</a> by <a href="https://github.com/Daenyth" target="_blank">Gavin Bisesi (Daenyth)</a> written using JSoup. The code employs the technique used by Google Plus to extract images from shared URLs. It does the job well and there is no dependency on external API endpoints.<br />
<br />
While there would be many options available to scrape webpages and get the images, JSoup will probably be the primary option and APIs would be the next. If you are short on time and willing to spend, paid APIs maybe an option. If not, you would have to try out classes such as the one listed above to get the job done.<br />
<br /></div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-11817254019636068962016-04-14T15:32:00.003+05:302016-04-14T15:32:58.785+05:30CardView Basics<div dir="ltr" style="text-align: left;" trbidi="on">
The new version of Google apps such as Google Now and Google News all use cards in their UI.<br />
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDepmqVkIBTA-GrNcSCvaBu_YqvPoHo1pXbi4bCErAG3jDeLcVM0Xv7BC9RgYEEACuygaCBAX23foXaxjQJhkz2VAeYDdVeCBThkwAgu3HK42FlakveeT6Yn1XwtQN-HmMcgXvUgxnA9w/s1600/google+now.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDepmqVkIBTA-GrNcSCvaBu_YqvPoHo1pXbi4bCErAG3jDeLcVM0Xv7BC9RgYEEACuygaCBAX23foXaxjQJhkz2VAeYDdVeCBThkwAgu3HK42FlakveeT6Yn1XwtQN-HmMcgXvUgxnA9w/s320/google+now.png" width="180" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
Google Now</div>
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj75LIfWS65OEhRdqQAnTypUyeD5tv8uipN11UY3QVJeFumEsPmeBHPd3qMRWv2NqEBjHj57LGo-Cd6jyuQ3SIPiU-4isqv3dBjill5xmwbHephGWzne6xTNdIKU1RdneybFt-3Z8ObqlE/s1600/googlenews.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj75LIfWS65OEhRdqQAnTypUyeD5tv8uipN11UY3QVJeFumEsPmeBHPd3qMRWv2NqEBjHj57LGo-Cd6jyuQ3SIPiU-4isqv3dBjill5xmwbHephGWzne6xTNdIKU1RdneybFt-3Z8ObqlE/s320/googlenews.png" width="180" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
Google News</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
Behind the scenes, it is <span style="font-family: "courier new" , "courier" , monospace;">CardView</span> at work. CardView is part of the android support library and is being used extensively with <span style="font-family: "courier new" , "courier" , monospace;">RecyclerView </span><span style="font-family: inherit;">as a replacement for the </span><span style="font-family: "courier new" , "courier" , monospace;">ListView</span>.<br />
<span style="font-family: inherit;">Just like you would define a list item, you define a cardview in its own xml file such as list_item.xml. The CardView can include Imageviews and Textviews inside a linearlayout. To provide a card-like to the component, CardView includes the following attributes:</span><br />
<br />
<pre>app:cardCornerRadius="10sp"app:cardElevation="2sp"app:cardBackgroundColor="#ffffff"app:cardUseCompatPadding="true"</pre>
<br />
The <span style="background-color: white; color: blue; font-family: "courier new"; font-size: 9pt; font-weight: bold;">cardCornerRadius </span>provides for a rounded view for the cards, like rounded rectangles. The <span style="background-color: white; color: blue; font-family: "courier new"; font-size: 9pt; font-weight: bold;">cardElevation </span>gives a 3D look to the cards. The <span style="background-color: white; color: blue; font-family: "courier new"; font-size: 9pt; font-weight: bold;">cardUseCompatPadding </span>provides uniform padding for the cards across platforms (Lollipop and others).<br />
<br />
As with any other UI component, CardView can be added using the findViewById method<br />
<br />
<pre>View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.main_view_row, parent, false);</pre>
<br />
If you are using this with RecyclerView, the CardView will be typically added inside the RecyclerView adapter's onCreateViewHolder method.
</div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-90656941214890904962016-04-05T23:31:00.000+05:302016-04-05T23:31:35.131+05:30ListView to RecyclerView - Key Code Changes<div dir="ltr" style="text-align: left;" trbidi="on">
There are several good blog posts that explain the concept and theory of a <span style="font-family: "courier new" , "courier" , monospace;">RecyclerView </span>and how to implement it. This post is mainly looks at the key code changes required when moving from <span style="font-family: "courier new" , "courier" , monospace;">ListView </span>to <span style="font-family: "courier new" , "courier" , monospace;">RecyclerView</span>.<br />
<br />
1. Add the following to the build.gradle under the app module<br />
<pre> dependencies {
compile 'com.android.support:recyclerview-v7:23.2.1'
}</pre>
<br />
2. Probably the biggest change is the adapter from BaseAdapter or ArrayAdapter to RecyclerView.Adapter.<br />
<pre>public class MainViewAdapter extends RecyclerView.Adapter<MainViewAdapter.PostViewHolder></pre>
<br />
<div>
3. If like me you had been using an <span style="font-family: "courier new" , "courier" , monospace;">ArrayAdapter</span> , make the arrays into lists as the new adapter code looks more elegant with them</div>
<div>
<div>
<div>
<br /></div>
<div>
4. The <span style="font-family: "courier new" , "courier" , monospace;">ViewHolder</span> class becomes a must - it is a <span style="font-family: "courier new" , "courier" , monospace;">public static class </span>inside the adapter that holds the UI items such as TextViews</div>
<div>
<br /></div>
<div>
5. UI items get added to a view holder instead of a View</div>
</div>
<div>
<br /></div>
<div>
6. Implement custom <span style="font-family: "courier new" , "courier" , monospace;">ViewHolder </span>classes such as <span style="font-family: "courier new" , "courier" , monospace;">PostViewHolder </span>that I have mentioned above to hold the layout that you need (e.g. TextViews, ImageView etc. that make a row in a list)</div>
<div>
<br /></div>
<span style="font-family: "courier new" , "courier" , monospace;">7. getView </span>method in adapter is replaced by <span style="font-family: "courier new" , "courier" , monospace;">onCreateViewHolder </span>- holder is created here, <span style="font-family: "courier new" , "courier" , monospace;">onBindViewHolder </span>- UI attributes such as TextView.setText happen here</div>
<div>
<br /></div>
<div>
8. XML layout file has to include a <span style="font-family: "courier new" , "courier" , monospace;">RecyclerView </span>instead of a <span style="font-family: "courier new" , "courier" , monospace;">ListView</span></div>
<div>
<br />
9. Usually a <span style="font-family: "courier new" , "courier" , monospace;">CardView </span>is used for the "list row" inside the <span style="font-family: "courier new" , "courier" , monospace;">RecyclerView. </span><span style="font-family: "arial" , "helvetica" , sans-serif;">It can be made to look like a list with the right tweaks to </span><span style="font-family: "courier new" , "courier" , monospace;">cardElevation</span></div>
<div>
<br />
10. Handling clicks is a big pain as there is no <span style="font-family: "courier new" , "courier" , monospace;">onItemClick </span>like lists and <span style="font-family: "courier new" , "courier" , monospace;">OnItemTouchListener </span>requires implementing several methods. The workaround is to create an interface like <span style="font-family: "courier new" , "courier" , monospace;">ItemClickListener </span>and attach it to a view. <a href="http://www.truiton.com/2015/02/android-recyclerview-tutorial/" target="_blank">This article</a> shows how to do it along with a detailed tutorial on other aspects of the <span style="font-family: "courier new" , "courier" , monospace;">RecyclerView</span>.</div>
<div>
<br /></div>
</div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-2191113077947989012016-03-19T23:21:00.000+05:302016-03-19T23:21:05.351+05:30Implementing Pull to Refresh<div dir="ltr" style="text-align: left;" trbidi="on">
Implementing the "pull to refresh" feature in Android 5.1 upwards is fairly straightforward. Here are the steps:<br />
<br />
1. Wrap the list where you want to implement it with a SwipeRefreshLayout<br />
<br />
<pre><android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/swiperefresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout>
</pre>
<div>
<br /></div>
2. Get the SwipeRefreshLayout in the Activity or Fragment in onCreateView method like so<br />
<br />
<pre>swipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swiperefresh);</pre>
<br />
3. If using a Fragment, add a method onViewCreated. In it attach the onRefreshListener to the SwipeRefreshLayout<br />
<br />
<pre> @Override
public void onViewCreated(View view, Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
Log.i(TAG, "onRefresh called from SwipeRefreshLayout");
//add code here to refresh the list
}
});
}
</pre>
<br />
Done. </div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-70128532379627954362016-03-12T15:46:00.000+05:302016-03-12T15:46:12.998+05:30Smooth User Experience through AsyncTask<div dir="ltr" style="text-align: left;" trbidi="on">
I was looking at the examples in the Android Developer site for connecting to the web and found the Network Connect sample. It illustrates how to use a HTTPURLConnection class and fetch details from the stream. While tinkering with the sample code, I moved the code from the AsyncTask to the main class. The gist is shown below.<br />
<pre> public boolean onOptionsItemSelected(MenuItem item) {
try{
URL url = new URL("https://news.google.com");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
....
conn.connect();
InputStream stream = conn.getInputStream();
}
catch (Exception e){
Log.e(TAG, e.toString());
}
return true;
}
</pre>
When I ran the code, I got an exception - <span style="font-family: Courier New, Courier, monospace;">android.os.NetworkOnMainThreadException</span>.What this essentially means is that we cannot do any time consuming operations, such as connecting to the network or loading large images on the main thread, as these would ruin the user experience of the app. So, Google has mandated (quite rightly so) to use the AsyncTask class which helps in doing operations in the background. So, in the AsyncTask class the key methods that help us are doInBackground and onPostExecute. We need to extend the AsyncTask class and override the doInBackground and onPostExecute methods.
Key points and steps:
When extending the AsyncTask class, the parameters should match the methods' return types.
doInBackground will execute the logic
onPostExecute will have the results
Parameter of onPostExecute should match the return type of doInBackground; in this case both are Strings
Instantiate the class that extends AsyncTask in the main class and call the execute method passing the arguments of the doInBackground method
<br />
<pre> private class WebDataLoaderTask extends AsyncTask<string string="" void=""> {
@Override
protected String doInBackground(String... urls) {
try {
URL url = new URL("https://news.google.com");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
....
conn.connect();
InputStream stream = conn.getInputStream();
...
return new String(buffer);
}
catch (Exception e){
Log.e(TAG, e.toString());
}
}
@Override
protected void onPostExecute(String result) {
//results are available here
Log.i(TAG, result);
}
}</string></pre>
The earlier code now looks like this:<br />
<pre> public boolean onOptionsItemSelected(MenuItem item) {
try{
new WebDataLoaderTask().execute("https://news.google.com");
}
catch (Exception e){
Log.e(TAG, e.toString());
}
return true;
}
</pre>
By moving to the AsyncTask based approach the <span style="font-family: Courier New, Courier, monospace;">android.os.NetworkOnMainThreadException </span>is gone and the app provides a good user experience. </div>
Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-11418115577066056372016-03-06T14:54:00.000+05:302016-03-08T23:54:28.216+05:30Search APIs - Cheap, Fast, Good (choose only 2)I tried <a href="http://www.faroo.com/hp/api/api.html" target="_blank">Faroo</a> - a search API that I was considering to use for a mobile app. Faroo is free for up to a million requests a month. Probably the most generous among the free plans available from the competition. Signup is straight forward but it took a few days to receive the key. Just append the key to the search requests and you are done.<br/><br/>It appears that Faroo is more focused on Europe or the US as search results for India focused products did not produce any results. Since the app that I am looking to build is India-centric, I am looking at a search API that can bring in results related to India. Many of the searches produced no results.<br/><br/>I next tried <a href="https://webhose.io/pricing" target="_blank">Webhose.io</a>, another search API but a more restrictive plan of 1000 requests per month. Signup done and received the key in less than a minute. Search results brought in results on India-specific terms. The quality of results was impressive too. It is the pricing that is steep and preventing me from going ahead with using the API.<br/><br/>As it stands, I have to decide between free/low price with not much quality or expensive results with quality. Or maybe I will figure out a third option. I will continue exploring for now.Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0tag:blogger.com,1999:blog-5923887751969898671.post-21004367306082651272016-02-11T14:40:00.000+05:302016-03-08T23:54:28.207+05:30Stopping Development of ThingseThe last post here was over 5 months ago. Why did I not post anything for so long? Because there was no development on Thingse. I had planned on adding various features such as moving to a backend-as-a-service for the database, adding search capabilities, login using social ID etc. But the motivation was gradually dwindling as I did not see much interest in the app (had shared the APK to a few folks). I believe that the app more than served its purpose: allowing me to get started with Android programming, helping me move to Android Studio, Gradle and Material Design. The source code and binary of the app is available in <a href="https://github.com/daneshzaki/Thingse" target="_blank">Github</a>. Anyone who is interested to take it forward is welcome to do so.Daneshhttp://www.blogger.com/profile/07801817103097495240noreply@blogger.com0