Google Maps searchbox with autocomplete

I was sitting trying to do some mods on a Queclink GL200 GPS transmitter for the MPS project. After many hours of no luck at all I gave up for the day. If anyone have some input on that please contact me!

So i started messing around with the Google Maps API demo that I made for them instead. Adding some auto complete to the search form instead. I thought I would share what I managed to do. The challange is to do a mach up of Google Maps API and jQuery to get it to work good.

The trick is to attach the jQuery handler to the object. Why?
You have to create the search box dynamically in order to push it on top of the Google Maps canvas.

Entire demo can be found here: http://jsfiddle.net/kallsbo/XgsC6/

First initialize the map and all it’s settings:
[js]
var map;
var addressField;
var geocoder;

$(document).ready(function () {
// Define map options
var mapOptions = {
center: new google.maps.LatLng(57.698254, 12.037024),
zoom: 16,
mapTypeId: google.maps.MapTypeId.HYBRID,
panControl: true,
zoomControl: true,
mapTypeControl: true,
scaleControl: true,
streetViewControl: true,
overviewMapControl: true
};

// Define map
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);

// Define Gecoder
geocoder = new google.maps.Geocoder();

// Init searchbox
initSearchBox();
});

function initSearchBox() {
// Add searchbox
var searchControlDiv = document.createElement(‘div’);
var searchControl = new SearchControl(searchControlDiv, map);

searchControlDiv.index = 1;
map.controls[google.maps.ControlPosition.TOP_CENTER].push(searchControlDiv);
}
[/js]
As you can see we initialize the search box control and put it in a div at the top of the canvas. This is how we create the control and it’s auto complete function:
[js firstline=”38″]
function SearchControl(controlDiv, map) {
// Set CSS styles for the DIV containing the control
// Setting padding to 5 px will offset the control
// from the edge of the map.
controlDiv.style.padding = ‘5px’;

// Set CSS for the control border.
var controlUI = document.createElement(‘div’);
controlUI.style.backgroundColor = ‘white’;
controlUI.style.borderStyle = ‘solid’;
controlUI.style.borderWidth = ‘2px’;
controlUI.style.cursor = ‘pointer’;
controlUI.style.textAlign = ‘center’;
controlUI.title = ‘Sök ex: gatunamn, stad’;
controlDiv.appendChild(controlUI);

// Create the search box
var controlSearchBox = document.createElement(‘input’);
controlSearchBox.id = ‘search_address’;
controlSearchBox.size = ’80’;
controlSearchBox.type = ‘text’;
}
[/js]
So when you have gotten this far in the code you have the search input box as a VAR. Now whe can use that VAR to attache the function for the auto complete to it:
[js firstline=”61″]
// Initiat autocomplete
$(function () {
$(controlSearchBox).autocomplete({
source: function (request, response) {

if (geocoder == null) {
geocoder = new google.maps.Geocoder();
}

geocoder.geocode({
‘address’: request.term
}, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var searchLoc = results[0].geometry.location;
var lat = results[0].geometry.location.lat();
var lng = results[0].geometry.location.lng();
var latlng = new google.maps.LatLng(lat, lng);
var bounds = results[0].geometry.bounds;

geocoder.geocode({
‘latLng’: latlng
}, function (results1, status1) {
if (status1 == google.maps.GeocoderStatus.OK) {
if (results1[1]) {
response($.map(results1, function (loc) {
return {
label: loc.formatted_address,
value: loc.formatted_address,
bounds: loc.geometry.bounds
}
}));
}
}
});
}
});
},
select: function (event, ui) {
var pos = ui.item.position;
var lct = ui.item.locType;
var bounds = ui.item.bounds;

if (bounds) {
map.fitBounds(bounds);
}
}
});
});
[/js]
Then finish up creating the object and push it the the Google Maps Canvas as a custom control:
[js]
// Set CSS for the control interior.
var controlText = document.createElement(‘div’);
controlText.style.fontFamily = ‘Arial,sans-serif’;
controlText.style.fontSize = ’12px’;
controlText.style.paddingLeft = ‘4px’;
controlText.style.paddingRight = ‘4px’;
controlText.appendChild(controlSearchBox);
controlUI.appendChild(controlText);
}
[/js]

