Grand Central Dispatch(GCD)

Apple’s GCD (long form: Grand Central Dispatch) framework allows you to create asynchronous apps for iOS, ensuring smooth a smooth user experience in situations like the one mentioned above.

Flying First Class
-Return from functions or closures
-Receive as parameters of functions and closures
First-Class Types
-Assign to variables and constants
-Add to Arrays or Dictionaries

//: First Class

import UIKit

let f = {(x:Int) -> Int
	in
	return x + 42}

f(9)
f(76)

let closures = [f,
	{(x:Int) -> Int in return x * 2},
	{x in return x - 8},
	{x in xx * x},
	{$0 * 42}]

for fn in closures{
	fn(42)
}

parameters.putString

new GraphRequest(
	AccessToken.getCurrentAccessToken(),
	"/me",
	parameters,
	HttpMethod.GET,
	new GraphRequest.Callback(){
		@Override
		public void onCompleted(GraphResponse response){
			if (response.getError() != null){
				Toast.makeText(AccountActivity.this, response.getError().getErrorMessage(), Toast.LENGTH_LONG).show();
				return;
			}

			JSONObject jsonResponse = response.getJSONObject();
			try {
				String locationStr = jsonResponse.getString("location");
				location.setText(locationStr);
			} catch (JSONException e){
				e.printStackTrace();
			}
		}
	}
).executeAsync();
{
	"location": {
		"id": "107413405955233",
		"name": "Huntington Beach, California"
	},
	"id": "128607281023401"
}
Bundle parameters = new Bundle();
parameters.putString("message", "Access Denied");
new GraphRequest(
	AccessToken.getCurrentAccessToken(),
	"/me/feed",
	parameters,
	HttpMethod.POST,
	new GraphRequest.Callback(){
		@Override
		public void onCompleted(GraphResponse response){
			if (response.getError() != null){
				Toast.makeText(MainActivity.this, response.getError().getErrorMessage(), Toast.LENGTH_LONG).show();
				return;
			}
		}
	}
).executeAsync();

Testing account kit

Making a test plan for account kit
common flows:
1. User logs in with phone number
2. User logs in with email

How can the Graph API make app better?
-increased personalization
-more opportunities for social interaction

Better personalization and more opportunities for social interaction can lead to improvements in:
-Engagement
-Retention

Facebook Graph API
https://developers.facebook.com/docs/graph-api?locale=ja_JP

if (accessToken != null &&
accessToken.getPermissions().contains("user_friends")){
	// make the API call to fetch friends list
	Bundle parameters = new Bundle();
	parameters.putString("fields", "picture");
	new GraphRequest(
	AccessToken.getCurrentAccessToken(), "/me/friends",HttpMethod.GET,...);
}.executeAsync();

Logout

Implementing the logout button manually

public void onLogout(View view){
	AccountKit.logOut();
	LoginManager.getInstance().logOut();
	launchLoginActivity();
}

How to Test: Making a Test Plan
unexpected conditions:
1.A new user declines to authenticate permissions once, then tries to log in again
2.A returning user who has changed their password
3.A returning user with an expired token
4.A returning user who logs in after disabling the Facebook platform

Account kit
Common Flows:
1. A user logs in with a phone number
2. A user logs in with an email address

Unexpected conditions:
1. A user tries to log in, but does not receive the SMS
2. A user types in the wrong code

Custom Tab Activity

<activity
	android:name="com.facebook.CustomTabActivity"
	android:exported="true">
	<intent-filter>
		<action android:name="android.intent.action.VIEW" />
		<category android:name="android.intent.category.DEFAULT" />
		<category android:name="android.intent.category.BROWSABLE" />
		<data android:scheme="@string/fb_login_protocol_scheme" />
	</intent-filter>
</activity>
@Override
protected void onActivityResult(final int requestCode,
final int resultCode, final Intent data){
	super.onActivityResult(requestCode, resultCode, data);

	callbackManager.onActivityResult(requestCode, resultCode, data);
	...
}
if (AccessToken.getCurrentAccessToken() != null){
	...
}
else{
	AccountKit.getCurrentAccount(new AccountKitCallback<Account>(){
		...
	})
}

if (AccessToken.getCurrentAccessToken() != null){
	Profile profile = Profile.getCurrentProfile();
}

if (AccessToken.getCurrentAccessToken() != null){
	Profile currentProfile = Profile.getCurrentProfile();
	if (currentProfile != null){
		displayProfileInfo(currentProfile);
	} else {
		Profile.fetchProfileForCurrentAccessToken();
	}
}

