tag:blogger.com,1999:blog-31155954617612991322024-02-06T22:40:14.696-06:00The Giacobbe candidatesR,Java, other...zigmundhttp://www.blogger.com/profile/07548914057663250729noreply@blogger.comBlogger14125tag:blogger.com,1999:blog-3115595461761299132.post-76851832038667664042019-01-23T06:43:00.001-06:002019-01-25T07:48:48.980-06:00Read magnetic strip card data in Android Recently I have developed an app with the purpose to read data from an USB card reader. The data to be read are stored on a plastic card organized in this way:<br />
<ol>
<li> a <i>start</i> tag;</li>
<li>a fixed field (length of 17 char);</li>
<li>two other fields separated by a white space with no size declarad but always present;</li>
<li>an <i>end </i>tag. </li>
</ol>
The external USB card reader is something similar to an external keyboard so it's possible to override the appropriate method in the Activity to handle every single character read from the reader.<br />
The Activity manages the card data character by character so firstly I had to create a <a href="https://gist.github.com/bubbobne/a7bc53275474cd746692477d5241f5da">UsbDecoder</a> class to manage the data flow and to build my output values. Lastly. I had to implemented the onKeyDown to intercept the data from the reader:<br />
<br />
<pre class="prettyprint linenums lang-java"> @Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
char pressedKey;
if (event.getKeyCode() == KeyEvent.KEYCODE_SPACE || event.getKeyCode() == KeyEvent.KEYCODE_TAB) {
pressedKey = Character.SPACE_SEPARATOR;
} else {
pressedKey = (char) event.getUnicodeChar();
}
if (usbDecoder.addChar(pressedKey)) {
#do somethings, data are available
}
return true;
}
</pre>
<br />
Unfortunately, the sequence of characters intercepted by this method had some issues as, for example, the fact that the white space was not passed to this method. After several attempts I found a workaround due to the fact that a space charachter is passed to onKeyUp method:<br />
<br />
<br />
<pre class="prettyprint linenums lang-java"> @Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
char pressedKey;
if (event.getKeyCode() == KeyEvent.KEYCODE_SPACE || event.getKeyCode() == KeyEvent.KEYCODE_TAB) {
pressedKey = Character.SPACE_SEPARATOR;
usbDecoder.addChar(pressedKey);
}
return true;
} </pre>
<pre class="prettyprint linenums lang-java"> </pre>
zigmundhttp://www.blogger.com/profile/07548914057663250729noreply@blogger.com0tag:blogger.com,1999:blog-3115595461761299132.post-56194481548198941242017-02-11T09:07:00.002-06:002017-02-11T09:09:30.433-06:00RESTFull GEOJson with Swagger and SlimI often find myself having to write RESTFull api for small project. So I have search and tried several tools. I finally choose to use <a href="http://swagger.io/">Swagger</a> to write the documentation and <a href="https://www.slimframework.com/">Slim micro framework</a> to implements it.<br />
<br />
The first step is writing the yalm file in the Swagger editor (there is a nice tutorial at <a href="https://apihandyman.io/writing-openapi-swagger-specification-tutorial-part-1-introduction/">Api Handyman</a> blog). With the yalm specification file it's simple to build an html documentation. Swagger have two pre build schema in html (html and html). You can export it, from Swagger Editor with Generate Client button (where you can export other languages client code).<br />
<br />
To create the Slim skeleton, simply click on the Generate server button and choose Slim. Now you have two zip file that contains documentation and the skeleton code.<br />
<br />
Usually my project folder is composed by three subfolders: app (with the api code), api_doc (with the documentation generated by Swagger) and then an db_doc (the database documentation with diagram).<br />
<br />
To provide a geographic information the request retrive or send a <a href="http://geojson.org/geojson-spec.htm">GEOJson</a>, so I have write a <a href="https://gist.github.com/bubbobne/fe5f2db65acf039be6a9fd92fc9c7233#file-geometry_geojson-yaml"> yalm gist</a> as example.<br />
<br />
To store the data I use PostgresSQL/PostGIS, using this query to retrive the data:<br />
<pre class="prettyprint lang-sql">
SELECT row_to_json(featuresCollection)</pre>
<pre class="prettyprint lang-sql"> FROM ( SELECT 'FeatureCollection' As type,</pre>
<pre class="prettyprint lang-sql"> array_to_json(array_agg(features)) As features</pre>
<pre class="prettyprint lang-sql"> FROM (SELECT 'Feature' As type
,ST_AsGeoJSON(data.the_geom, 4)::json As geometry
, row_to_json((SELECT prop FROM (SELECT property1, property2.....) As prop )) As properties
FROM myTable As data ) As features ) As featuresCollectionc;
</pre>
zigmundhttp://www.blogger.com/profile/07548914057663250729noreply@blogger.com0tag:blogger.com,1999:blog-3115595461761299132.post-40652980079221509352017-01-14T11:03:00.004-06:002017-01-14T11:04:35.768-06:00A leaflet template for ionic<b><a href="http://leafletjs.com/">Leaflet</a> is a very useful javascript library to insert map into an app. It has lots of extensions, which simplify it's use. I use it mainly in ionic's app, so I have created a repo on GitHub as a start point. It's extends the <a href="https://github.com/driftyco/ionic-starter-sidemenu">side menu template</a> with leaflet.</b><br />
<div>
<b><br /></b></div>
<div>
<b>The key points are:</b></div>
<div>
<ol>
<li><b>Get a <a href="http://geojson.org/">GeoJson</a> through an api call (markersApi.js)</b></li>
<li><b>Create a map (with <a href="http://www.openstreetmap.org/">OSM</a> as baselayer).</b></li>
<li><b>Add the GeoJson to the map (using the <a href="https://github.com/Leaflet/Leaflet.markercluster">marker-cluster library</a>).</b></li>
<li><b>Add a marker on tap.</b></li>
</ol>
<h2>
Add the map to the html</h2>
</div>
<div>
To add leaflet map in ionic (and angular) there is a directive to simplify it: <a href="http://tombatossals.github.io/angular-leaflet-directive/#!/">angular-leaflet-directive</a> (or you can use <a href="https://github.com/angular-ui/ui-leaflet">ui-leaflet</a>). In the html you can just put:<br />
<br /></div>
<leaflet data-tap-disabled="true" defaults="map.defaults" id="map" layers="map.layers" lf-center="map.center"></leaflet><b><br /></b>
<b><br /></b>
<b><br /></b>And after you have incluse in the app's model dependencies, the angular-leaflet directive, and have defined an object in the controller as $scope.map which contains the center point when load the map, the layer to load and some optional parameter you can see the map.<br />
<pre class="prettyprint lang-js">
//set the property of the map
$scope.map = {
center: {
lat: 46,
lng: 11,
zoom: 8
},
defaults: {
zoomControl: false,
attributionControl: true
},
layers: {
baselayers: {
xyz: {
name: 'OpenStreetMap (XYZ)',
url: 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
type: 'xyz',
zoomControl: false,
layerOptions: {
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}
}
}
}
};</pre>
<div>
<br />
You also can center the map to the actual position:
<br />
<pre class="prettyprint lang-js">
var options = {enableHighAccuracy: false,timeout: 20000};
//center the map on the actual position.
var setCurrentPosition = function () {
$ionicLoading.show({
template: '<ion-spinner icon="android"></ion-spinner>',
duration: 7000
});
$cordovaGeolocation.getCurrentPosition(options).then(function (position) {
if (position) {
$scope.map.center.lat = position.coords.latitude;
$scope.map.center.lng.longitude = position.coords.longitude;
} else {}
}).catch(function (err) {}).finally(function () {
$ionicLoading.hide();
});
};
</pre>
<h2>
Add markers to the marker</h2>
<div>
The markers are in a GeoJson format, so they are among throughout the <span style="background-color: white; color: #795da3; font-family: "consolas" , "liberation mono" , "menlo" , "courier" , monospace; font-size: 12px; white-space: pre;">L.GeoJSON </span><span style="background-color: white; font-family: "consolas" , "liberation mono" , "menlo" , "courier" , monospace; font-size: 12px; white-space: pre;">layer:</span></div>
<pre class="prettyprint lang-js">
//create a marker cluster layer
var markers = L.markerClusterGroup();
/*
*When the view enter:
* get the map.
* get the markers form the api.
* create the geojson layer
* add the geojson layer to the marker cluster layer
* add the marker cluster layer to the map
*
*/
$scope.$on("$ionicView.enter", function (scopes, states) {
leafletData.getMap("map").then(function (map) {
map.invalidateSize();
markersApi.getPoints().then(function (resp) {
var geojson = new L.GeoJSON(resp, {
onEachFeature: function (feature, layer) {
//open a ionic modal on click
layer.on('click', function (e) {
$scope.map.center.lat = feature.geometry.coordinates[1];
$scope.map.center.lng = feature.geometry.coordinates[0];
$scope.feature = feature;
$scope.openLayersModal();
});
}
});
markers.addLayer(geojson);
map.addLayer(markers);
}, function (err) {
console.log('ERROR', err.status);
});
});
</pre>
<h2>
Add a marker on tap</h2>
<div>
To add a marker on tap, you can add this code:</div>
<div>
<br /></div>
<pre class="prettyprint lang-js">var setMarker = function (latlng) {
if (!newMarker) {
newMarker = new L.marker(latlng).addTo(map);
} else {
newMarker.setLatLng(latlng).update();
}
};
var newMarker = null;
map.on('click', function (e) {
setMarker(e.latlng);
});
</pre>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
the repo is available on GitHub at this <a href="https://github.com/bubbobne/leafletTemplate">link</a>.</div>
<br />
<div>
<b>NOTE: angular-leaflet use leaflet at version 0.7.7 so the marker-cluster is the old version as you can see in the bower.json file.</b></div>
<div>
<div>
<b><br /></b></div>
</div>
</div>
zigmundhttp://www.blogger.com/profile/07548914057663250729noreply@blogger.com0tag:blogger.com,1999:blog-3115595461761299132.post-67402818441250635622017-01-02T08:33:00.003-06:002017-01-02T08:41:18.210-06:00My notes on JavaScriptI started study JavaScript about one years ago, I studied the basic rule and then, due to my work, I moved quickly to use some framework (<a href="https://ionicframework.com/">Ionic</a> and <a href="https://angularjs.org/">Angular</a>) so I omitted to study it in depth and also the best practise... Because of this bad start, this December, I re-started to study and I'm writing some notes (mainly on different things than other languages). <br />
<br />
<h4>
Variables</h4>
<div>
<ul>
<li>keyword <b>const, </b>to declare a constant.</li>
<li><b>Number</b>:</li>
<ul>
<li>Number.<i>NEGATIVE_INFINITY</i><<i>Number.MIN_VALUE</i><<i>Number.MAX_VALUE</i><<i>Number.POSITIVE_INFINITY</i>.</li>
<li>Math is an "object" with the most common mathematic functions.</li>
<li>Some useful method of Number: <i>parseInt(), parseFloat(), isNaN(), isInfinite().</i></li>
</ul>
<li><b>Multiline string</b>, useful to include variable values into the string:
<pre class="prettyprint linenums lang-js"> var a=2;
var b=2;
var myString=`this is
my value ${a+b} `;</pre>
</li>
<h3>
</h3>
</ul>
</div>
<h4>
The if statement</h4>
<div>
<ul>
<li>To test if an array is empty, simply use if(<i>myArray.length</i>) not if(<i>myArray.length>0</i>).</li>
<li>To test if a string is void use if(myString).</li>
<li>Test only if an object is null<i> if(myObj===null)</i> not if it's <i>null</i> and <i>undefined</i>.</li>
</ul>
<h4>
The scope</h4>
</div>
<div>
The scope is a "nested chain": the variable definition is searched in the nested scope, if there isn't then it's search in the upper scope.</div>
<div>
<ul>
<li><a href="http://stackoverflow.com/documentation/javascript/480/scope#t=201701021410055334074">more about scope in Stack Overflow</a></li>
<li><a href="https://en.wikipedia.org/wiki/Immediately-invoked_function_expression">Immediately Invoked Function Expression on wikipedia</a></li>
<li><i>Loops</i> and <i>if</i> statement don't have their own scope in <b>ES5</b>, but <b>ES6</b> introduced it (key-word <i>let</i>).</li>
</ul>
<h4>
Functions</h4>
</div>
<div>
The functions parameters are stored in an object (<i>arguments</i>), similar to an array, so it's possible to retrive parameters with:<i> arguments[i]</i>.</div>
<div>
<br /></div>
<h4>
Collections</h4>
<div>
<ul>
<li>Array</li>
<ul>
<li>it can stores several type.</li>
<li>it's a map, the key is the index. The length() method return the last index plus 1, so <pre class="prettyprint linenums lang-js"> var a=2;
var myArray=[];
myArray[25]="myLastObject";
console.log(myArray.length()); //print 26
</pre>
</li>
<li>Usefull methods: <i>foreach, concat, join, pop, push, shift, unshift, reverse, sort</i>.</li>
</ul>
<li>Maps, only in ES6.</li>
<li>Sets, only in ES6.</li>
</ul>
<h4>
Tools</h4>
</div>
<div>
<ul>
<li><a href="https://bower.io/">bower</a>, package manager.</li>
<li><a href="https://www.npmjs.com/">npm</a>, pakage manager.</li>
<li><a href="http://www.javascriptlint.com/">javascriptlint</a></li>
<li><a href="http://gulpjs.com/">gulp</a>, builder, it's possible run several task (lint, minify resources..).</li>
</ul>
</div>
<div>
<br /></div>
zigmundhttp://www.blogger.com/profile/07548914057663250729noreply@blogger.com0tag:blogger.com,1999:blog-3115595461761299132.post-30498765679402687272016-07-16T04:14:00.001-06:002016-07-16T04:14:31.890-06:00Notes about SQLiteI'm using SQLite in several project, mainly in mobile app (Android SDK or with Cordova plugin).<br />
SQLite is the best solution to store data locally, but when using it? Maybe it's better to understand when does't use it:<br />
<br />
IF data are detached from the app OR there are lots of concurrent writers OR Big Data<br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">THEN t's better build a server side services (client-server)</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">OTHERWISE SQLite</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Main Properties:</span><br />
<br />
<ol>
<li><span style="font-family: Arial, Helvetica, sans-serif;">self-contained</span></li>
<li><span style="font-family: Arial, Helvetica, sans-serif;">serverless</span></li>
<li><span style="font-family: Arial, Helvetica, sans-serif;">zero-configuration</span></li>
<li><span style="font-family: Arial, Helvetica, sans-serif;">transactional: Atomic,Consistent,Isolated, Durable (ACID)</span></li>
</ol>
<br />
<span style="font-family: Arial, Helvetica, sans-serif;">SQLite han't all feature that usually a server side db (as MySQL) have:</span><br />
<br />
<ul>
<li><span style="font-family: Arial, Helvetica, sans-serif;">Right and full outer join.</span></li>
<li><span style="font-family: Arial, Helvetica, sans-serif;">ALTER TABLE isn't completely supported.</span></li>
<li><span style="font-family: Arial, Helvetica, sans-serif;">There isn't Date and Time DataType but it's possible to store data as a REAL (Julian day number), INTEGER (Unix time) or TEXT (ISO8601) and extract it by specific function. I prefer store date as text so for example the today's date is strftime("%s",'now') or use in a query as <span style="color: #bb8844;">"strftime('%Y-%m-%d',DATA_RILIEVO) DESC" </span>where DATA_RILIEVO is the columns name.</span></li>
<li><span style="font-family: Arial, Helvetica, sans-serif;">If an INTEGER column is a primary key then it's an alias of the ROWID column. ROWID set is value to first available integer, otherwise it's possible to use AUTOINCREMENT.</span></li>
<li><span style="font-family: Arial, Helvetica, sans-serif;">I have noticed that multiple primary key isn't always supported.</span></li>
</ul>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<h4>
<span style="font-family: Arial, Helvetica, sans-serif;">reference</span></h4>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;">site <a href="http://www.sqlite.org/index.html">SQLite</a></span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<br />
<br />zigmundhttp://www.blogger.com/profile/07548914057663250729noreply@blogger.com0tag:blogger.com,1999:blog-3115595461761299132.post-13408071846398871122015-12-31T06:51:00.001-06:002016-01-01T07:09:03.594-06:00Chart.js 2.0 in IonicThere are lots JS data chart libraries... it's hard to choose one that's right for you.
I started using <a href="http://www.chartjs.org/">chartjs</a> because it's responsiveness, it has good support for users interactions and there is an angular directives that support it: <a href="http://jtblin.github.io/angular-chart.js/">angular-chart.js</a>. Angulars directive support chart.js 1.0, after some attempts, I have had some issues:<br />
<ol>
<li>Time series aren't supported.</li>
<li>It isn't simple to manage missing value.</li>
</ol>
Then I moved to chart.js 2.0, which was under development. Now, there is a beta version of the <a href="https://github.com/nnnick/Chart.js/releases">library.</a><br />
<br />
So, as first step I have installed it with bower (at https://github.com/nnnick/Chart.js.git#v2.0-dev), and then I try to put it into a Ionic project.
<br />
I have put the chart inside a slider:
<br />
<pre class="prettyprint linenums lang-html"><ion-view view-title="Chart.js 2.0">
<ion-nav-buttons side="left">
<button class="button button-icon button-clear ion-navicon" menu-toggle="left">
</button>
</ion-nav-buttons>
<ion-content>
<ion-refresher on-refresh="doRefresh()" pulling-text="Pull to refresh...">
</ion-refresher>
<ion-slide-box animation="slide-left-right-ios7" show-pager="true">
<ion-slide>
<div class="list card">
<div class="item">
First series
</div>
<div class="item item-body">
<canvas class="chart" height="300" id="firstPlot"></canvas>
</div>
</div>
</ion-slide>
<ion-slide>
<div class="list card">
<div class="item">
Second
</div>
<div class="item item-body">
<canvas class="chart" height="300" id="secondPlot"></canvas>
</div>
</div>
</ion-slide>
</ion-slide-box>
</ion-content>
</ion-view>
</pre>
And the controller code:
<br />
<pre class="prettyprint linenums lang-js">
angular.module('myModule', [])controller('chartCtrl', function ($scope, $ionicSlideBoxDelegate,
$stateParams, $sce , getMyDataServices) {
Chart.defaults.global.pointHitDetectionRadius = 1;
Chart.defaults.global.datasetFill = false;
/*dataToPlot contains 2 series chart1 (which is an array of dimension 3xn => [[],[],[]])
/ and chart2 which is an array 1xn
/ dataToPlot.data contains the labels for x axis.
*/
var dataToPlot=getMyDataServices.getDataToPlot();
var chart1=null;
var chart2=null;
//if I want to plot an interval.
var l = dataToPlot.data.length - 1;
var start = 0;
//if I want to formatting the data
var labels = dataToPlot.data.map(function (d) {
return d;
});
chart1 = createPlot(chart1, {series: [dataToPlot.chart1], serieLabel: ["Plot1 "],
labels: labels,
colors:['rgb(0, 0,255)','rgb(0, 0, 0)', 'rgb(255, 0, 0)']},
start, end, "#plot1a", "[-]");
chart2 = createPlot(chart2, {series: [dataToPlot.chart2], serieLabel: ["Plot2 "],
labels: labels, colors: ['rgb(0, 0, 255)']},
start, end, "#plot2", "[-]");
//update
$scope.$broadcast('scroll.refreshComplete');
$ionicSlideBoxDelegate.update();
$scope.$broadcast('scroll.refreshComplete');
$scope.doRefresh = function () {
getData();
$ionicSlideBoxDelegate.update();
};
});
var opt = {
tooltips: {
mode: 'label'
},
hover: {
mode: 'label'
},
scales: {
xAxes: [{
display: true,
scaleLabel: {
show: true
}
}],
yAxes: [{
display: true,
scaleLabel: {
show: true,
labelString: "void"
}
}]
}, elements: {
line: {
borderCapStyle: 'round',
borderWidth: 1.0,
tension: 0.1
},
point: {
backgroundColor: Chart.defaults.global.defaultColor,
borderWidth: 1,
borderColor: 'rgb(0,0,0)',
hitRadius: 10,
hoverRadius: 5,
hoverBorderWidth: 1,
radius: 2
}
}
};
var createPlot = function (plot, dataToPlot, start, end, id, scaleLabel) {
opt.scales.yAxes[0].scaleLabel.labelString = scaleLabel;
var dataset = [];
if (!!dataToPlot.series) {
for (var i = 0; i < dataToPlot.series.length; i++) {
if (!!dataToPlot.series[i]) {
dataset.push({
label: dataToPlot.serieLabel[i],
data: dataToPlot.series[i].slice(start, end).map(function (x) {
//parse the value to int, only for me
return parseInt(x, 10);
}),
fill: false,
borderColor: dataToPlot.colors[i]
});
}
}
var config = {
type: 'line',
data: {
labels: dataToPlot.labels.slice(start, l),
datasets: dataset
},
options: opt
};
if (plot !== null) {
plot.destroy();
}
var ctx = angular.element(document.querySelector(id));
plot = new Chart(ctx, config);
return plot;
}
};
</pre>
zigmundhttp://www.blogger.com/profile/07548914057663250729noreply@blogger.com0tag:blogger.com,1999:blog-3115595461761299132.post-87064380122750692602015-04-10T10:34:00.000-06:002015-06-15T08:46:29.066-06:00A RESTFul with Openshft, Python + Flask and AeroGearAs a new year's resolution I have started to learn Python. So I have read an introduction to this programming language. Then as next step I have created a RESTful API app. I have found tons of documents but, however, it take<span class="st"> a lot of time and effort... </span><br />
<br />
<h4>
<span class="st">The aim</span></h4>
<h4>
<span class="st"> </span></h4>
<span class="st"><span style="font-weight: normal;"> Build a RESTFul API to store and retrive data. It use MongoDB and AeroGear to send a notification (when new object is stored).</span></span><br />
<h4>
<span class="st"><span style="font-weight: normal;"> </span></span></h4>
<h4>
<span class="st">Tools</span></h4>
<h4>
<span class="st"> </span></h4>
<ol>
<li><span class="st"> <a href="https://openshift.redhat.com/">openshift</a>, as </span><span class="st">hosting platform.</span></li>
<li><span class="st"> Python + <a href="http://flask.pocoo.org/">Flask</a>, to build the RESTFul API. </span></li>
<li><span class="st"> <a href="https://aerogear.org/">AeroGear</a> used to push notification. </span></li>
</ol>
<h4>
</h4>
<h4>
<span class="st">Notification</span><span class="st"> </span></h4>
<h4>
<span class="st"> </span></h4>
<span class="st">The notifications are send with AeroGear. So I have used one of the openshift gears to hosting this service. I also have built an Android App to receive the notification (using<i> Android SDK</i>, <i>AeroGear</i> library for Android and the <i>Google Api</i> to manage push notifications).</span><br />
<br />
<h4>
<span class="st">RESTFull API </span></h4>
<h4>
<span class="st"> </span></h4>
<span class="st">To build the Flask app I have followed this <a href="http://blog.miguelgrinberg.com/post/designing-a-restful-api-with-python-and-flask">tutorial</a> and add some code.</span><br />
This is the required library, in my setup.py:<br />
<br />
<pre class="prettyprint linenums lang-python"> install_requires=['Flask==0.10.1', 'MarkupSafe' ,
'Flask-SQLAlchemy==0.16','Flask-HTTPAuth==2.2.0',
'jsonschema>= 2.3.0','requests'],
</pre>
Then, as simple <i>auth</i> method (the same in the tutorial):
<br />
<pre class="prettyprint linenums lang-python">@auth.get_password
def get_password(username):
if username == "myUserName":
return "myPwd"
return None
@auth.error_handler
def unauthorized():
return make_response(jsonify({"error": "Unauthorized access"}), 401)</pre>
To initialize MongoDB it's necessary to use the environment variables (OPENSHIFT_MONGODB_DB_URL,OPENSHIFT_APP_NAME), as in the getData method:<br />
<br />
<pre class="prettyprint linenums lang-python">@app.route("/api/getMyData/", methods=['GET'])
def getData():
conn = pymongo.Connection(os.environ['OPENSHIFT_MONGODB_DB_URL'])
db = conn[os.environ['OPENSHIFT_APP_NAME']]
result = db.mydata.find()
return str(json.dumps({'results':list(result)},default=json_util.default))
</pre>
The last, and more complicated method is:
<br />
<pre class="prettyprint linenums lang-python">@app.route("/api/setMyData/", methods=['POST'])
@auth.login_required
def createData():
myJson = request.json
with open(os.path.join(os.path.dirname(__file__),"myData.json"),'r') as f:
schema = f.read()
try:
jsonschema.validate(myJson, json.loads(schema))
except jsonschema.ValidationError as e:
return "problem with json schema"
conn = pymongo.Connection(os.environ['OPENSHIFT_MONGODB_DB_URL'])
db = conn[os.environ['OPENSHIFT_APP_NAME']]
mydata = db['mydata']
mydata.insert(myJson)
headers={"Accept":u"application/json", "Content-type": u"application/json"}
url="https://myOpenshift/ag-push/rest/sender/"
resp = requests.post(url, data=json.dumps({
"message": {
"alert": "My first notification!",
"action-category": "cat1",
"sound": "default",
"badge": 2,
"content-available": true,
"user-data": {
"key": "value",
"key2": "other value"
},
"simple-push": "version=1.2"
},
"config": {
"ttl": 3600
}}), auth=requests.auth.HTTPBasicAuth("theAeroGearID", "AeroGearAuth"),headers=headers)
return str(resp)</pre>
This method required some extra imports: jsonschema, requests, json.<br />
<br />
At line 4 i get the json from a curl rerquest :
<br />
<pre class="prettyprint linenums lang-python">curl -i -H "Content-Type: application/json" -X POST
--data '{"idStation": 2,"name": "test","lat": 43,
"lng": 11,"z": 200,"stationOwner": "daniele","lastUpdate": "today"}'
http://myopenschifturl/api/setMyData -u myUserName:myPwd
</pre>
<span class="" id="result_box" lang="en"><span class="hps">From line</span> <span class="hps">5</span> <span class="hps">to</span> <span class="hps">8</span></span>, my json schema is read (from myData.json file) and is verified if actual json has this schema. To read the file it's necessary to use the variable os.path.dirname(__file__) as the root.<br />
<br />
Then if the json is valid, it's stored into the database. My app manages geographic data, so to use these it's necessary to modify the json, and put latitude and longitude in a <i>loc</i> variable. In order to use it in geographical operation enable it with db.points.create_index([('loc', GEO2D)]).<br />
<br />
The last step is send notification to Aerogear. It's mandatory put the data into json.dumps() to avoid trouble to encoding. theAeroGearID and AeroGearAuth are available in the AeroGear dashboard into application.
In the last line I have put the whole signature identifier for HTTPBasicAuth because Flask has it's own HTTPBasicAuth.zigmundhttp://www.blogger.com/profile/07548914057663250729noreply@blogger.com0tag:blogger.com,1999:blog-3115595461761299132.post-67808218583995376052014-10-13T08:04:00.004-06:002014-10-13T10:19:15.065-06:00GeoGig: an useful tool to work with geographic dataIn the past I was looking for a versioning tool for spatial data, but without success... Recently I have found this <a href="http://geogig.org/">geogig</a> project, which seems to be what really is suiting my needs. It's a simple tool for all the guys that have familiarity with <a href="http://git-scm.com/">git and versioning</a> and provides a plugin for <a href="http://geoserver.org/">geoserver</a>.<br />
<br />
I have tried only the basic operations with a shapefile (import, export, add, commit...) and I'm really enthusiastic about how it works. Indeed my purpose for the near future is to use it in a real project and to better test the features available.<br />
<br />
<br />
<br />zigmundhttp://www.blogger.com/profile/07548914057663250729noreply@blogger.com0tag:blogger.com,1999:blog-3115595461761299132.post-67455248003658614382014-08-03T08:42:00.002-06:002014-08-13T05:23:58.266-06:00On the smartphone GPS accuracy<span style="background-color: white;"></span><br />
<div style="text-align: justify;">
As i started playing around <b> Android</b> programming, as soon I got the grip on the basic, I had go deep into "localization".
So I had read a lot of manual pages, web pages and post about it. My first step was to create a class which allow me to select the best <i>location provider,</i> in several study case. So my mainly choice parameter were the requested accuracy, the status of the battery, and if I get the passive data then the age of the <b>Location</b> Object.</div>
<div style="text-align: justify;">
Two fact drawing my attention: the <i>passive provider</i>, and the improve of precision of coordinates when the wi-fi was turned on. So I have investigate how it was work, and I found several blog article or post [2], which explain how it work, and support it by example on how happen when people relocate without changes ("relocate") theirs their's wi-fi hot spot: a catastrophic lack in accuracy of the Location.</div>
<div style="text-align: justify;">
However in the last days I have had some spare time so I have tried to better understand the accuracy of the smart phone devices. First of all I have detected a point with fixed coordinate (in order to compare with Location data). Then I have use my old Localization class to write an App which write into a file all the parameters stored into a Location class.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Before to jump into the data analysis, I would recollect some basics term.</div>
<div style="text-align: justify;">
A devices can have several location providers (A-GPS, GPS, Network, Cell-ID), each of this providers can output a location. In the Android OS a <b>Location</b> [3] is a class with several methods and fields. For the analysis I will consider the following parameters that, accordingly to my opinion are the most important:</div>
<ul style="text-align: justify;">
<li><b>Accuracy</b> <i>(double)</i>: which is only about horizontal value, and is a length, which represent a circle within we have the 0.68 probability to be inside.</li>
<li><b>Latitude</b><i> (double)</i>.</li>
<li><b>Longitude </b><i>(double)</i>.</li>
<li><b>Altitude</b><i> </i><i>(double)</i><b>. </b></li>
<li><b>Time</b> (<i>long</i>), the UCT time of the fix.</li>
<li><b>Bundle<span style="background-color: white;"> </span></b><span style="background-color: white;">(<span style="color: black; display: inline ! important; float: none; font-family: Ubuntu,sans-serif; font-size: 17px; font-style: normal; font-variant: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"><i>android.os.Bundle</i>)</span></span>, which is specific information and depends on the provider.</li>
</ul>
<div style="text-align: justify;">
<b>My App</b></div>
<div style="text-align: justify;">
I have written a simple application
that updates and collects the location data for every available provider,
every 5 seconds for 30 times. I have used an instance of the
class <i>java.util</i>.Timer and have extended the class <i>java.util.TimerTask</i>. For every <b>Location</b> I have extract the fields I have described before and wrote them down in a .csv file.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b>Statistical Analisys</b></div>
<div style="text-align: justify;">
After I had collected the data, I had to find a point with known
coordinates, then with all my devices I collected the information for
that point.</div>
<div style="text-align: justify;">
To simplify the analyses I will not use the accuracy and I'll consider
the
collected data as a single measure (a perfect shot!). However I will use
the known point coordinates and from all the sample values I will
evaluate the
accuarcy with a Circular Error Probability (CERP) set to 0.68 and 0.95.
To perform all the statistical analysis I'll use R [4]. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b>References</b></div>
<div style="text-align: justify;">
<br /></div>
<ol style="text-align: justify;">
<li><a href="http://blog.shinetech.com/2011/10/14/a-good-look-at-android-location-data/">http://blog.shinetech.com/2011/10/14/a-good-look-at-android-location-data/</a></li>
<li> <a href="http://android.stackexchange.com/questions/44608/google-maps-location-history-is-showing-an-incorrect-location">http://android.stackexchange.com/questions/44608/google-maps-location-history-is-showing-an-incorrect-location</a></li>
<li><a href="http://developer.android.com/reference/android/location/Location.html"> http://developer.android.com/reference/android/location/Location.html </a></li>
<li><a href="http://www.r-project.org/"> http://www.r-project.org/</a></li>
</ol>
zigmundhttp://www.blogger.com/profile/07548914057663250729noreply@blogger.com0tag:blogger.com,1999:blog-3115595461761299132.post-22719538924861738902014-08-03T07:53:00.000-06:002014-08-13T05:14:56.484-06:00 Efficient Android Threading, By Anders Goransson, O'Reilly Media<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqDEK_Bd0aqdqVVAMs4EGyaUxSSNr8V89oLYpE0OuezeGglEUB2i_vYNpY6lFC_R1pi4br27SuE-md9lGXHfnjvnXeB5wmnfEKvbCl3wUqOz6pB_EBuOo5K-VT3e3_7B8ZjZGYm_9SgVW3/s1600/cover.gif" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqDEK_Bd0aqdqVVAMs4EGyaUxSSNr8V89oLYpE0OuezeGglEUB2i_vYNpY6lFC_R1pi4br27SuE-md9lGXHfnjvnXeB5wmnfEKvbCl3wUqOz6pB_EBuOo5K-VT3e3_7B8ZjZGYm_9SgVW3/s1600/cover.gif" /></a></div>
<style type="text/css">P { margin-bottom: 0.21cm; }</style>
<br />
<style type="text/css">P { margin-bottom: 0.21cm; }</style>
<br />
<div style="margin-bottom: 0cm;">
I'm not a Java threading expert , so I decided to spend some of my spare time to study it . I started from scratch and then I move to threading in the Android Platform. To achieve this goal I used the Efficient Android Threading book , written by Anders Goransson. Obviously the guide isn't for beginners of Android programming and it requires a minimal knowledge of Android SDK.<br />
<br />
First chapters are dedicated to the basics of threading and how the operating system manages the multi-threading. These chapters allowed me to memorize some concept and to have a better background about the system threading management. The following chapters are focused on how to use the Android framework's multi-threading tools .<br />
<br />
In my opinion this book offers to the readers the opportunity to become familiar with the whole range of techniques that allow to build more responsive Android Apps by using threads. I have appreciated the comparison between available techniques listed in the final chapter that suggests why and when to use one technique over the other In fact, until now I have mainly used the AsyncTask that is one of the most employed technique to realize apps by asynchronous method and I realized that sometimes an alternatives can work better. Using the hints of the book I explored all the possibility and now I can improve my code by use more appropriate techniques for asynchronous programming .<br />
<br />
<br />
<br /></div>
<a href="http://www.oreilly.com/reviews/"><img alt="I review for the O'Reilly Reader Review Program" border="0" src="http://cdn.oreillystatic.com/bloggers/blogger-review-badge-125.png" height="125" width="125" /></a>
zigmundhttp://www.blogger.com/profile/07548914057663250729noreply@blogger.com0tag:blogger.com,1999:blog-3115595461761299132.post-67780423477097464442014-07-20T08:46:00.002-06:002014-07-21T01:21:57.025-06:00Enum to build SQLite database in Android<span class="span9">Over the past few days, </span>I have search a "cleanest" way to manage a SQLite database. If the database contains only one table the simplest solution is to put directly into the <code class="language-java hljs "><span class="line" id="LC15"><span class="hljs-class"><span class="hljs-title"><span style="font-family: inherit;"><i>SQLiteOpenHelper</i></span> </span></span></span></code>a string query to create/update the table. With several tables, In my opinion, it isn't the smartest solution. So to build the sql query and manage the tables I have used <i>Enum</i>.<br />
<br />
I have created two Enum types: Columns and Table.<br />
<br />
The Columns is an Interface which contains an Enum for each table. This Enums are the list of the columns of a table, and have as a value the type of the the variable( INTEGER, REAL,TEXT...), in order to use it to get a piece of query with the getCreateQuery method.
<br />
<pre class="prettyprint linenums lang-java">public interface Columns {
String getCreateQuery();
public enum TableTest1 implements Columns {
ID(INTEGER), COL1(TEXT), COL2(REAL)
private final String value;
private TableTest1(String value) {
this.value = value;
}
@Override
public String getCreateQuery() {
return this.name() + SPACE + this.value;
}
}
public enum TableTest2 implements Columns {
ID(INTEGER), COL1(TEXT), COL2(REAL)
private final String value;
private TableTest1(String value) {
this.value = value;
}
@Override
public String getCreateQuery() {
return this.name() + SPACE + this.value;
}
}
}
</pre>
The second Enum is the list of tables. It contains as a value the corresponding elements in the Columns interface and an activity (I have put the activity because I have for each activity a table).
<br />
<pre class="prettyprint linenums lang-java">public enum Table {
TABLE1(TableTest1.class, Activity1.class),
TABLE2(TableTest2.class, Activity2.class),
private Class value;
private Class activity;
private Table(Class columns,
Class activity) {
value = columns;
this.activity = activity;
}
public Class getTableStrucrure() {
return (Class) value;
}
public Class getActivity() {
return activity;
}
private static final String CREATE = "CREATE TABLE ";
private static final String FIRST = " ( ROWID integer primary key, ";
private static final String LAST = ")";
public String getColumns() {
StringBuilder sb = new StringBuilder(CREATE + this.name() + SPACE);
sb.append(FIRST);
Colonne[] values = value.getEnumConstants();
int length = values.length - 1;
for (int i = 0; i < length; i++) {
sb.append(values[i].getCreateQuery() + COMMA);
}
sb.append(values[length].getCreateQuery());
sb.append(LAST);
return sb.toString();
}
public static String[] getValues(int tipo2) {
List<string> vals = new ArrayList<string>();
for (Tabelle tb : Tabelle.values()) {
if (tb.tipo == tipo2) {
vals.add(tb.name());
}
}
Object[] temp = vals.toArray();
String[] names = new String[temp.length];
for (int i = 0; i < names.length; i++) {
names[i] = temp[i].toString();
}
return names;
}
}</pre>
So in the DBHelper class, to create the table:</br>
<pre class="prettyprint linenums lang-java"> public void onCreate(SQLiteDatabase db) {
for (Table tb : Table.values()) {
db.execSQL(tb.getColumns());
}
}
</pre>
zigmundhttp://www.blogger.com/profile/07548914057663250729noreply@blogger.com1tag:blogger.com,1999:blog-3115595461761299132.post-46153788704146638662014-03-14T05:55:00.000-06:002014-03-14T05:55:33.953-06:00Load raster into QGis with a python script<br />
This week I have started to study PyQGis[2], then I have tried to write a python script to load several raster into the QGis layer .<br />
<br />
My filenames contain date as a part of name, so, instead to load all files in the folder, I have built the file name as a join of two string, the path of the folder and date (extracted from a fixed range -> 01-01-2006 to 01-31-2006). Then I have extracted the maximum and minimum value from this raster, and the value in some fixed point of a shape file.
<br />
<br />
<br />
<pre class="prettyprint linenums lang-python">import datetime
import time
startdate = datetime.date(2006,1,1)
enddate = datetime.date(2006,1,31)
minValue=0
maxValue=0
#load my point
myShapeFile = QgsVectorLayer("/myPath/stazioni.shp", \
"stazioni", "ogr")
myPoint = myShapeFile.getFeatures()</pre>
<pre class="prettyprint linenums lang-python">#iterate to load all raster </pre>
<pre class="prettyprint linenums lang-python">for i in range((enddate-startdate).days + 1):
currentdate = startdate + datetime.timedelta(days=i)
tt=time.strftime("%m-%d", currentdate.timetuple())
fileName=""
fileName=fileName.join(["/myFolderPath/temperature",tt,".asc"])
qgis.utils.iface.addRasterLayer(fileName)
layer1 = qgis.utils.iface.mapCanvas().layer(0)
#iterate over all feature to extract the value
for feature in myPoint:
ident = layer1.dataProvider().identify(feature.geometry().asPoint(),QgsRaster.IdentifyFormatValue)
if ident.isValid():
print ident.results()
maxValue1=layer1.maximumValue(1)
if maxValue < maxValue1 :
maxValue=maxValue1
minValue1=layer1.minimumValue(1)
if minValue > minValue1 :
minValue=minValue1
print(layer1.name())
print("Max")
print(maxValue)
print("Min")
print(minValue)
allLayers = canvas.layers()
for i in allLayers:
</pre>
<br />
References:<br />
<ol>
<li>QGis, http://www.qgis.org</li>
<li>PyQGis Developer CookBook, http://www.qgis.org/en/docs/pyqgis_developer_cookbook/index.html</li>
</ol>
zigmundhttp://www.blogger.com/profile/07548914057663250729noreply@blogger.com0tag:blogger.com,1999:blog-3115595461761299132.post-34585499294556504512014-03-10T07:06:00.002-06:002014-03-16T04:46:24.990-06:00My first plot with xkcd xkcd R package is a tool to enhance the R plot. Usually, I use ggplot2 to build my plot, but I wanted to create "more informal" plot so I found this library [2].<br />
<br />
<br />
1) Install the <b>extrafont </b>e<b> xkcd</b> and <b>sysfonts</b> packages (I have had some problem with update packages, so before I have run<br />
<br />
<pre class="prettyprint lang-r">update.packages(checkBuilt = TRUE, ask = FALSE)
</pre>
<br />
And then install xkcd from R repository and extrafont from downloaded code. The sysfonts required to install free-type (sudo apt-get install freetype*)<br />
<br />
<br />
2) Install fonts from <i>http://simonsoftware.se/other/xkcd.ttf</i> within the R console<br />
<br />
<br />
<pre class="prettyprint lang-r">library(ggplot2)
library(extrafont)
if(! "xkcd" %in% fonts()) {
xkcdFontURL <- "http://simonsoftware.se/other/xkcd.ttf"
download.file(xkcdFontURL,dest="xkcd.ttf")
font_import(".")
## because we downloaded to working directory
loadfonts()
}
</pre>
<br />
<br />
3) Install ggplot (In R)<br />
<br />
<pre class="prettyprint lang-r">library(ggplot2)
library(xkcd)
library(extrafont)
library(lubridate)
wind<- read.table(file = myFile, header =TRUE)
wind$date<-as.character(datiVento$date)
wind$date<-ymd(wind$date)
wind$doy<-yday(wind$date)
p<-ggplot(wind,aes(wind$doy,wind$media))+geom_point()+xkcdaxis(range(c(1,366)),range(c(1,20)))+facet_wrap(~
station)+ylab("velocita' [m/s]")+xlab("day of year")
ggsave(myOutFile)
</pre>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZPMZ8CLs8m8bkmXqOKU5LcWjNR9yYCZdrcmwo_N_mmVYlK5tZKql6XLen2eOYrvwIM6J47UZgmMCxQGaAFTiDdFfnomX8AagMCo_Nz_fMjIZwkQVdQPYOtqs-qGpSxs0q0aK3i2ac3dsg/s1600/testXkcd.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZPMZ8CLs8m8bkmXqOKU5LcWjNR9yYCZdrcmwo_N_mmVYlK5tZKql6XLen2eOYrvwIM6J47UZgmMCxQGaAFTiDdFfnomX8AagMCo_Nz_fMjIZwkQVdQPYOtqs-qGpSxs0q0aK3i2ac3dsg/s400/testXkcd.png" /></a></div>
And to obtain a bar plot of the speed class:
<br />
<pre class="prettyprint lang-r">wind<-wind[wind$stazione=='myStation',]
scalaBeaufort<-c(0.0,0.3,1.5,3.4,5.4,7.9,10.7,13.8,17.1,20.7,24.4,28.4,32.6,50)
wind$speedClass<-NA
n&lt-13
for(i in 1:n){
inf&lt-scalaBeaufort[i]
sup&lt-scalaBeaufort[i+1]
wind[!is.na(wind$media) & wind$media >=inf & wind$media < sup,c("speedClass")]<&lt-i-1
}
freqWind<-table(wind$speedClass)
freqWind<-data.frame(y=as.numeric(freqWind),x=as.numeric(names(freqWind)))
freqWind$xmin <- freqWind$x - 0.1
freqWind$xmax <- freqWind$x + 0.1
freqWind$ymin <- 0
freqWind$ymax <- freqWind$y
xrange<-range(c(-0.1,3))
yrange<-range(c(0,350))
mapping<-aes(xmin=xmin,ymin=ymin,xmax=xmax,ymax=ymax)
p<-ggplot()+themexkcd()+ xkcdrect(mapping,freqWind)+
xkcdaxis(xrange,yrange)+scale_x_discrete(breaks = 0:2, labels=c("0","1","2")) +
xlab(NULL)
</pre>
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9Fr46x1l-NeW-Z3R6fe6iJyDkHMJmf-L4e7MvC61AU_VAIQwB8uyDBvlL1De_s5Y4vQ3A0dWP_yrLBjOEtbiYPoVafhc6EFubK-ZIS4D9H2aD19PH173cJ4laSsVHStECDjUOVreiKSF4/s1600/testXkcd2.png" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9Fr46x1l-NeW-Z3R6fe6iJyDkHMJmf-L4e7MvC61AU_VAIQwB8uyDBvlL1De_s5Y4vQ3A0dWP_yrLBjOEtbiYPoVafhc6EFubK-ZIS4D9H2aD19PH173cJ4laSsVHStECDjUOVreiKSF4/s320/testXkcd2.png" /></a>
<br />
<br />
4)Next step working with map...<br />
<br />
<br />
<b>references </b>
<br />
<ol>
<li><b> R http://www.r-project.org/</b></li>
<li><b> xkcd - http://xkcd.r-forge.r-project.org/</b></li>
<li><b> ggplot2 - http://ggplot2.org/</b></li>
<li><b> lubridate - http://cran.r-project.org/web/packages/lubridate/index.html</b></li>
</ol>
zigmundhttp://www.blogger.com/profile/07548914057663250729noreply@blogger.com0tag:blogger.com,1999:blog-3115595461761299132.post-33652732238500599902014-03-10T06:50:00.000-06:002014-03-10T09:19:36.624-06:00My Coursera Maps and the Geospatial Revolution Peer AssessmentThe purpose of my work has been to understand how my neighbor spent theirs spare time during the summer. The sample has been composed to the twitter users that has published tweet in a range of 150km from my house. Only few alternatives has been exterminated. So it has been extracted the tweet contains four keywords (lake, MUSE, MART or climbing) and no other hypothesis or check has been made on the the text.
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkc-V55iDXM31qkFZ46wY9-zc9Yj_xe85R03uIB4Juit68dJpJInILuHlw9tK7cSjC5ERznl-fbFV4ay1bfIM7DweOsxipISwhUdMSubrui9Dcz-IUMUqiQ3dpLruzOfVgABqCnL2mZF0g/s1600/laurea2.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkc-V55iDXM31qkFZ46wY9-zc9Yj_xe85R03uIB4Juit68dJpJInILuHlw9tK7cSjC5ERznl-fbFV4ay1bfIM7DweOsxipISwhUdMSubrui9Dcz-IUMUqiQ3dpLruzOfVgABqCnL2mZF0g/s320/laurea2.jpeg" /></a></div>
zigmundhttp://www.blogger.com/profile/07548914057663250729noreply@blogger.com0