Can we use the same API that Google Latitude APP is using for discovering location? - cellid

I have a device that sends me
Mobile Country Code (MCC)
Mobile Network Code (MNC)
Location area code (LAC)
and
Cell ID
of each closest mobile tower in my region. Google Latitude APP is using this info to detect my location. I would like to make my own app that could use same technique, but I can't find any Google API description.
There is a possibility to use OpenCellID for my purpose, but there are no CellIDs available for country where I live.
There are some posts where are outdated links to API which I need https://developers.google.com/gears/ and http://www.google.com/glm/mmap but seems like none of them work anymore.

You can try using google Maps api:
https://developers.google.com/maps/?hl=es
They there's an option &sensor=true to detect if you are trying to get the latitude and longitude from a device.

Here is a PHP script that takes parameters mcc, mnc, lac and cid and returns latitude:longitude if a result is available, NOT_FOUND if no result is found. This makes use of the same Google API you've mentioned.
<?php
$data =
"\x00\x0e".
"\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00".
"\x00\x00".
"\x00\x00".
"\x1b".
"\x00\x00\x00\x00".
"\x00\x00\x00\x00".
"\x00\x00\x00\x03".
"\x00\x00".
"\x00\x00\x00\x00".
"\x00\x00\x00\x00".
"\x00\x00\x00\x00".
"\x00\x00\x00\x00".
"\xff\xff\xff\xff".
"\x00\x00\x00\x00"
;
$mcc = substr("00000000".dechex($_REQUEST["mcc"]),-8);
$mnc = substr("00000000".dechex($_REQUEST["mnc"]),-8);
$lac = substr("00000000".dechex($_REQUEST["lac"]),-8);
$cid = substr("00000000".dechex($_REQUEST["cid"]),-8);
$init_pos = strlen($data);
$data[$init_pos - 38]= pack("H*",substr($mnc,0,2));
$data[$init_pos - 37]= pack("H*",substr($mnc,2,2));
$data[$init_pos - 36]= pack("H*",substr($mnc,4,2));
$data[$init_pos - 35]= pack("H*",substr($mnc,6,2));
$data[$init_pos - 34]= pack("H*",substr($mcc,0,2));
$data[$init_pos - 33]= pack("H*",substr($mcc,2,2));
$data[$init_pos - 32]= pack("H*",substr($mcc,4,2));
$data[$init_pos - 31]= pack("H*",substr($mcc,6,2));
$data[$init_pos - 24]= pack("H*",substr($cid,0,2));
$data[$init_pos - 23]= pack("H*",substr($cid,2,2));
$data[$init_pos - 22]= pack("H*",substr($cid,4,2));
$data[$init_pos - 21]= pack("H*",substr($cid,6,2));
$data[$init_pos - 20]= pack("H*",substr($lac,0,2));
$data[$init_pos - 19]= pack("H*",substr($lac,2,2));
$data[$init_pos - 18]= pack("H*",substr($lac,4,2));
$data[$init_pos - 17]= pack("H*",substr($lac,6,2));
$data[$init_pos - 16]= pack("H*",substr($mnc,0,2));
$data[$init_pos - 15]= pack("H*",substr($mnc,2,2));
$data[$init_pos - 14]= pack("H*",substr($mnc,4,2));
$data[$init_pos - 13]= pack("H*",substr($mnc,6,2));
$data[$init_pos - 12]= pack("H*",substr($mcc,0,2));
$data[$init_pos - 11]= pack("H*",substr($mcc,2,2));
$data[$init_pos - 10]= pack("H*",substr($mcc,4,2));
$data[$init_pos - 9]= pack("H*",substr($mcc,6,2));
if ((hexdec($cid) > 0xffff) && ($mcc != "00000000") && ($mnc != "00000000")) {
$data[$init_pos - 27] = chr(5);
} else {
$data[$init_pos - 24]= chr(0);
$data[$init_pos - 23]= chr(0);
}
$context = array (
'http' => array (
'method' => 'POST',
'header'=> "Content-type: application/binary\r\n"
. "Content-Length: " . strlen($data) . "\r\n",
'content' => $data
)
);
$xcontext = stream_context_create($context);
$str=file_get_contents("http://www.google.com/glm/mmap",FALSE,$xcontext);
if (strlen($str) > 10) {
$lat_tmp = unpack("l",$str[10].$str[9].$str[8].$str[7]);
$lon_tmp = unpack("l",$str[14].$str[13].$str[12].$str[11]);
$lon = $lon_tmp[1]/1000000;
$lat = $lat_tmp[1]/1000000;
echo $lat.":".$lon;
}
else{echo "NOT_FOUND";}
?>
Save the code as a php file (I've used locate.php in the example below), upload it to your web host and you can make a query as :
http://yourwebhost.com/locate.php?mcc=XXX&mnc=XXX&lac=XXXXX&cid=XXXXXXXX
You can then parse the response obtained to get latitude and longitude information.

Related

Scala.js event handling

I'm writing a little Scala.Js app that uses two event handlers: one for an input field's onkeyup event and another for a button's onclick event.
The two event handlers share quite a bit of common coding, but as soon as I try to optimise the event handler coding into a single function that returns an event handler function, it compiles correctly, but events are no longer trapped in the browser.
In the following code in function main, the event handler for btn.onclick works fine, but the event handler for cityNameInput.onkeyup no longer works. All I did was copy the coding assigned directly to the event handler, and put it in a function called keystrokeHandler that returns a Function1[dom.Event, _]. This compiles OK, but the onkeyup event is no longer trapped in the browser.
def keystrokeHandler(userInput: String, responseDiv: dom.Element): Function1[dom.Event,_] =
(e: dom.Event) => {
// The city name must be at least 4 characters long
if (userInput.length > 3) {
responseDiv.innerHTML = ""
val xhr = buildXhrRequest(userInput, searchEndpoint)
xhr.onload = (e: dom.Event) => {
val data: js.Dynamic = js.JSON.parse(xhr.responseText)
// Can any cities be found?
if (data.count == 0)
// Nope, so show error message
responseDiv.appendChild(p(s"Cannot find any city names starting with ${userInput}").render)
else {
// Build a list of weather reports
buildSearchList(data, responseDiv)
}
}
// Send XHR request to OpenWeather
xhr.send()
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Main program
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#JSExport
def main(container: dom.html.Div): Unit = {
container.innerHTML = ""
val cityNameInput = input.render
val btn = button.render
val weatherDiv = div.render
cityNameInput.defaultValue = owmQueryParams.get("q").get
btn.textContent = "Go"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Button onclick event handler
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
btn.onclick = (e: dom.Event) => {
if (cityNameInput.value.length > 3) {
weatherDiv.innerHTML = ""
val xhr = buildXhrRequest(cityNameInput.value, weatherEndpoint)
xhr.onload = (e: dom.Event) => {
val data = js.JSON.parse(xhr.responseText)
// Can the city be found?
if (data.cod == "404")
// Nope, so show error message
weatherDiv.appendChild(p(s"City ${cityNameInput.value} not found").render)
else {
// So first add the div containing both the weather information
// and the empty div that will hold the slippy map.
// This is needed because Leaflet writes the map information to an
// existing DOM element
val report = new WeatherReportBuilder(data)
weatherDiv.appendChild(buildWeatherReport(report, 0))
buildSlippyMap("mapDiv0", report)
}
}
// Send XHR request to OpenWeather
xhr.send()
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Input field onkeyup event handler
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
cityNameInput.onkeyup = keystrokeHandler(cityNameInput.value, weatherDiv)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Write HTML to the screen
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
container.appendChild(
div(
h1("Weather Report"),
table(
tr(td("Enter a city name (min 4 characters)"), td(cityNameInput)),
tr(td(), td(style := "text-align: right", btn))
),
weatherDiv
).render
)
}
What's the problem here?
Should the keystrokeHandler function return some special Scala.Js event handler type? Or is it something else?
Thanks
Chris W
I think the problem is here:
cityNameInput.onkeyup = keystrokeHandler(cityNameInput.value, weatherDiv)
The event handler is triggered, but the userInput is frozen to cityNameInput.value at the time the handler was created, instead of varying with the current value of cityNameInput.value. Indeed, that line is equivalent to
val userInput = cityNameInput.value
cityNameInput.onkeyup = keystrokeHandler(userInput, weatherDiv)
which makes it obvious that cityNameInput.value is only evaluated once.
Instead, you should give cityNameInput itself as parameter to keystrokeHandler, and access cityNameInput.value inside the anonymous function, so that it is evaluated every time the function (handler) is called.

Can I suppress vacuous 'More...' links on Doxygen class reference pages?

A Doxygen class reference page consists primarily of lists of class members, each followed by its brief description (if such exists). The member proper is a link to a details page for that member. Invariably the brief description is followed by a 'More...' link. The content of this link is identical to that of the member proper. This 'More...' link suggests - at least to me - that a more extended description is available at the other end of that link. This is misleading when the member has only a brief description. In that case the link points to a page which simply repeats that brief description and then states "Definition at line NN of file abcxyz.ext."
Is there anyway to get Doxygen to suppress these frustratingly vacuous 'More...' links?
Experimental patch for doxygen 1.8.10, which allows you to remove the "More..." links by using "USE_MORE_LINK = NO" in Doxyfile.
<!-- language: diff -->
=== modified file 'src/classdef.cpp'
--- src/classdef.cpp 2015-07-06 11:29:12 +0000
+++ src/classdef.cpp 2015-07-06 11:37:57 +0000
## -1802,12 +1802,14 ##
// HTML only
ol.pushGeneratorState();
- ol.disableAllBut(OutputGenerator::Html);
- ol.docify(" ");
- ol.startTextLink(getOutputFileBase(),
- anchor.isEmpty() ? QCString("details") : anchor);
- ol.parseText(theTranslator->trMore());
- ol.endTextLink();
+ if (Config_getBool("USE_MORE_LINK")) {
+ ol.disableAllBut(OutputGenerator::Html);
+ ol.docify(" ");
+ ol.startTextLink(getOutputFileBase(),
+ anchor.isEmpty() ? QCString("details") : anchor);
+ ol.parseText(theTranslator->trMore());
+ ol.endTextLink();
+ }
ol.popGeneratorState();
if (!anchor.isEmpty())
=== modified file 'src/config.xml'
--- src/config.xml 2015-07-06 11:29:12 +0000
+++ src/config.xml 2015-07-06 11:57:09 +0000
## -366,6 +366,13 ##
]]>
</docs>
</option>
+ <option type='bool' id='USE_MORE_LINK' defval='1'>
+ <docs>
+<![CDATA[
+ Experimental parameter, which allows you to remove the "More..." links by using USE_MORE_LINK = NO.
+]]>
+ </docs>
+ </option>
<option type='list' id='ABBREVIATE_BRIEF' format='string'>
<docs>
<![CDATA[
=== modified file 'src/filedef.cpp'
--- src/filedef.cpp 2015-07-06 11:29:12 +0000
+++ src/filedef.cpp 2015-07-06 11:31:41 +0000
## -373,8 +373,8 ##
ol.writeString(" \n");
ol.enable(OutputGenerator::RTF);
- if (Config_getBool("REPEAT_BRIEF") ||
- !documentation().isEmpty()
+ if ( (Config_getBool("REPEAT_BRIEF") || !documentation().isEmpty() ) &&
+ Config_getBool("USE_MORE_LINK")
)
{
ol.disableAllBut(OutputGenerator::Html);
=== modified file 'src/memberdef.cpp'
--- src/memberdef.cpp 2015-07-06 11:29:12 +0000
+++ src/memberdef.cpp 2015-07-06 11:37:48 +0000
## -1805,22 +1805,24 ##
{
static bool separateMemberPages = Config_getBool("SEPARATE_MEMBER_PAGES");
ol.pushGeneratorState();
- ol.disableAllBut(OutputGenerator::Html);
- //ol.endEmphasis();
- ol.docify(" ");
- if (separateMemberPages ||
- (m_impl->group!=0 && gd==0) ||
- (m_impl->nspace!=0 && nd==0)
- ) // forward link to the page or group or namespace
- {
- ol.startTextLink(getOutputFileBase(),anchor());
- }
- else // local link
- {
- ol.startTextLink(0,anchor());
- }
- ol.parseText(theTranslator->trMore());
- ol.endTextLink();
+ if (Config_getBool("USE_MORE_LINK")) {
+ ol.disableAllBut(OutputGenerator::Html);
+ //ol.endEmphasis();
+ ol.docify(" ");
+ if (separateMemberPages ||
+ (m_impl->group!=0 && gd==0) ||
+ (m_impl->nspace!=0 && nd==0)
+ ) // forward link to the page or group or namespace
+ {
+ ol.startTextLink(getOutputFileBase(),anchor());
+ }
+ else // local link
+ {
+ ol.startTextLink(0,anchor());
+ }
+ ol.parseText(theTranslator->trMore());
+ ol.endTextLink();
+ }
//ol.startEmphasis();
ol.popGeneratorState();
}
(Tentative answer as this particular case is not something I've ever needed to do.)
In the case that you want to remove all detailed descriptions (and thus, presumably, the links to it) you might be able to modify the 'layout' file to make that section invisible.
Reference: http://www.doxygen.nl/manual/customize.html#layout
Alternatively..
From your description it sounds like REPEAT_BRIEF is set on. If there really is no description beyond the first full stop then you may find that turning REPEAT_BRIEF off will remove the link, as the text there will truly be vacuous.
It might be a bit late but I faced the same problem and solved it easily, with the following doxyfile configuration:
ALWAYS_DETAILED_SEC = NO
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = NO
EXTRACT_ALL = NO
# Since EXTRACT_ALL is NO, configure the following as you wish. In my case
EXTRACT_PRIVATE = YES
EXTRACT_STATIC = YES
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = YES
I hope that helps.

Grails findAllByRole() error

I am trying to send email to all users with admin role when list() action has been called.
Inside my list method I put the following code:
def admins = User.findAllByRole("ROLE_ADMIN")
//def approverEmails = User.findByRole("ROLE_APPROVER").collect { it.email }
notifierService.sendApproverRequestEmail(admins)
flash.message = message(code: 'default.created.message', args: [message(code: 'project.label', default: 'Project'), projectInstance.id])
redirect(action: "show", id: projectInstance.id)
But Grails doesn't recognize findAllByRole() method. What am I doing wrong? Is there any other way to send message from service when certain actions in controller are called.
Here is also my service code:
def sendApprovalRequestEmail( def users ) {
users.each { -> user
mailService.sendMail{
to user.email
from "padre#everyonecounts.com"
subject "New project needs approval."
body "Hi ${user.username}! " +
"New project has been requested and needs your approval."
}
}
}
Here is the error:
URI
/PaDRe/project/list
Class
org.codehaus.groovy.grails.exceptions.InvalidPropertyException
Message
No property found for name [role] for class [class com.everyonecounts.padre.User]
Around line 21 of grails-app\controllers\com\everyonecounts\padre\ProjectController.groovy
18: params.max = Math.min(params.max ? params.int('max') : 10, 100)
19: [projectInstanceList: Project.list(params), projectInstanceTotal: Project.count()]
20:
21: def admins = User.findAllByRole("ROLE_ADMIN")
22: //def approverEmails = User.findByRole("ROLE_APPROVER").collect { it.email }
23: notifierService.sendApproverRequestEmail(admins)
24:
Trace
Line | Method
->> 108 | methodMissing in org.grails.datastore.gorm.GormStaticApi
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 21 | list in ProjectController.groovy
| 895 | runTask . . . in java.util.concurrent.ThreadPoolExecutor$Worker
| 918 | run in ''
^ 662 | run . . . . . in java.lang.Thread
Here is my User class
package com.everyonecounts.padre
class User{
transient springSecurityService
String username
String password
String email
boolean enabled
boolean accountExpired
boolean accountLocked
boolean passwordExpired
static constraints = {
username blank: false, unique: true
password size: 5..80, blank: false
}
static mapping = {
password column: '`password`'
}
Set<Role> getAuthorities() {
UserRole.findAllByUser(this).collect { it.role } as Set
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}
}
The problem you are having is because you don't understand the default spring security implementation. To get a list of users with a given role:
UserRole.findAllByRole(Role.findByAuthority("ROLE_ADMIN"))*.user
Your problem probably is that User.findAllByRole() is expecting a Role as the argument, not a String.
There is a relevant example in 'Querying Associations' subsection of http://grails.org/doc/2.2.x/guide/single.html#finders (shown below)
def author = Author.findByName("Stephen King")
def books = author ? Book.findAllByAuthor(author) : []

Sinatra + Rack routing

I have an app file that looks like this ws_app.rb:
require 'rubygems'
require 'sinatra'
require 'sinatra/respond_to'
require 'dm-core'
require 'dm-migrations'
require 'dm-timestamps'
require 'json'
require 'csv'
load 'models/Battery.rb'
Sinatra::Application.register Sinatra::RespondTo
DataMapper::setup(:default,"sqlite3://#{Dir.pwd}/mpt_hmi.sqlite3")
class MPTHMI < Sinatra::Base
load 'controller/BatteryController.rb'
end
The modules/Battery.rb looks like this:
class Battery
include DataMapper::Resource
property :id, Serial
property :i_battery_manager_id, Integer
property :c_battery_number, String
property :c_battery_state, String
property :c_voltage_byte, String
property :i_voltage_int, Integer
property :i_temperature, Integer
property :i_resistance, Integer
property :i_capacity, Integer
property :i_cell_balancing_duration, Integer
property :i_total_cell_balancing_duration, Integer
property :i_age, Integer
property :i_time_to_service, Integer
property :created_at, DateTime
property :updated_at, DateTime
def to_my_json
{
:i_battery_manager_id => self.i_battery_manager_id,
:c_battery_number => self.c_battery_number,
:c_battery_state => self.c_battery_state,
:c_voltage_byte => self.c_voltage_byte,
:i_voltage_int => self.i_voltage_int,
:i_temperature => self.i_temperature,
:i_resistance => self.i_resistance,
:i_capacity => self.i_capacity,
:i_cell_balancing_duration => self.i_cell_balancing_duration,
:i_total_cell_balancing_duration => self.i_total_cell_balancing_duration,
:i_age => self.i_age,
:i_time_to_service => self.i_time_to_service
}
end
end
The controller/BatteryController.rb file looks like this:
get '/battery/:id' do
#battery = Battery.get(params[:id])
respond_to do |wants|
wants.html { erb :battery } # html
wants.json { #battery.to_my_json.to_s } # json
end
end
get '/batteries' do
#batteries = Battery.all
respond_to do |wants|
wants.html { erb :batteries } # html
wants.json {
#batteries.all.inject({}) { |hsh, obj|
hsh[obj.id] = obj.to_my_json
hsh
}.to_json
}
end
end
This works perfectly when I run Sinatra normally, like so:
$ ruby ws_app.rb
== Sinatra/1.3.2 has taken the stage on 4567 for development with backup from Thin
>> Thin web server (v1.3.1 codename Triple Espresso)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:4567, CTRL+C to stop
Then go here:
http://0.0.0.0:4567/battery/5.json
I get the JSON I'm expecting:
{:i_battery_manager_id=>1, :c_battery_number=>"5", :c_battery_state=>"3", :c_voltage_byte=>"145", :i_voltage_int=>191, :i_temperature=>107, :i_resistance=>81, :i_capacity=>228, :i_cell_balancing_duration=>127, :i_total_cell_balancing_duration=>37, :i_age=>111, :i_time_to_service=>211}
but I need to deploy this on a Cherokee web server, so I want to make a rack config.ru file for this...
So I have a file mpthmiws.rb which contains
load 'ws_app.rb'
MPTHMI.run
And a config.ru file which contains
load 'mpthmiws.rb'
run MPTHMI.new
When I run
$ rackup config.ru
>> Thin web server (v1.3.1 codename Triple Espresso)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:9292, CTRL+C to stop
and go here:
http://0.0.0.0:9292/battery/1.json
but then I get the famous, "Sinatra doesn't know this ditty - try get '/battery/1.json' do "Hello World" end
If I take the first route from the controller/BatteryController.rb file and put it inside HMIMPT class in the ws_app.rb file like this:
require 'rubygems'
require 'sinatra'
require 'sinatra/respond_to'
require 'dm-core'
require 'dm-migrations'
require 'dm-timestamps'
require 'json'
require 'csv'
load 'models/Battery.rb'
Sinatra::Application.register Sinatra::RespondTo
DataMapper::setup(:default,"sqlite3://#{Dir.pwd}/mpt_hmi.sqlite3")
class MPTHMI < Sinatra::Base
get '/battery/:id' do
#battery = Battery.get(params[:id])
respond_to do |wants|
wants.html { erb :battery } # html
wants.json { #battery.to_my_json.to_s } # json
end
end
end
I get this error:
undefined method `respond_to' for #<MPTHMI:0x00000001240a80>
How can I resolve this?
Thanks
First of all, that thing with mpthmiws.rb and config.ru is overly complicated. Delete mpthmiws.rb and use this config.ru for use with rackup config.ru:
require './ws_app'
run MPTHMI
If you want to run the App with plain old ruby ws_app.rb, use this run.rb file:
require './ws_app'
MPTHMI.run!
Which brings us to the next point: NEVER EVER USE load! It executes the code in the loaded file, but it does not bring over any defined variables, functions etc. Use require instead! Here you must prefix the path with ./ or add ./ to $LOAD_PATH, but in turn you can omit the .rb extension.
Next is your BatteryController.rb file. It should look like this:
require 'sinatra/respond_to'
class BatteryController < Sinatra::Base
register Sinatra::RespondTo
get '/battery/:id' do
# ...
end
get '/batteries' do
# ...
end
end
And this is also the point where you register your extensions — in the class where you need it.
Now that we understand how load works, you may already have noticed that you were not actually loading the get blocks into the MPTHMI class, but rather executing them outside of the class. That is the only reason why your app worked anyway with plain old ruby ws_app.rb!
You can properly include your controller into a class with use:
# require all your gems
# ...
require './models/Battery'
require './controller/BatteryController'
DataMapper::setup(:default,"sqlite3://#{Dir.pwd}/mpt_hmi.sqlite3")
class MPTHMI < Sinatra::Base
use BatteryController
end
You can also leave off the register in here. Feel free to comment if you have further questions!
And here's the full diff:
diff --git a/config.ru b/config.ru
index eaa15fe..1568544 100644
--- a/config.ru
+++ b/config.ru
## -1,3 +1,3 ##
-load 'mpthmiws.rb'
+require './ws_app'
-run MPTHMI.new
+run MPTHMI
diff --git a/controller/BatteryController.rb b/controller/BatteryController.rb
index 31e4910..c500c48 100644
--- a/controller/BatteryController.rb
+++ b/controller/BatteryController.rb
## -1,20 +1,27 ##
-get '/battery/:id' do
- #battery = Battery.get(params[:id])
- respond_to do |wants|
- wants.html { erb :battery } # html
- wants.json { #battery.to_my_json.to_s } # json
- end
-end
+require 'sinatra/respond_to'
-get '/batteries' do
- #batteries = Battery.all
- respond_to do |wants|
- wants.html { erb :batteries } # html
- wants.json {
- #batteries.all.inject({}) { |hsh, obj|
- hsh[obj.id] = obj.to_my_json
- hsh
- }.to_json
- }
+class BatteryController < Sinatra::Base
+ register Sinatra::RespondTo
+
+ get '/battery/:id' do
+ #battery = Battery.get(params[:id])
+ respond_to do |wants|
+ wants.html { erb :battery } # html
+ wants.json { #battery.to_my_json.to_s } # json
+ end
end
-end
+
+ get '/batteries' do
+ #batteries = Battery.all
+ respond_to do |wants|
+ wants.html { erb :batteries } # html
+ wants.json {
+ #batteries.all.inject({}) { |hsh, obj|
+ hsh[obj.id] = obj.to_my_json
+ hsh
+ }.to_json
+ }
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/mpt_hmi.sqlite3 b/mpt_hmi.sqlite3
index e69de29..9897cd9 100644
Binary files a/mpt_hmi.sqlite3 and b/mpt_hmi.sqlite3 differ
diff --git a/mpthmiws.rb b/mpthmiws.rb
deleted file mode 100644
index 87f3406..0000000
--- a/mpthmiws.rb
+++ /dev/null
## -1,3 +0,0 ##
-load 'ws_app.rb'
-
-MPTHMI.run
diff --git a/ws_app.rb b/ws_app.rb
index 1cab867..4a6e332 100644
--- a/ws_app.rb
+++ b/ws_app.rb
## -1,19 +1,18 ##
require 'rubygems'
require 'sinatra'
-require 'sinatra/respond_to'
require 'dm-core'
require 'dm-migrations'
require 'dm-timestamps'
require 'json'
require 'csv'
-load 'models/Battery.rb'
+require './models/Battery'
+require './controller/BatteryController'
-Sinatra::Application.register Sinatra::RespondTo
DataMapper::setup(:default,"sqlite3://#{Dir.pwd}/mpt_hmi.sqlite3")
class MPTHMI < Sinatra::Base
-
- load 'controller/BatteryController.rb'
+
+ use BatteryController
end

help with perl foreach loop

I need help figuring out where to call my send_mail (). Where I currently place it in the code, it sends out an email for every condition and each email it sends it adds another record as part of the set. I'm only interested in sending a single email with the collected records, the last email shown (msg4). Can I do this within the same loop? I'm not sure.
Example:
(msg1)
Service: MST Engine - Stopped - Manual
(msg2):
Service: MST Engine - Stopped - Manual
Service: MST Logging - Stopped - Manual
(msg3):
Service: MST Engine - Stopped - Manual
Service: MST Logging - Stopped - Manual
Service: MST Server - Stopped - Manual
(msg4): (intersted in only this email)
Service: MST Engine - Stopped - Manual
Service: MST Logging - Stopped - Manual
Service: MST Server - Stopped - Manual
Service: MST Formatter - Stopped - Manual
Here is the main piece where I set the conditions:
(I'm using Win32::OLE package has a method in(COLLECTION). So its not an array reference.)
foreach my $serv (in $servSet)
{
next if $serv->{started};
my $sname = $serv->{name};
my $sstate = $serv->{started};
my $ssmode = $serv->{startmode};
$winsvcs .= "Service: $sname - $servicestate[$sstate] - $ssmode\n";
send_email();
}
Move the send_email call out of the loop or it will call it every time it goes through the loop. I assume the function just sends the contents of $winsvcs.
my $winsvcs = '';
foreach my $serv (in $servSet) {
next if $serv->{started};
my $sname = $serv->{name};
my $sstate = $serv->{started};
my $ssmode = $serv->{startmode};
$winsvcs .= "Service: $sname - $servicestate[$sstate] - $ssmode\n";
}
send_email();