Missing People Sweden Techsupport

I’m currently involved in a project for Missing People Sweden (MPS). MPS is organizes volunteers to do big search operation for lost people. I was one of the volunteers last fall and saw first hand what a huge task it was to organize all the people and search area. So I went online the same night and wrote a blog entry on my Swedish blog. I questioned why no one could help this organisation with some technical support and build them a system to take care of all this. That’s how Missing People Sweden Techsupport was born. First we got put of by the organisation due to an other company that wanted to build it for them. A few month later they delivered a system that was unusable!

So once again I reached out to my contacts in the business and asked them to join me in my quest for this. Unfortunately many of them was busy on other projects or didn’t have the drive anymore after being put of the first time. But i managed to get the best project manager I ever worked with to join in. We got a MVC programmer and a jQuery guy on board. We had a few meetings with the, not so technical guys, at MPS. So they din’t know tech so well but they are really good at finding people. So we asked them what they needed, what would help them. A few meetings in I felt that we needed to show them something, show that we do stuff not just talk. So I made a quick demo of how we could help them do search segments on a map. Using Google Maps API and some spare time I made a really easy prof of concept.

The other system delivered to them, that they discarded, was 1000 man hours of development. This demo I made was 2 hours of work one night. It has now been used several times to do maps for them when actually looking for real lost people. My point here is to really listen to the customer and give them what they need not what you think they need or whats cool to do with tech!

MPS DEMODemo: http://mpsdemo.kallsbo.se/googlemaps.htm

 

RoundCube Webmail login case sensitive

I got an issue reported to me that a user of a RoundCube Webmail setup we have had lost all his contacts. I logged in to his account and all the contacts where gone. Checked the database and found that all the contacts where still in the database. After some digging i found that there where 2 accounts in the RoundCube database. One sad User@ourdomain.com the other sad user@ourdomain.com. When I logged on to the User account all the contacts where there! So i realized that RoundCube logon are case sensitive. He will still see his e-mail because the RoundCube doesn’t keep track of his password, it only tries to logon to the IMAP server and if logon is successful it creates it own DB-entries to keep track of contacts and other information. The IMAP server however isn’t case sensitive and User or user is the same thing for it. But there is an easy way to fix it!

RoundCube Settings

I’m running RoundCube on a IIS server so I go in to the wwwroot and on to the config folder. In the file main.inc.php I look for the line $rcmail_config[‘login_lc’] = false; and change it like below:
[php]
// If users authentication is not case sensitive this must be enabled.
// You can also use it to force conversion of logins to lower case.
// After enabling it all user records need to be updated, e.g. with query:
// UPDATE users SET username = LOWER(username);
$rcmail_config[‘login_lc’] = true;
[/php]
Then I do a IIS reset.

Database changes

If the user have all the contacts on the lowercase account your all good. Just delete the User account and it will all be good. But if the contacts where created on the User account like in my case you have to do like this. Delete the lowercase account and then run:
[sql]UPDATE users SET username = LOWER(username) WHERE user_id = {id of uppercase account};[/sql]
If you don’t delete the lowercase account first you will get an error like this:
[plain]Error Code: 1062. Duplicate entry ‘{username}’ for key ‘username'[/plain]
If the user have spread his contacts over both accounts just change the contact table like this:
[sql]UPDATE contacts SET user_id = {id of lowercase account} WHERE user_id = {id of uppercase account};[/sql]
Then delete the uppercase account and your all good!

Script: List users homedir size

I compiled a vbscript that loops through all the sub folders of a given folder and print out the size. The script takes the folder name and searches the Active Directory for a corresponding user. If found it prints the name of the user in the output.