AuthCode

AccountKitConfiguration.AccountKitConfigurationBuilder configurationBuilder = new AccountKitConfiguration.AccountKitConfigurationBuilder(
	loginType,
	AccountKitActivity.ResponseType.CODE
);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
	super.onActivityResult(requestCode, resultCode, data);
		AccountKitLoginResult loginResult = data.getParcelableExtra(
			AccountKitLoginResult.RESULT_KEY);
		String toastMessage;
		if(loginResult.getError() != null){
			toastMessage = loginResult.getError().getErrorType().getMessage();
			showErrorActivity(loginResult.getError());
		else if (loginResult.wasCancelled());
			toastMessage = "Login Canceled";
		} else {
			String authCode = loginResult.getAuthorizationCode();
			startActivity(new Intent(this, AuthorizedActivity.class));
		}

}
{
	"id" : <account_kit_user_id>,
		"access_token" : <account_access_token>,
		"token_refresh_interval_sec" : <refresh_interval>
}

GET https://graph.accountkint.com/v1.v1/me/?access_token=

{
	"id":"12345"
	"phone":{
		"number":"+15551234567"
		"country_prefix":"1",
			"national_number":"5551234567"
	}
}
public void getAccountInfo(AccountInfo accountInfo){
	String accountKitId = accountInfo.getId();
	String phoneNumber = accountInfo.getPhone().getNumber();

	String email = accountInfo.getEmail();
}
AppEventsLogger logger = AppEventsLogger.newLogger(this)

public void onLoginSMS(final View view){
	logger.logEvent("onSMSLogin");
	onLogin(LoginType.PHONE);
}

public void onLoginEmail(final View view){
	logger.logEvent("onEmailLogin");
	onLogin(LoginType.EMAIL);
}

AndroidManifest.xml

<application
	android:allowBackup="true"
	android:icon="@mipmap/ic_launcher"
	android:label="@string/app_name"
	android:roundIcon="@mipmap/ic_launcher_round"
	android:supportsRtl="true"
	android:theme="@style/AppTheme">
	<meta-data android:name="com.facebook.accountkit.ApplicationName"
		android:value="@string/app_name" />
	<meta-data android:name="com.facebook.sdk.ApplicationId"
		android:value="@string/FACEBOOK_APP_ID" />
	<meta-data android:name="com.facebook.accountkit.ClientToken"
		android:value="@string/ACCOUNT_KIT_CLIENT_TOKEN" />

	<activity
		android:name="com.facebook.accountkit.ui.AccountKitActivity"
		android:theme="@style/AppLoginTheme"
		tools:replace="android:theme">
	</activity>
<resources>
	<style name="AppLoginTheme" parent="Theme.AccountKit"/>
</resources>
import com.facebook.accountkit.AccountKit;
import com.facebook.accountkit.AccessToken;

@Override
Protected void onCreate(Bundle savedInstanceState){
	AccessToken accessToken = AccountKit.getCurrentAccessToken();
	if (accessToken != null){
		launchAccountActivity();
	}
}

How account kit work

1. client access token
-> you aren’t running your own servers
-> simpler to implement
-> long-lived token

2. authorization code (more secure)
-> all other cases
-> requires extra steps server-side
-> client never sees the token

repositories {
	jcenter()
}
allprojects {
	repositories {
		jcenter()
	}
}
dependencies {
	compile 'com.facebook.android:account-kit-sdk:4.+'
}

Connecting Count Bolt

class:Word Spout
componentId:”word-spout”

builder.setSpout("word-spout", new WordSpout(), 5);

class:CountBolt
componentOd:”count-bolt”

builder.setBolt("count-bolt",
	new CountBolt(), 15)
		.fieldsGrouping("word-spout",
			new Field("word"));

beautiful soup

easy_install beautifulsoup4

Storm & Hadoop

Storm & Hadoop are complimentary!
Hadoop => big batch processing
Storm => fast, reactive, real time processing

Storm data model
-Spouts
->sources of data for the topology (e.g) Postgres/MySQL/Kafka/Kestrel
-Bolts
->units of computation on data (e.g) filtering/aggregation/join/transformations

Live stream of Tweets
tweet spout, parse tweet bolt, word count bolt

Stream grouping
shuffle, fields, all, global

tuble: immutable ordered list of elements
topology: directed acyclic graph, vertices = computation and edges = streams of data