I had been googled almost a day to find out the answer. In case it is necessary in the future for my own use and someone might need, I decided to make a reference here as well as the original link link.
*** All credits have to go for the author, FurryNutz. ***
The following is his works
DCS:
This is an example of settings using a Google email account:
SMPT server address: smtp.gmail.com
Server port: 465 or 587 (I used 587)
Sender e-mail address: Username@gmail.com
Receiver e-mail address: Username@gmail.com
User Name: Username@gmail.com
Password: Created an app password through 2-step verification - Steps Below
Checked: SSL-TLS (or, STARTTLS if SSL-TLS doesnt work or no SSL-TLS there)
Through g-mail settings, Enabled 2 step verification. Follow the instructions and you should receive a text code to enable 2 step. Then go into app passwords and created a password for "other" apps. Enter the 16 digit code into the password column then it should work. Walked back and forth in front of the camera a few times to make sure it e-mails are received.
DNS:
First thing, the settings for sending must be correct.
The user name/password are what is used to log in to the NAS shares from a computer on the network.
For the port and SMTP Server see https://support.google.com/a/answer/176600?hl=en Although they mention printer etc. it is the same for the NAS.
The sender should be something to define the NAS (example: my.nas@myhome.com)
SMTP Auth - see the info in the above link.
Finally do a test send to check it is up and running.
Don't forget to save settings and also set what information you want to get from the NAS box.
The receiver is your gmail name@gmail.com
Windows Live/Hotmail
SMTP server address: smtp.live.com
SMTP user name: (Your complete Windows Live Hotmail email address ("me@hotmail.com" or "me@live.com" for instance) )
SMTP password: (Your Windows Live Hotmail password)
SMTP port: 587
SMTP Auth: TLS/SSL required: yes
Note: the port number is required for the SSL/TLS to work.
early in the morning
Monday, November 13, 2017
Monday, June 20, 2016
Google map api v3 with Ionic framework
My web was using Ionic framwork 1.x. After I read some threads and examples on the web, initiate the google map as following is the only way I can make the map show up.
index.html
<script src="http://maps.googleapis.com/maps/api/js?key=yourAPIkey&libraries=places" async defer></script>
view html:
<ion-header-bar class="bar bar-header bar-positive" ng-init="initMap()"></ion-header-bar>
<ion-content>
<div id="map" data-tap-disabled="true"></div>
</ion-content>
javascript:
$scope.initMap = function() {
$scope.directionsService = new google.maps.DirectionsService;
$scope.directionsDisplay = new google.maps.DirectionsRenderer({
suppressMarkers:true,
preserveViewport: true
//polylineOptions: { strokeColor: "red" }
});
var mylocation = new google.maps.LatLng('41.72', '-71.93');
var grayStyles = [
{ featureType: "all",
elementType: "labels.text",
stylers: [
{ gamma: 0.01 }
]
},
];
var mapOptions = {
center: mylocation,
zoom: 11,
styles: grayStyles,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map"),
mapOptions);
$scope.directionsDisplay.setMap(map);
var trafficLayer = new google.maps.TrafficLayer();
trafficLayer.setMap(map);
marker = new google.maps.Marker({
position: mylocation ,
icon: "http://maps.google.com/mapfiles/kml/pal3/icon48.png",
map: map
});
marker.infowindow = new google.maps.InfoWindow({
content: 'My xxx Inc.'
});
google.maps.event.addListener(marker, 'click', (function(marker) {
return function() {
marker.infowindow.open(map, marker);
}
})(marker));
$scope.map = map;
};
index.html
<script src="http://maps.googleapis.com/maps/api/js?key=yourAPIkey&libraries=places" async defer></script>
view html:
<ion-header-bar class="bar bar-header bar-positive" ng-init="initMap()"></ion-header-bar>
<ion-content>
<div id="map" data-tap-disabled="true"></div>
</ion-content>
javascript:
$scope.initMap = function() {
$scope.directionsService = new google.maps.DirectionsService;
$scope.directionsDisplay = new google.maps.DirectionsRenderer({
suppressMarkers:true,
preserveViewport: true
//polylineOptions: { strokeColor: "red" }
});
var mylocation = new google.maps.LatLng('41.72', '-71.93');
var grayStyles = [
{ featureType: "all",
elementType: "labels.text",
stylers: [
{ gamma: 0.01 }
]
},
];
var mapOptions = {
center: mylocation,
zoom: 11,
styles: grayStyles,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map"),
mapOptions);
$scope.directionsDisplay.setMap(map);
var trafficLayer = new google.maps.TrafficLayer();
trafficLayer.setMap(map);
marker = new google.maps.Marker({
position: mylocation ,
icon: "http://maps.google.com/mapfiles/kml/pal3/icon48.png",
map: map
});
marker.infowindow = new google.maps.InfoWindow({
content: 'My xxx Inc.'
});
google.maps.event.addListener(marker, 'click', (function(marker) {
return function() {
marker.infowindow.open(map, marker);
}
})(marker));
$scope.map = map;
};
Android Webview call Angular controller function.
Since the web is written with AngularJS 1.x, things are working with $scope that it does not look alike simple javascript; anyway, here is how I call a function declared in a controller successfully through Webview.
Android webview:
myWebView.loadUrl("javascript:drvAppDevicePosition('" + mLat + "','" + mLng + "');");
Javascript:
window.drvAppDevicePosition = function(a, b) {
$scope.$apply(function() {
console.log("Lat:"+a+"; Lng:"+b);
});
};
Android webview:
myWebView.loadUrl("javascript:drvAppDevicePosition('" + mLat + "','" + mLng + "');");
Javascript:
window.drvAppDevicePosition = function(a, b) {
$scope.$apply(function() {
console.log("Lat:"+a+"; Lng:"+b);
});
};
Android - Capture Signature
Recently, I implemented an App ran on Android for capture signature.
There are some examples on the web that I can taken for reference.
I also wanna share mine here if someone is also looking for this.
public class CaptureSignature extends Activity {
LinearLayout mContent;
SignatureView mSignature;
Button mClear, mGetSign, mCancel;
public static String tempDir;
public String current = null;
private Bitmap mBitmap;
View mView;
File mypath;
@Override public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.signature);
getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
tempDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS)
+ "/" + getResources().getString(R.string.external_dir) + "/";
ContextWrapper cw = new ContextWrapper(getApplicationContext());
File directory = cw.getDir(getResources().getString(R.string.external_dir),
Context.MODE_PRIVATE);
prepareDirectory();
current = "mySignaturre.png";
mypath= new File(tempDir,current);
mContent = (LinearLayout) findViewById(R.id.linearLayout);
mSignature = new SignatureView(this, null);
mSignature.setBackgroundColor(Color.WHITE);
mContent.addView(mSignature);
mClear = (Button)findViewById(R.id.clear);
mGetSign = (Button)findViewById(R.id.getsign);
mGetSign.setEnabled(false);
mCancel = (Button)findViewById(R.id.cancel);
mView = mContent;
mClear.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
mSignature.clear();
mGetSign.setEnabled(false);
}
});
mGetSign.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
boolean error = captureSignature();
if(!error){
mView.setDrawingCacheEnabled(true);
mSignature.save(mView);
finish();
}
}
});
mCancel.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
finish();
}
});
}
@Override protected void onDestroy() {
super.onDestroy();
}
private boolean captureSignature() {
boolean error = false;
String errorMessage = "";
if(error){
}
return error;
}
private String getTodaysDate() {
final Calendar c = Calendar.getInstance();
int todaysDate = (c.get(Calendar.YEAR) * 10000) +
((c.get(Calendar.MONTH) + 1) * 100) +
(c.get(Calendar.DAY_OF_MONTH));
return(String.valueOf(todaysDate));
}
private String getCurrentTime() {
final Calendar c = Calendar.getInstance();
int currentTime = (c.get(Calendar.HOUR_OF_DAY) * 10000) +
(c.get(Calendar.MINUTE) * 100) +
(c.get(Calendar.SECOND));
return(String.valueOf(currentTime));
}
private boolean prepareDirectory()
{
try {
if (makedirs())
{
return true;
} else {
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
private boolean makedirs()
{
File tempdir = new File(tempDir);
if (!tempdir.exists())
tempdir.mkdirs();
return true;
}
public class SignatureView extends View
{
private static final float STROKE_WIDTH = 18f;
private static final float HALF_STROKE_WIDTH = STROKE_WIDTH / 2;
private Paint paint = new Paint();
private Path path = new Path();
private float lastTouchX;
private float lastTouchY;
private final RectF dirtyRect = new RectF();
public SignatureView(Context context, AttributeSet attrs)
{
super(context, attrs);
paint.setAntiAlias(true);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(STROKE_WIDTH);
}
public void save(View v)
{
if(mBitmap == null)
{
mBitmap = Bitmap.createBitmap (mContent.getWidth(), mContent.getHeight(),
Bitmap.Config.RGB_565);
}
Canvas canvas = new Canvas(mBitmap);
try {
//Remove the old Signature if exists.
boolean deleted = mypath.delete();
FileOutputStream mFileOutStream = new FileOutputStream(mypath);
v.draw(canvas);
mBitmap.compress(Bitmap.CompressFormat.PNG, 90, mFileOutStream);
mFileOutStream.flush();
mFileOutStream.close();
String url = Images.Media.insertImage(getContentResolver(), mBitmap, "title",
null);
}
catch(Exception e)
{
Log.v("log_tag", e.toString());
}
}
public void clear()
{
path.reset();
invalidate();
}
@Override protected void onDraw(Canvas canvas)
{
canvas.drawPath(path, paint);
}
@Override public boolean onTouchEvent(MotionEvent event)
{
float eventX = event.getX();
float eventY = event.getY();
mGetSign.setEnabled(true);
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
path.moveTo(eventX, eventY);
lastTouchX = eventX;
lastTouchY = eventY;
return true;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
resetDirtyRect(eventX, eventY);
int historySize = event.getHistorySize();
for (int i = 0; i < historySize; i++)
{
float historicalX = event.getHistoricalX(i);
float historicalY = event.getHistoricalY(i);
expandDirtyRect(historicalX, historicalY);
path.lineTo(historicalX, historicalY);
}
path.lineTo(eventX, eventY);
break;
default:
debug("Ignored touch event: " + event.toString());
return false;
}
invalidate((int) (dirtyRect.left - HALF_STROKE_WIDTH),
(int) (dirtyRect.top - HALF_STROKE_WIDTH),
(int) (dirtyRect.right + HALF_STROKE_WIDTH),
(int) (dirtyRect.bottom + HALF_STROKE_WIDTH));
lastTouchX = eventX;
lastTouchY = eventY;
return true;
}
private void debug(String string){
}
private void expandDirtyRect(float historicalX, float historicalY)
{
if (historicalX < dirtyRect.left)
{
dirtyRect.left = historicalX;
}
else if (historicalX > dirtyRect.right)
{
dirtyRect.right = historicalX;
}
if (historicalY < dirtyRect.top)
{
dirtyRect.top = historicalY;
}
else if (historicalY > dirtyRect.bottom)
{
dirtyRect.bottom = historicalY;
}
}
private void resetDirtyRect(float eventX, float eventY)
{
dirtyRect.left = Math.min(lastTouchX, eventX);
dirtyRect.right = Math.max(lastTouchX, eventX);
dirtyRect.top = Math.min(lastTouchY, eventY);
dirtyRect.bottom = Math.max(lastTouchY, eventY);
}
}
}
AndroidMainfest.xml:
<activity android:name=".CaptureSignature" android:label="Signature Confirmation"
android:screenOrientation="landscape"
android:theme="@android:style/Theme.Dialog" />
signature.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="fill_parent"> <LinearLayout android:layout_height="wrap_content"
android:id="@+id/linearLayout2" android:layout_width="match_parent"> <Button android:layout_height="50dp" android:layout_weight=".30"
android:text="Cancel" android:layout_width="0dp" android:id="@+id/cancel" /> <Button android:layout_height="50dp" android:layout_weight=".35"
android:text="Clear" android:layout_width="0dp" android:id="@+id/clear" /> <Button android:layout_height="50dp" android:layout_weight=".35"
android:text="Confirm" android:layout_width="0dp" android:id="@+id/getsign" /> </LinearLayout> <TableLayout android:layout_height="wrap_content"
android:id="@+id/tableLayout1" android:layout_width="match_parent"> <TableRow android:id="@+id/tableRow3"
android:layout_width="wrap_content" android:layout_height="wrap_content"> </TableRow> </TableLayout> <LinearLayout android:layout_height="match_parent"
android:orientation="vertical" android:id="@+id/linearLayout"
android:layout_width="match_parent" /> </LinearLayout>
Thursday, March 10, 2016
[Amazon/SNS] AWS SNS publish SMS PHP 5.6 Implementation
Recently, I decided to add a verification code thru SMS to validate the user login. After I the feasibility of how my project integrate this feature, I decided to give AWS SNS a try since I already got a few services from them.
Here I wanna share my experience of how to set this up and hope it helps someone.
First, download and install AWS SDK PHP
my SDK PHP version is v3. and the minimum PHP version is 5.5
The first problem that came to me was when I tried to config OPCache following the Optimal Settings , I got Html error 500 when run phpinfo(). It took me some times to figure out the event log and it shown me Zend Opcache:
I created an user solely for all functions of SNS via IAM. There are several ways to configure your Credential File, I choose a file location I preferred instead of the default anyway, and setup like follows:
credentials.ini
[default]
aws_access_key_id = <YOUR AWS ACCESS KEY ID>
aws_secret_access_key = <YOUR AWS SECRET ACCESS KEY>
Next, I followed here to create my first "Topic" in SNS.
Since the format of TopicArn is like
Here I wanna share my experience of how to set this up and hope it helps someone.
My server environment for this setup:
Windows 7 IIS 7.5, PHP 5.6.19, AWS SDK PHP v3
First, download and install AWS SDK PHP
my SDK PHP version is v3. and the minimum PHP version is 5.5
The first problem that came to me was when I tried to config OPCache following the Optimal Settings , I got Html error 500 when run phpinfo(). It took me some times to figure out the event log and it shown me Zend Opcache:
"Unable to reattach to base address
Attempt to access invalid address."
For more information, you can see here.
Anyway, I finally followed the most easy fix, just set permission to 'everyone' on the temp folder, thanks to fedevegili the one who suggested.
Ok, before you can run the API the SDK provided successfully, you need to create an AWS account of course, as well as getting the Access key ID and Secret for the authentication putting in your script.
Ok, before you can run the API the SDK provided successfully, you need to create an AWS account of course, as well as getting the Access key ID and Secret for the authentication putting in your script.
I created an user solely for all functions of SNS via IAM. There are several ways to configure your Credential File, I choose a file location I preferred instead of the default anyway, and setup like follows:
<?php
//these two lines placed on top of the script
use Aws\Credentials\CredentialProvider;
use Aws\Sns\SnsClient;
$provider = CredentialProvider::ini('default', '/aws/credentials.ini');
$sns = SnsClient::factory(array(
'version' => 'latest',
'region' => 'us-east-1',
'credentials' => CredentialProvider::memoize($provider)
));
?>
credentials.ini
[default]
aws_access_key_id = <YOUR AWS ACCESS KEY ID>
aws_secret_access_key = <YOUR AWS SECRET ACCESS KEY>
Next, I followed here to create my first "Topic" in SNS.
- Make sure you set the region to "us-east-1"; otherwise, the option "SMS" won't be show up in the drop-down list for you select when you create "Subscription" later.
- Display Name must be given, and this Display Name will be show at the beginning of the SMS message followed by a ">" sign then your actual message.
As of today, 3/10/16, be aware that the API "publish" will only work as sending all subscriptions under a Topic. Although I see someone is able to send to specific Endpoint, they all have "Applications" defined in the middle for their specific Endpoint works; however, I don't have one (Application).
This is not a big problem though, I made one topic for one subscription only for one Endpoint (mobile number). The thing is you may need to know which topic you're going to send for the specific Endpoint.
Since the format of TopicArn is like
arn:aws:sns:<Region>:<Subscriber/Topic Owner>:<TopicName>
I can use the TopicName to distinguish who I'm going to send, and like this
$region="us-east-1";
$subscriber="1234567890";
$topicName="USER001";
$TargetArn="arn:aws:sns:".$region.$subscriber.":".$topicName;
$Message="Hello World!";
$sns->publish(array('TargetArn'=>$TargetArn,'Message' => $Message));
Hope you Enjoy!$subscriber="1234567890";
$topicName="USER001";
$TargetArn="arn:aws:sns:".$region.$subscriber.":".$topicName;
$Message="Hello World!";
$sns->publish(array('TargetArn'=>$TargetArn,'Message' => $Message));
Monday, October 26, 2015
php 5.4/5.6 MS SQL 2005/2008 - sqlstate im002 "microsoft odbc driver manager data source name not found"
Recently, I setup a new IIS on a windows 10 to connect a MS SQL server with PHP; I got this Error Message, "sqlstate: im002, message: microsoft odbc driver manager data source name not found", when trying to connect to the server.
I tried to google the answer, but no one could solve my problem, most of the answers directed to the incorrectly version of ODBC driver. But it was not my case.
Eventually, I compared the new server configurations to my working one, and found that
"SQL Server Native Client 11.0" is installed.
so, I wrote this down and hope this helps someone.
p.s. if you've trouble to locate the download link of "SQL Server native Client"
take a look here: http://www.sqlservercentral.com/Forums/Topic1458276-2799-1.aspx
Updated on 20161217: Recently, I encountered the same problem with the environment like PHP 5.4 with SQL Server 2005 (SP4) and tried to move it to PHP 5.6.
I found no solution for this issue even updated the SQL Server native client from 11 to 12. I only can choose either to stay "PHP 5.4 with SQL Server 2005 (SP4)" or move to "SQL Server 2008 (and after)" if I want PHP 5.6.
2nd, since I've added a new feature to the current system that will work with AWS SMS, and PHP 5.5 is the minimum requirement for the AWS SDK.
Thus, in this case, I have to move the DB from 2005 to 2008 R2 and make it works with PHP 5.6.
I tried to google the answer, but no one could solve my problem, most of the answers directed to the incorrectly version of ODBC driver. But it was not my case.
Eventually, I compared the new server configurations to my working one, and found that
"SQL Server Native Client 11.0" is installed.
so, I wrote this down and hope this helps someone.
p.s. if you've trouble to locate the download link of "SQL Server native Client"
take a look here: http://www.sqlservercentral.com/Forums/Topic1458276-2799-1.aspx
Updated on 20161217: Recently, I encountered the same problem with the environment like PHP 5.4 with SQL Server 2005 (SP4) and tried to move it to PHP 5.6.
I found no solution for this issue even updated the SQL Server native client from 11 to 12. I only can choose either to stay "PHP 5.4 with SQL Server 2005 (SP4)" or move to "SQL Server 2008 (and after)" if I want PHP 5.6.
2nd, since I've added a new feature to the current system that will work with AWS SMS, and PHP 5.5 is the minimum requirement for the AWS SDK.
Thus, in this case, I have to move the DB from 2005 to 2008 R2 and make it works with PHP 5.6.
Sunday, September 21, 2014
[Android] A simple trick to watch unsupport video format directly from Sandisk Wireless Flash
I just got a Sandisk Wireless Flash and mainly for storing up videos that I can watch on my mobile device (mine one is Samsung S3 and Tab 3) anytime.
However, when I tried to watch rmvb and mkv, a message pop up and it said 'your Android device cannot view this type of file.'
Even I did try the Realplayer Cloud that the Sandisk recommends this approach, I cannot see my Sandisk device under the Realplayer Cloud with following steps:
http://kb.sandisk.com/app/answers/detail/a_id/10539/~/playing-videos-that-are-not-natively-supported-by-your-mobile-device
When I almost gave up, an idea came into my mind. How about if I rename the file type into avi that Android native support?
Then, it is just that simple. Rename the file type!
example 1:
rename video1.rmvb to video.avi
example 2:
rename video2.mkv to video.avi
(mp4 also works)
Yes, that's it. Now, we can click on the video file you renamed and Android now allows you to pick what video player in your device to play it.
Lastly, of course, you need to install a video player, that is able to play the particular video format, into your device beforehand.
I am using MX player if you want know what works for me.
However, when I tried to watch rmvb and mkv, a message pop up and it said 'your Android device cannot view this type of file.'
Even I did try the Realplayer Cloud that the Sandisk recommends this approach, I cannot see my Sandisk device under the Realplayer Cloud with following steps:
http://kb.sandisk.com/app/answers/detail/a_id/10539/~/playing-videos-that-are-not-natively-supported-by-your-mobile-device
When I almost gave up, an idea came into my mind. How about if I rename the file type into avi that Android native support?
Then, it is just that simple. Rename the file type!
example 1:
rename video1.rmvb to video.avi
example 2:
rename video2.mkv to video.avi
(mp4 also works)
Yes, that's it. Now, we can click on the video file you renamed and Android now allows you to pick what video player in your device to play it.
Lastly, of course, you need to install a video player, that is able to play the particular video format, into your device beforehand.
I am using MX player if you want know what works for me.
Subscribe to:
Posts (Atom)