Use:

[ps]cscript homedirsize.vbs[/ps]

Three input boxes will appear…

  1. Path where the homedir folders are located. Ex. d:home
  2. Width, in characters, of the first output column.
  3. Width, in characters, of the second output column.

Download script here: [wpdm_file id=2]
[vb]
‘****************************************************************************************

‘ Name: Homedirsize.vbs

‘ Retrieves the size of each subdirectory and matches them to an AD account.
‘ Outputs a list of directories, username and size.

‘ Written by: Kristofer Källsbo
‘ 2013-02-26 – http://www.hackviking.com

‘****************************************************************************************
Option explicit
dim path, column1, column2, objRoot, domainname, fso, partline, i, rootFolder, folder

‘ get path of homedirs
path = inputbox("Enter path of homedirs:")

‘ get column widths
column1 = Cint(inputbox("Enter width of first output column:"))
column2 = Cint(inputbox("Enter width of second output column:"))

‘ get the current domain
Set objRoot = GETOBJECT("LDAP://RootDSE")
domainname = objRoot.GET("defaultNamingContext")

‘ get the file system object
Set fso = CreateObject("Scripting.FileSystemObject")

‘ print description lines
wscript.echo "homedirsize.vbs runned on " & Date & " – " & Time
wscript.echo ""
wscript.echo LeftJustified("Foldername", column1) & LeftJustified("Username", column2) & "Size (Mb)"

for i = 0 to column1 + column2 + 8
partline = partline & "-"
next

wscript.echo partline

‘ start looping all the subfolders
Set rootFolder = fso.GetFolder(path)
For Each folder in rootFolder.SubFolders
Dim folderSize
folderSize = folder.Size

wscript.echo LeftJustified(folder.Name, column1) & LeftJustified(FindUser(folder.Name, domainname), column2) & FormatNumber(((folderSize/1024)/1024),2) & " Mb"
Next

Set fso = Nothing

FUNCTION FindUser(BYVAL UserName, BYVAL Domain)
Dim cn,cmd,rs
SET cn = CREATEOBJECT("ADODB.Connection")
SET cmd = CREATEOBJECT("ADODB.Command")
SET rs = CREATEOBJECT("ADODB.Recordset")

cn.open "Provider=ADsDSOObject;"

cmd.activeconnection=cn
cmd.commandtext="SELECT Name FROM ‘LDAP://" & Domain & _
"’ WHERE sAMAccountName = ‘" & UserName & "’"

SET rs = cmd.EXECUTE

IF err<>0 THEN
FindUser = 2
wscript.echo "Error connecting to Active Directory Database:" & err.description
ELSE
IF NOT rs.BOF AND NOT rs.EOF THEN
rs.MoveFirst
FindUser = rs.Fields("Name").Value
ELSE
FindUser = "N/A"
END IF
END IF
cn.close
END FUNCTION

Function LeftJustified(ColumnValue, ColumnWidth)
If(ColumnWidth < Len(ColumnValue) OR ColumnWidth = Len(ColumnValue)) then
LeftJustified = Left(ColumnValue, ColumnWidth – 1) & " "
else
LeftJustified = ColumnValue & Space(ColumnWidth – Len(ColumnValue))
End if
End Function
[/vb]

View Members Dynamic E-mail Group – Exchange 2010

Always nice to be able to check who a dynamic group contains. Easy to do from the powershell with these two commands:

[ps]
$DynGroup = Get-DynamicDistributionGroup "{name of dynamic distribution group}"
Get-Recipient -RecipientPreviewFilter $Dyn.RecipientFilter -OrganizationalUnit $DynGroup.RecipientContainer
[/ps]

Script: NTFS rights on user home directories

