Most of the code below relates to GUI messaging, but this Android app is full HCE for a Cloud Based Payments card. It is a total of 201 lines of code including comments, and line spaces. It is a single class application for simplicity.
The goal is to show that the libraries for managing CBP on the mobile app are lightweight for developers to use.
The libs are designed to be placed into ANY application that may want to enable CBP. The one below is about the simplest integration.
The full application is called SimplestTapp and can be downloaded and tested here:
http://wiki.simplytapp.com/home/self-driven-hce-pilot/make-a-payment-card/simplytapp-s-vcbp-changelog/software-dev-kits/mobile-sdk
it also may be good to view this help resource for creating and managing the card perso and lifecycle in the cloud:
http://wiki.simplytapp.com/home/using-admin-api-console
The core of the card download and enablement is really contained in this section. This section instantiates a VirtualCard that will be loaded from the remote server. In order to instantiate the CBP card, you will see that there are some required credential information because a request will be made to the CBP server to retrieve the card that will be used.
The data in the snippet is sample data only.
The AsyncTask is used because the load() method makes network calls and can't be run on the UI thread.
// Create a card with data from AdminApi console // See wiki for help: // http://wiki.simplytapp.com/home/using-admin-api-console // // Values are found within your AdminApi Console. Click Get APP // Credentials. // // card agent code hash is found inside the Issuer Entity portion of the // web portal // final VirtualCard card = VirtualCardBuilder .cardId("5901") .mobileAppConsumerKey( "oJmqoey7I97FBOZQDXoH0A9RbM7BciXbD8CHZDMU") .mobileAppConsumerSecret( "ugTD5dGjBUEC1pyzxjMNtw6k9TUocGtY4plta9he") .walletAccessToken("O15F4jG3PcwC44NpkfEqv1ZD7tjNo5NhGpHHFEax") .walletTokenSecret("Ur504iPQn2lxgsS5fVBycf2zK9uuSglppvn2mBa3") .cardAgentCodeHash("aa4185c2364048447a38aa02499a9897") .context(this).build(); // now load the card... // this requires network connectivity and is blocking // so we must use AsyncTask to avoid running this in UI thread // new AsyncTask() { @Override protected Void doInBackground(Void... params) { try { myActivity.postUi("==================================" + "\n" + "=====Loading Card From Server=====" + "\n" + "==================================" + "\n"); card.load(); } catch (IOException ex) { Log.e(TAG, "Failed to load", ex); } return (Void) null; } }.execute();
// define the message default card message handler // and set it in the lib static { VirtualCardMessaging virtualCardMessenger = new VirtualCardMessaging() { @Override public void virtualCardMessage(VirtualCardMessaging.Message message) { switch (message.getCode()) { case VirtualCardMessaging.CARD_CREATION_COMPLETED: try { // when card is created, then activate the card agent, // then connect it to the ApduService, // then ask the user if they want this app the default // app // for servicing the reader message.getVirtualCard().activate(); ApduService.setVirtualCard(message.getVirtualCard()); myActivity.postUi("========================" + "\n" + "=====Card Created=======" + "\n" + "========================" + "\n" + "==Card Id: " + message.getVirtualCard().getVirtualCardId() + "\n" + "==Num: " + message.getVirtualCard() .getVirtualCardNumber() + "\n" + "==Card Exp: " + message.getVirtualCard() .getVirtualCardExpDate() + "\n" + "==Card Type: " + message.getVirtualCard().getVirtualCardType() + "\n" + "==Card Logo: " + message.getVirtualCard().getVirtualCardLogo() + "\n"); myActivity.postUi("========================" + "\n" + "=====Card Activating====" + "\n" + "========================" + "\n"); } catch (IOException e) { e.printStackTrace(); } break; case VirtualCardMessaging.CARD_ACTIVATE_COMPLETED: myActivity.postUi("========================" + "\n" + "========================" + "\n" + "========================" + "\n" + "=====Card Activated=====" + "\n" + "=====Ready To Tap=======" + "\n" + "========================" + "\n" + "========================" + "\n" + "========================" + "\n"); break; case VirtualCardMessaging.TRANSACTION_ENDED: myActivity.postUi("========================" + "\n" + "========================" + "\n" + "========================" + "\n" + "===Ready To Tap Again====" + "\n" + "========================" + "\n" + "========================" + "\n" + "========================" + "\n"); break; default: break; } // log the message Log.d(TAG, message.getMessage() + " cardId=" + message.getVirtualCardId() + " code=" + message.getCode()); myActivity.postUi(message.getMessage() + " cardId=" + message.getVirtualCardId() + " code=" + message.getCode() + "\n"); } }; // set the default messenger VirtualCard.setDefaultVirtualCardMessaging(virtualCardMessenger); }
You will notice above that the messaging loop is logging all messages from the card and printing them to the screen of the app and the debugger. This can give you an idea of the events the card notifies the app. As far as API requests to the card from the app, the VirtualCard library contains many methods. Here is the JavaDoc:
http://simplytapp.github.io/android/virtualcard/doc/
Full activity class code for this example:
package com.simplytapp.example.simplesttapp; import java.io.IOException; import com.simplytapp.virtualcard.ApduService; import com.simplytapp.virtualcard.VirtualCard; import com.simplytapp.virtualcard.VirtualCardBuilder; import com.simplytapp.virtualcard.VirtualCardMessaging; import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.nfc.NfcAdapter; import android.nfc.cardemulation.CardEmulation; import android.os.AsyncTask; import android.os.Bundle; import android.text.method.ScrollingMovementMethod; import android.util.Log; import android.widget.TextView; public class MainActivity extends Activity { private static final String TAG = MainActivity.class.getSimpleName(); private static MainActivity myActivity = null; private TextView tv = null; // this method posts strings to the textview box in the UI thread private void postUi(final String t) { new Runnable() { public void run() { runOnUiThread(new Runnable() { public void run() { tv.append(t); if (tv.getLayout() != null) { // auto-scroll vertically final int scrollAmount = tv.getLayout().getLineTop( tv.getLineCount()) - tv.getHeight(); // if there is no need to scroll, scrollAmount will // be <=0 if (scrollAmount > 0) tv.scrollTo(0, scrollAmount); else tv.scrollTo(0, 0); } } }); } }.run(); } // define the message default card message handler // and set it in the lib static { VirtualCardMessaging virtualCardMessenger = new VirtualCardMessaging() { @Override public void virtualCardMessage(VirtualCardMessaging.Message message) { switch (message.getCode()) { case VirtualCardMessaging.CARD_CREATION_COMPLETED: try { // when card is created, then activate the card agent, // then connect it to the ApduService, // then ask the user if they want this app the default // app // for servicing the reader message.getVirtualCard().activate(); ApduService.setVirtualCard(message.getVirtualCard()); myActivity.postUi("========================" + "\n" + "=====Card Created=======" + "\n" + "========================" + "\n" + "==Card Id: " + message.getVirtualCard().getVirtualCardId() + "\n" + "==Num: " + message.getVirtualCard() .getVirtualCardNumber() + "\n" + "==Card Exp: " + message.getVirtualCard() .getVirtualCardExpDate() + "\n" + "==Card Type: " + message.getVirtualCard().getVirtualCardType() + "\n" + "==Card Logo: " + message.getVirtualCard().getVirtualCardLogo() + "\n"); myActivity.postUi("========================" + "\n" + "=====Card Activating====" + "\n" + "========================" + "\n"); } catch (IOException e) { e.printStackTrace(); } break; case VirtualCardMessaging.CARD_ACTIVATE_COMPLETED: myActivity.postUi("========================" + "\n" + "========================" + "\n" + "========================" + "\n" + "=====Card Activated=====" + "\n" + "=====Ready To Tap=======" + "\n" + "========================" + "\n" + "========================" + "\n" + "========================" + "\n"); break; case VirtualCardMessaging.TRANSACTION_ENDED: myActivity.postUi("========================" + "\n" + "========================" + "\n" + "========================" + "\n" + "===Ready To Tap Again====" + "\n" + "========================" + "\n" + "========================" + "\n" + "========================" + "\n"); break; default: break; } // log the message Log.d(TAG, message.getMessage() + " cardId=" + message.getVirtualCardId() + " code=" + message.getCode()); myActivity.postUi(message.getMessage() + " cardId=" + message.getVirtualCardId() + " code=" + message.getCode() + "\n"); } }; // set the default messenger VirtualCard.setDefaultVirtualCardMessaging(virtualCardMessenger); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myActivity = this; tv = (TextView) findViewById(R.id.textView1); tv.setMovementMethod(new ScrollingMovementMethod()); // try to set this app as the default HCE application app CardEmulation cardEmulationManager = CardEmulation .getInstance(NfcAdapter.getDefaultAdapter(this)); ComponentName paymentServiceComponent = new ComponentName( getApplicationContext(), ApduService.class.getCanonicalName()); if (!cardEmulationManager.isDefaultServiceForCategory( paymentServiceComponent, CardEmulation.CATEGORY_PAYMENT)) { Intent intent = new Intent(CardEmulation.ACTION_CHANGE_DEFAULT); intent.putExtra(CardEmulation.EXTRA_CATEGORY, CardEmulation.CATEGORY_PAYMENT); intent.putExtra(CardEmulation.EXTRA_SERVICE_COMPONENT, paymentServiceComponent); startActivityForResult(intent, 0); } // Create a card with data from AdminApi console // See wiki for help: // http://wiki.simplytapp.com/home/using-admin-api-console // // Values are found within your AdminApi Console. Click Get APP // Credentials. // // card agent code hash is found inside the Issuer Entity portion of the // web portal // final VirtualCard card = VirtualCardBuilder .cardId("5901") .mobileAppConsumerKey( "oJmqoey7I97FBOZQDXoH0A9RbM7BciXbD8CHZDMU") .mobileAppConsumerSecret( "ugTD5dGjBUEC1pyzxjMNtw6k9TUocGtY4plta9he") .walletAccessToken("O15F4jG3PcwC44NpkfEqv1ZD7tjNo5NhGpHHFEax") .walletTokenSecret("Ur504iPQn2lxgsS5fVBycf2zK9uuSglppvn2mBa3") .cardAgentCodeHash("aa4185c2364048447a38aa02499a9897") .context(this).build(); // now load the card... // this requires network connectivity and is blocking // so we must use AsyncTask to avoid running this in UI thread // new AsyncTask() { @Override protected Void doInBackground(Void... params) { try { myActivity.postUi("==================================" + "\n" + "=====Loading Card From Server=====" + "\n" + "==================================" + "\n"); card.load(); } catch (IOException ex) { Log.e(TAG, "Failed to load", ex); } return (Void) null; } }.execute(); } }
Hi Doug, we are trying to implement HCE using SimplyTapp and getting BAD_CREDENTIAL error while trying to load card. Below is my code snippet, your help would be appreciable. Thanks
ReplyDeletefinal VirtualCard card = VirtualCardBuilder
.cardId("446")
.mobileAppConsumerKey(
"USDzf9qamTyTYfqYD1el2Oq2wlcEuHF2SfeENYLN")
.mobileAppConsumerSecret(
"Iqu7YLaNDPSacMIfQXUE66MmFQg1WogS6RwccLkv")
.walletAccessToken("GEwD0huz2NZ132rFrF9sSSqnsxGx2LAWCcrViFRt")
.walletTokenSecret("TUywzsxHGTDkk0z6qw3M4uOhbBDrUzSokOrVJErK")
.cardAgentCodeHash("a12d08522c8a0026f85e5bb1f1a108f6")
.context(this).build();
Great Article
Deleteandroid based projects
Java Training in Chennai
Project Center in Chennai
Java Training in Chennai
projects for cse
The Angular Training covers a wide range of topics including Components, Angular Directives, Angular Services, Pipes, security fundamentals, Routing, and Angular programmability. The new Angular TRaining will lay the foundation you need to specialise in Single Page Application developer. Angular Training
looking at the DB, it looks like the access token and secret you have are for your issuer entity specific card Access Token and secret. also it looks like your cardId is wrong. looking at the db, i think the call should be:
ReplyDeletefinal VirtualCard card = VirtualCardBuilder
.cardId("6069")
.mobileAppConsumerKey(
"USDzf9qamTyTYfqYD1el2Oq2wlcEuHF2SfeENYLN")
.mobileAppConsumerSecret(
"Iqu7YLaNDPSacMIfQXUE66MmFQg1WogS6RwccLkv")
.walletAccessToken("hq11CShDLvukQUZwmhoQ17eJzBoXdLCPWLRrAlEM")
.walletTokenSecret("7vYxPf5r84BbCkEOOmFjwNb4rQqZwQLhk0pdMCVu")
.cardAgentCodeHash("a12d08522c8a0026f85e5bb1f1a108f6")
.context(this).build();
Thanks for your reply Doug, its working fine now :) .
DeleteHi Doug, now am able to load the card in my Android app using the steps you have given in this link. I also want to develop an app which acts as a NFC terminal and communicates with the VirtualCard created above and completes the transaction successfully. Can you please provide me any link which I can go through to achieve this?
ReplyDeleteThanks,
Pradeep.
https://github.com/SimplyTapp/SoftTerminal
ReplyDeleteHi Doug, Thanks for the link. The source code seems to be java lib, any sample Android app which uses this java lib to interact with the virtual card over NFC?
ReplyDeleteAlso I have written an Android app as a terminal to interact with my card over NFC. The terminal app is able to read "PPSE if I send Ppse Aid" and "Card Applet if I send Card Aid" from my Virtual Card app running on another phone. But to complete the transaction I should be able to read "processing options" and "record data" as well which am not able to. Please guide me how I can read the "processing options" and "record data" of the virtual card to complete the transaction. Below are the Aids am sending over NFC to read the Ppse and card applet value from my terminal.
private static final byte[] AID_ANDROID = { (byte)0xA0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10 };
private static final byte[] PPSE_ANDROID = { (byte)0x32, 0x50, 0x41, 0x59, 0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31 };
Thanks.
Hi Doug,
ReplyDeleteI am able to read the VirtualCard data(Ppse, Card Aid, Processing options and Record data) from my terminal app running on another phone over NFC. But I have a requirement where I need to read all the above data(Ppse, Card Aid, Processing options and Record data) from VirtualCard object in the same app. Can you guide me how I can achieve this?
Thanks,
Pradeep.
Hi Doug, in the example above inside virtualCardMessage() function am getting ApprovalData as null when I try accessing it by message.getApprovalData() . Can you help me how I can get ApprovalData of a VirtualCard object.
ReplyDeleteThanks,
Pradeep.
using ApprovalData:
ReplyDelete2) using callback from agent to mobile app:
agent calls:
postMessage(String msg, boolean getApproval, ApprovalData approvalData)
msg can be any string
getApproval should be true
ApprovalData should be:
ApprovalData myData = new ApprovalData(new ApprovalData.StringData(-1,-1,0))
that passes an object that is requesting a String from the mobile app that can be any length and any characters
this message actually goes to the mobile application is a message through the VirtualCardInterface defined at the creation of new VirtualCard(...)
you can filter for message: VirtualCardInterface.POST_MESSAGE
if(message.getCode()==VirtualCardInterface.POST_MESSAGE)
{
//a post message from the agent is here
ApprovalData approvalData = message.getApprovalData();
ApprovalData.StringData sd = (ApprovalData.StringData)approvalData.getApprovalData();
sd.setAnswer("my answer");
//then send this back to the agent
virtualCard.messageApproval(true, approvalData);
}
this "virtualCard.messageApproval(...)" will trigger messageApproval(boolean approved,ApprovalData approvalData) agent method. so the agent code should have this:
@Override
public void messageApproval(boolean approved,ApprovalData approvalData){
//check my answer from the app:
ApprovalData.StringData sd = (ApprovalData.StringData)approvalData.getApprovalData();
String answer = sd.getAnswer();
//now answer contains string data from the application.
}
Using SoftPCD interface to read an interac flash card:
ReplyDeleteSoftPcd softPcd = new SoftPcd((short)5000);
try {
virtualCard.transactWithSoftPcd(softPcd);
} catch (IOException e) {
e.printStackTrace();
}
try {
softPcd.connect();
byte[] apdu = softPcd.transceiveWithCard(new byte[]{0x00,(byte)0xA4,0x04,0x00,0x05,(byte)0x32,0x50,0x41,0x59,(byte)0x2E});
apdu = softPcd.transceiveWithCard(new byte[]{0x00,(byte)0xA4,0x04,0x00,0x07,(byte)0xA0,0x00,0x00,0x02,0x77,0x10,0x10,0x00});
apdu = softPcd.transceiveWithCard(new byte[]{(byte)0x80,(byte)0xA8,0x00,0x00,0x15,(byte)0x83,0x13,(byte)0xD0,(byte)0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x01,0x24,0x01,0x24,0x02,0x66,0x33,(byte)0x82,0x01,0x00});
apdu = softPcd.transceiveWithCard(new byte[]{0x00,(byte)0xB2,0x01,0x0C,0x00});
apdu = softPcd.transceiveWithCard(new byte[]{0x00,(byte)0xB2,0x01,0x14,0x00});
apdu = softPcd.transceiveWithCard(new byte[]{0x00,(byte)0xB2,0x02,0x14,0x00});
apdu = softPcd.transceiveWithCard(new byte[]{0x00,(byte)0xB2,0x03,0x14,0x00});
apdu = softPcd.transceiveWithCard(new byte[]{0x00,(byte)0xB2,0x04,0x14,0x00});
apdu = softPcd.transceiveWithCard(new byte[]{0x00,(byte)0xB2,0x01,0x1C,0x00});
apdu = softPcd.transceiveWithCard(new byte[]{(byte)0x80,(byte)0xAE,(byte)0x80,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x24,
0x00,(byte)0x80,0x00,(byte)0x80,0x00,0x01,0x24,0x13,0x06,0x27,0x00,0x02,0x66,0x33,(byte)0x82,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x00,0x00});
softPcd.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
Hi Doug, thanks for your response. As specified above I am using SoftPcd to read card data, unfortunately 2 crashes are getting reported in the app
ReplyDelete1 . One crash is seen after loading the card, I had never come across this crash before. Below is the stacktrace which points to the cardagent :
W/dalvikvm( 9324): threadid=17: thread exiting with uncaught exception (group=0x41efec08)
D/MainActivity( 9324): Account is Disabled cardId=6164 code=24
D/MainActivity( 9324): Account is Disabled cardId=6164 code=24
E/AndroidRuntime( 9324): FATAL EXCEPTION: Thread-2714
E/AndroidRuntime( 9324): Process: com.example.sampletapp, PID: 9324
E/AndroidRuntime( 9324): java.lang.NullPointerException
E/AndroidRuntime( 9324): at com.simplytapp.cardagent.c.run(SourceFile:1794)
E/AndroidRuntime( 9324): at java.lang.Thread.run(Thread.java:841)
W/ActivityManager( 3042): Force finishing activity com.example.sampletapp/.MainActivity
I/CardAgent( 9324): activated, tGetAccountParams is still accessing remote card applet, waiting...
I/ServiceKeeper( 3042): In getseinfo pid = 3042 uid = 1000 seinfo= system
D/CrashAnrDetector( 3042): processName: com.example.sampletapp
D/CrashAnrDetector( 3042): broadcastEvent : com.example.sampletapp data_app_crash
W/ApplicationPackageManager( 3042): getCSCPackageItemText()
V/SmartFaceService - 3rd party pause( 3042): onReceive [android.intent.action.ACTIVITY_STATE/com.example.sampletapp/pause]
D/SSRMv2:CustomFrequencyManagerService( 3042): acquireDVFSLockLocked : type : DVFS_MIN_LIMIT frequency : 1200000 uid : 1000 pid : 3042 pkgName : ACTIVITY_RESUME_BOOSTER@4
W/ActivityManager( 3042): mDVFSHelper.acquire()
2 . Another crash is found for the code
byte[] apdu = softPcd.transceiveWithCard(new byte[]{0x00,(byte)0xA4,0x04,0x00,0x05,(byte)0x32,0x50,0x41,0x59,(byte)0x2E});
and below is the stacktrace.
I/CardAgent( 9324): activated, tGetAccountParams is still accessing remote card applet, waiting...
I/System.out( 9845): Thread-2815(HTTPLog):SmartBonding Enabling is false, log to file is false, DBG is false
W/System.err( 9324): java.io.IOException: PCD_TIMEOUT
W/System.err( 9324): at com.simplytapp.virtualcard.SoftPcd.transceiveWithCard(SourceFile:94)
W/System.err( 9324): at com.example.sampletapp.MainActivity.readCardData(MainActivity.java:149)
W/System.err( 9324): at com.example.sampletapp.MainActivity.access$400(MainActivity.java:23)
W/ActivityManager( 3042): destPackageName = null
W/System.err( 9324): at com.example.sampletapp.MainActivity$3.doInBackground(MainActivity.java:227)
W/System.err( 9324): at com.example.sampletapp.MainActivity$3.doInBackground(MainActivity.java:218)
W/System.err( 9324): at android.os.AsyncTask$2.call(AsyncTask.java:288)
W/System.err( 9324): at java.util.concurrent.FutureTask.run(FutureTask.java:237)
W/System.err( 9324): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
W/System.err( 9324): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
W/System.err( 9324): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
W/System.err( 9324): at java.lang.Thread.run(Thread.java:841)
Hope I am not disturbing you much, your help would be greatly appreciated.
Thanks,
Pradeep.
both of these appear to happening in the cardAgent. the latter is a timeout that is quite normal if the card Agent does not respond. the former looks like a card agent code side bug.
ReplyDeleteHi Doug, thanks for your quick response. Can PCD_TIMEOUT issue be fixed by increasing timeout while creating SoftPcd instance ? I never faced first issue before, these 2 issues have become a blocker for our development, your suggestions would help me in a great way.
ReplyDeleteThank,
Pradeep.
Hi Doug, PCD_TIMEOUT issue is fixed but first issue still persists. softPcd.transceiveWithCard() API is returning same value for all the inputs that I pass. If I convert byte array returned to Hex string its 6F00 in all the cases, any pointers on this?
ReplyDeleteThanks,
Pradeep.
Hi Doug
ReplyDeleteThe link below describes an interesting and simple service issuers could offer to their existing cardholders.
https://www.dropbox.com/s/k933b6g317aw4z1/Virtual%20Temporary%20Supplementary%20Card%20Concept%20Description.pdf?dl=0
Take a look and let me know your feedback
Milos
Hi Milos
ReplyDeleteI would be interested in that document.
Unfortunately the link you provided does not work.
Regards,
Diego
I have read your blog its very attractive and impressive. I like it your blog.
ReplyDeleteJava Training in Chennai | Core Java Training in Chennai
Online Java Training | Java EE Training Institute in Chennai
CIITN is located in Prime location in Noida having best connectivity via all modes of public transport. CIITN offer both weekend and weekdays courses to facilitate Hadoop aspirants. Among all Hadoop Training Institute in Noida , CIITN's Big Data and Hadoop Certification course is designed to prepare you to match all required knowledge for real time job assignment in the Big Data world with top level companies. CIITN puts more focus in project based training and facilitated with Hadoop 2.7 with Cloud Lab—a cloud-based Hadoop environment lab setup for hands-on experience.
ReplyDeleteCIITNOIDA is the good choice for Big Data Hadoop Training in NOIDA in the final year. I have also completed my summer training from here. It provides high quality Hadoop training with Live projects. The best thing about CIITNOIDA is its experienced trainers and updated course content. They even provide you placement guidance and have their own development cell. You can attend their free demo class and then decide.
Hadoop Training in Noida
Big Data Hadoop Training in Noida
This hacking app is easy to use https://cellspyapps.org/how-to-hack-an-iphone/! And you can get a lot of effort!
ReplyDeleteI'm shakshi.I am working in India top most Escort serviceEscort service in Mumbai.If u want to join the all facility of escortsEscort service in Bhubaneswar.pls call me & whatssapEscort service in Puri
ReplyDeletevisit the sites.Escort service in Cuttack
Escort Service in Gurgaon
ReplyDeleteBangalore escorts
Escort Service in Mumbai
Call girls in Gurgaon
==========================
Gurgaon escorts
Bangalore escorts
Mumbai escorts
Gurgaon escorts
============================
Bangalore call girls
Gurgaon call girls
Gurgaon call girls
Mumbai call girls
==============================
Escort service in Gurgaon
Escort service in Gurgaon
Escort service in Mumbai
Escorts in Bangalore
Call girl in Gurgaon
call girls in lucknow
lucknow escorts service
I can only express a word of thanks. Because with the content on this blog I can add knowledge I, thank has been sharing this information. Do not forget to visit our website to share information hotele
ReplyDeleteIt is not simple as for me. But you should check a masterwriter jobs. You will find something.
ReplyDeleteI was very happy to find this site. I really enjoyed reading this article today and think it might be one of the best articles I have read so far. I wanted to thank you for this excellent reading !! I really enjoy every part and have bookmarked you to see the new things you post. Well done for this excellent article. Please keep this work of the same quality.
ReplyDeleteData Science Course in Bangalore
Firmware file is a set of instructions programmed on a hardware device. So if you are facing any issues in your smartphone like the application stopped working, IMEI issues, and dead issues, you can download flash files to fix the issues. It is unique for every phone Y51l volte
ReplyDeleteWhile working on QuickBooks accounting software user can face some errors which obstructs users from working smoothly. You can read our articles to solve all your errors through our blog QB Tool Hub.
ReplyDeleteVery Nice Information. Thank you for giving me this information.
ReplyDeleteAOL Mail Not Working On MacBook Pro
AOL Mail Not Working On MacBook
AOL Mail Not Working On Mac
AOL Email Not Working On MacBook Pro
AOL Email Not Working On MacBook
i am glad to discover this page : i have to thank you for the time i spent on this especially great reading !! i really liked each part and also bookmarked you for new information on your site.
ReplyDeletedata scientist course in bangalore
Great post i must say and thanks for the information. Education is definitely a sticky subject. However, is still among the leading topics of our time. I appreciate your post and look forward to more.
ReplyDeleteData Science Course in Bangalore
I want to leave a little comment to support and wish you the best of luck.we wish you the best of luck in all your blogging enedevors.
ReplyDeletedata analytics courses in bangalore
i am glad to discover this page : i have to thank you for the time i spent on this especially great reading !! i really liked each part and also bookmarked you for new information on your site.
ReplyDeletebest data science courses in bangalore
I want to leave a little comment to support and wish you the best of luck.we wish you the best of luck in all your blogging enedevors.
ReplyDeletedata science in bangalore
I just got to this amazing site not long ago. I was actually captured with the piece of resources you have got here. Big thumbs up for making such wonderful blog page!
ReplyDeletedata analytics course in bangalore
Thanks for posting the best information and the blog is very helpful.digital marketing institute in hyderabad
ReplyDeletei am glad to discover this page : i have to thank you for the time i spent on this especially great reading !! i really liked each part and also bookmarked you for new information on your site.
ReplyDeletedata scientist course in bangalore
Nice Information. Thanks for sharing.
ReplyDeleteCrop cum Cobble Shears are one of our most popular products, and we are a leading producer and exporter of them. Under the guidance of our professional specialists, the provided cobble shears are crafted and constructed using the highest quality materials and advanced equipment and techniques. These cobble shears are used in the car, manufacturing, and other mechanical industries to cut bars and rods continuously at predetermined cutting points. Crop cum Cobble Shears are available in a variety of styles and power ratings, all at affordable prices.
I want to leave a little comment to support and wish you the best of luck.we wish you the best of luck in all your blogging enedevors.
ReplyDeletedata science course
I am glad to discover this page. I have to thank you for the time I spent on this especially great reading !! I really liked each part and also bookmarked you for new information on your site.
ReplyDeleteData Science Training in Chennai
While working on QuickBooks accounting software user can face some errors which obstructs users from working smoothly. You can read our articles to solve all your errors through our blog initial necklace usa , initial necklace wholesale france
ReplyDeleteInformative blog
ReplyDeletebest digital marketing institute in hyderabad
I am a new user of this site, so here I saw several articles and posts published on this site, I am more interested in some of them, hope you will provide more information on these topics in your next articles.
ReplyDeletedata analytics training in bangalore
i am glad to discover this page : i have to thank you for the time i spent on this especially great reading !! i really liked each part and also bookmarked you for new information on your site.
ReplyDeleteartificial intelligence training in chennai
I am glad to discover this page. I have to thank you for the time I spent on this especially great reading !! I really liked each part and also bookmarked you for new information on your site.
ReplyDeleteData Science Course Syllabus
I feel very grateful that I read this. It is very helpful and very informative and I really learned a lot from it.
ReplyDeleteBest Data Science courses in Hyderabad
i am glad to discover this page : i have to thank you for the time i spent on this especially great reading !! i really liked each part and also bookmarked you for new information on your site.
ReplyDeleteartificial intelligence training in chennai
Informative blog
ReplyDeletebest digital marketing institute in hyderabad
I want to leave a little comment to support and wish you the best of luck.we wish you the best of luck in all your blogging enedevors.
ReplyDeletedata science training in chennai
Informative blog
ReplyDeletedata science course in Nashik
I am glad to discover this page. I have to thank you for the time I spent on this especially great reading !! I really liked each part and also bookmarked you for new information on your site.
ReplyDeleteData Science Course Syllabus
Very awesome!!! When I seek for this I found this website at the top of all blogs in search engine.
ReplyDeletebusiness analytics course
Great to become visiting your weblog once more, it has been a very long time for me. Pleasantly this article i've been sat tight fosuch a long time. I will require this post to add up to my task in the school, and it has identical subject along with your review. Much appreciated, great offer. data science course in nagpur
ReplyDeleteI want to leave a little comment to support and wish you the best of luck.we wish you the best of luck in all your blogging enedevors.
ReplyDeletedata science course in jaipur
Extremely overall quite fascinating post. I was searching for this sort of data and delighted in perusing this one. Continue posting. A debt of gratitude is in order for sharing. python course in delhi
ReplyDeleteInformative blog
ReplyDeleteai training in hyderabad
I want to leave a little comment to support and wish you the best of luck.we wish you the best of luck in all your blogging enedevors.
ReplyDeletedata science course
I read you post. I really glad to read your post. Thanks for sharing with us.
ReplyDeleteGear Boxes Manufacturers
Gear Boxes Manufacturer
Gear Boxes Manufacturer in India
Gear Boxes in India
Thanks for posting the best information and the blog is very good.Cloud Computing course in Bangalore
ReplyDeleteInformative blog
ReplyDeletedata analytics courses in hyderabad
We are an astrology firm initiated in 1999 as Bajrangi Dham, and now we are known as Bajrangi Astro. If you are to meet a Love marriage Astrologer in astrology or any life issue, you can get the correct astrological solutions to all your questions. Contact us via mail or call. You can also book a direct appointment to know the chances of you marrying out of Love.
ReplyDeleteI am sure it will help many people. Keep up the good work. It's very compelling and I enjoyed browsing the entire blog.
ReplyDeleteBusiness Analytics Course in Bangalore
I am really enjoying reading your well written articles. I am looking forward to reading new articles. Keep up the good work.
ReplyDeleteData Science Courses in Bangalore
I feel very grateful that I read this. It is very helpful and very informative and I really learned a lot from it.
ReplyDeleteData Analytics Course
What an incredible message this is. Truly one of the best posts I have ever seen in my life. Wow, keep it up.
ReplyDeleteAI Courses in Bangalore
I am glad to discover this page. I have to thank you for the time I spent on this especially great reading !! I really liked each part and also bookmarked you for new information on your site.
ReplyDeleteData Science Course in Noida
This is really very nice post you shared, i like the post, thanks for sharing..
ReplyDeletedata science training
Extremely overall quite fascinating post. I was searching for this sort of data and delighted in perusing this one. Continue posting. A debt of gratitude is in order for sharing. cloud computing course in bangalore
ReplyDeleteExtremely overall quite fascinating post. I was searching for this sort of data and delighted in perusing this one. Continue posting. A debt of gratitude is in order for sharing. cloud computing course in nagpur
ReplyDeleteQuickbooks tool hub is a combination of all the minor and major issues related to QuickBooks. Before the company was not introduced it the users needed to download different-different tools for the different-different issues. But now users only need to download the quickbooks tool hub it is a combination of tools.
ReplyDeleteThis website is remarkable information and facts it's really excellent data science training in noida
ReplyDeleteReally nice and interesting post. I was looking for this kind of information and enjoyed reading this one. Keep posting. Thanks for sharing. cyber security course in patna
ReplyDeleteA good blog always contains new and exciting information and as I read it I felt that this blog really has all of these qualities that make a blog. data scientist course in lucknow
ReplyDeleteAw, this was a really nice post. In idea I wish to put in writing like this additionally ?taking time and actual effort to make a very good article? But what can I say? I procrastinate a lot and in no way appear to get one thing done.
ReplyDelete고스톱
Thank you for sharing your info. I truly appreciate your efforts and I
ReplyDeletewill be waiting for your further write ups thanks once again.
스포츠토토
He's really nice and mean. it's a really cool blog. The link is a very useful thing. You have really helped a lot of people who visit the blog and give them useful information. Data Science Training in Dombivli
ReplyDeleteI am very thankful for such a wonderful blog. It's very interesting to read and easy to understand. Thanks for sharing. I will visit your blog daily because I know. It may be very beneficial for me. If you want to Fix Common QuickBooks Pro Errors please contact QuickBooks team for instant help.
ReplyDeleteI really like reading a post that can make people think. Also, thank you for permitting me to comment!|data science training in jodhpur
ReplyDeleteImpressive. Your story always bring hope and new energy. Keep up the good work. Data Science Training in Chennai
ReplyDeleteThis is an excellent post I seen thanks to share it. It is really what I wanted to see hope in future you will continue for sharing such a excellent post.Data Analytics Course in Chennai
ReplyDeleteI have bookmarked your site since this site contains significant data in it. You rock for keeping incredible stuff. I am a lot of appreciative of this site.
ReplyDeleteAmazingly by and large very interesting post. I was looking for such an information and thoroughly enjoyed examining this one.
ReplyDeleteKeep posting. An obligation of appreciation is all together for sharing.
data science course in gwalior
Play the Best Slots at the Best Sites in 2021 - Airjordan2Remo
ReplyDeleteBest online slots are authentic air jordan 18 retro men red developed by the best what is the best air jordan 18 retro men red software providers, offering them how to buy air jordan 18 retro yellow suede the where to get air jordan 18 retro men chance to win money and win where can i find air jordan 18 retro red real money, as well as winning
Wonderful blog post. It's absolute magic on your part! Hope you continue like this!
ReplyDeleteData Analytics Training in Bangalore
360DigiTMG, the top-rated organisation among the most prestigious industries around the world, is an educational destination for those looking to pursue their dreams around the globe. The company is changing careers of many people through constant improvement, 360DigiTMG provides an outstanding learning experience and distinguishes itself from the pack. 360DigiTMG is a prominent global presence by offering world-class training. Its main office is in India and subsidiaries across Malaysia, USA, East Asia, Australia, Uk, Netherlands, and the Middle East.
ReplyDeleteI am another customer of this site so here I saw various articles and posts posted by this site,I curious more energy for some of them trust you will give more information further.https://360digitmg.com/course/data-analytics-using-python-r
ReplyDeleteWe are really grateful for your blog post. You will find a lot of approaches after visiting your post. Great work
ReplyDeletedata science course
A debt of gratitude is in order for giving late reports with respect to the worry, I anticipate read more. data analytics course in mysore
ReplyDeleteSuperb Information, I really appreciated with it, This is fine to read and valuable pro potential, I really bookmark it, pro broaden read. Appreciation pro sharing. I like it. Data Analytics Course in Dehradun
ReplyDeleteWe are grateful for your blog post. You will find a lot of approaches after visiting your post. Great work
ReplyDeletedata science course in malaysia
Someone Sometimes with visits your blog regularly and recommended it in my experience to read as well. Data Science Course in Dehradun
ReplyDeleteI see some amazingly important and kept up to a length of your strength searching for in your on the site
ReplyDeletecyber security course malaysia
Pretty good post. I just stumbled upon your blog and wanted to say that I have really enjoyed reading your blog posts. Any way I’ll be subscribing to your feed and I hope you post again soon. digital marketing training
ReplyDelete제주도출장샵
ReplyDelete제주도출장샵
총판출장샵
총판출장샵
총판출장샵
고고출장샵
심심출장샵
제주출장샵
동해출장안마
ReplyDelete영덕출장안마
원주출장안마
의왕출장안마
의왕출장안마
삼척출장안마
용인출장안마
청송출장안마
ReplyDelete군포출장안마
군포출장안마
강릉출장안마
영양출장안마
춘천출장안마
하남출장안마
하남출장안마