Have a normal Windows setup where the user have a home folder on the file server. All the users is connected to there \fileserverhome$%username% via GPO on logon. How ever we found that some of the folders had rights that where messed up. So i wrote a quick script that loopes through all folders and checks if there is a user account in the domain if not it will move the directory to __unconnected__ folder. For all know users it uses cacls command to set rights for the user and admins only. If you need something else you can just edit the cacls command before you run it! Script is provided as is and feel free to modify it…

Download script here: [wpdm_file id=2]

[vb]
Option Explicit
‘ON ERROR RESUME NEXT
Dim path, objRoot, domainname, fso, rootFolder, folder, objShell, intRunError
path = inputbox("Enter path of homedirs:")

‘ Get current domain
IF domainname = "" THEN
SET objRoot = GETOBJECT("LDAP://RootDSE")
domainname = objRoot.GET("defaultNamingContext")
END IF

‘ Setup FSO connection
Set fso = CreateObject("Scripting.FileSystemObject")
Set rootFolder = fso.GetFolder(path)
Set objShell = WScript.CreateObject( "WScript.Shell" )

‘ Go through all homedir folders
For Each folder in rootFolder.SubFolders
if(FindUser(folder.Name, domainname) = 1) Then
‘ Folder found reset the permissions
wscript.echo folder.Name + " – has a user connected! Reseting the permissions…"
intRunError = objShell.Run("%COMSPEC% /c Echo Y| cacls " & folder.Path & " /t /c /g Administrators:F ""Domain Admins"":F " & folder.Name & ":F", 1, True)
If intRunError <> 0 Then
wscript.echo folder.Name + " – ERROR assigning rights!"
wscript.echo intRunError
else
wscript.echo folder.Name + " – Rights asigned!"
End If
elseif(FindUser(folder.Name, domainname) = 0) then
‘ This folder isn’t connected move it
If(folder.Name <> "__unconnected__") then
wscript.echo folder.Name + " – doesn’t have a user connected! Moving to .__unconnected__"
fso.MoveFolder folder.Path, rootFolder.Path + "__unconnected__"
End If
else
wscript.echo "ERROR: Connection to AD failed!"
End If
Next

Set objRoot = Nothing
Set fso = Nothing
Set rootFolder = Nothing
Set objShell = Nothing

‘ Function to check if user exists
FUNCTION FindUser(BYVAL UserName, BYVAL Domain)
Dim cn,cmd,rs
SET cn = CREATEOBJECT("ADODB.Connection")
SET cmd = CREATEOBJECT("ADODB.Command")
SET rs = CREATEOBJECT("ADODB.Recordset")

cn.open "Provider=ADsDSOObject;"

cmd.activeconnection=cn
cmd.commandtext="SELECT ADsPath FROM ‘LDAP://" & Domain & _
"’ WHERE sAMAccountName = ‘" & UserName & "’"

SET rs = cmd.EXECUTE

IF err<>0 THEN
FindUser = 2
wscript.echo "Error connecting to Active Directory Database:" & err.description
ELSE
IF NOT rs.BOF AND NOT rs.EOF THEN
rs.MoveFirst
FindUser = 1
ELSE
FindUser = 0
END IF
END IF
cn.close
END FUNCTION
[/vb]

Viewing Axis webcam from iPhone

I just installed an axis webcam at home to keep tabs on my home when I’m not there. I tried a few apps for my iPhone to use the cam as easy as possible. I found four free apps for Axis cameras but only one that actually was usable.

Netcamviewer – Don’t support SSL.

CamControl – Works great! Or at least the only one that supports SSL.

CamViewer – Looks really unprofessional, don’t support SSL.

CamSee  – Don’t support SSL.

Facebook login open to enumeration

The error message above is in Swedish, the short version: “The e-mail address you entered isn’t connected to any account in our system.” So instead of telling me that my username / password combo was unsuccessful they actually help me with half the problem. If they only would have told me that the username and password combo was bad I wouldn’t know if I had the correct e-mail address for the account i’m interested in. So I will just try the different e-mail addresses I know of my intended target with some bullshit password until I get “wrong password” error and then I know what e-mail they use. Really not good Facebook!

SQL error after upgrading from express

A few days ago I helped a client update there SQL 2008 Express installation to a real SQL 2008 R2 installation. They have been hitting the wall for the 4Gb database size limit for some time so it was really time. I installed the new instance on the server and all went well. I just don’t understand why SQL 2008 Express uses the default instance name MSSQLSERVER. Last time I had anything to do with the express version off SQL I think I remember the instance was named .SQLEXPRESS or something similar. This isn’t really a problem except that the default instance can’t be accessed unless you name it. Some programs doesn’t solve that issue as well as others and the default instance name of MSSQLSERVER I think should be reserved for the real installation.

How ever the move of the databases was really easy as well. Just took them offline, deattached them from the express installation and reattached them to the new SQL 2008 server install. Then when it was all done I uninstalled the express installation. That was when the problem started. I couldn’t use the SQL Server 2008 Configuration Manager anymore. It just gave my this error:

Cannot Connect to WMI provider. You do not have permission or the server is unreachable. Note that you can only manage SQL Server 2005 and later servers with SQL Server Configuration Manager. Invalid namespace [0x8004100e]
[plain]Cannot Connect to WMI provider. You do not have permission or the server is unreachable. Note that you can only manage SQL Server 2005 and later servers with SQL Server Configuration Manager. Invalid namespace [0x8004100e][/plain]
After a little digging around I figured out that the WMI namespace had been uninstalled by the express version uninstall. From Microsoft I got the information that the 32-bit express installation shared files should still be on disk and that I could reuse them to fix the issue. According to Microsoft I should be able to do this:
[ps]mofcomp "%programfiles(x86)%MicrosoftMicrosoft SQL Server100Sharedsqlmgmproviderxpsp2up.mof"[/ps]
How ever the installation wasn’t in that folder and I realized that the information was wrong. Part of the installation was actually there but at an other path. So I ended up with this:
[ps]mofcomp "%programfiles(x86)%Microsoft SQL Server100Sharedsqlmgmproviderxpsp2up.mof"[/ps]
That solved the problem and I was able to run the SQL Server Configuration Manager again.

Watchguard SSLVPN unavalible

One organization I work for have Watchguard firewalls and are using SSLVPN. Yesterday it just stopped working. You couldn’t connect with the client and if you tried to access the {firewall address}/sslvpn.html you got “Connection refused”. First I tried to reboot the firewall and ended up with the same result. Checked the debug log and found these entries:
[ps]2011-11-17 20:28:36 sslvpn sslvpn_userlist, entry(virtual_ip=8dea8c0) not found. Debug
2011-11-17 20:28:36 sslvpn sslvpn_userlist, entry(virtual_ip=adea8c0) not found. Debug
2011-11-17 20:28:36 sslvpn sslvpn_userlist, entry(virtual_ip=9dea8c0) not found. Debug
2011-11-17 20:28:36 sslvpn sslvpn_userlist, entry(virtual_ip=4dea8c0) not found. Debug
2011-11-17 20:28:36 sslvpn sslvpn_userlist, entry(virtual_ip=7dea8c0) not found. Debug
2011-11-17 20:28:36 sslvpn sslvpn_userlist, entry(virtual_ip=2dea8c0) not found. Debug[/ps]
Googled it, of course, and didn’t really find anything useful. So i started checking all of the config, the access to the AD and stuff like that. Thought that if the firewall didn’t get access to the AD it might just close all AD dependent connections but all looked OK there two.

Finally I found out how to solve it, or really get ride of the problem. It’s hardly a sexy solution but here’s what I did:

  1. I saved my config to an XML file.
  2. I disabled the SSLVPN and saved that config to the firewall.
  3. Opened the saved XML config with SSLVPN enabled and uploaded it to the firewall.

Then it all worked again!