Tuesday, December 16, 2014

List of mobile user-agents

Sometimes it is useful to have a list of different kinds of mobile user agents. It can be used in many ways for development purposes in wide areas.

For this reason I created quite a big list of user-agents. Each line in the list is a JSON object containing data of:
  • User agent
  • Device Brand
  • Device Model
Here are some examples from the file:

{"device":"SC-04E","brand":"DoCoMo","user_agent":"Mozilla\/5.0 (Linux; Android 4.4.2; en-us; SC-04E Build\/KOT49H) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/1.5 Chrome\/28.0.1500.94 Mobile Safari\/537.36"}
{"device":"U3","brand":"Housin","user_agent":"Mozilla\/5.0 (Linux; U; Android 4.0.2; en-in; HONPhone V7 Build\/ITL41D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30"}
{"device":"XT926","brand":"Motorola","user_agent":"Mozilla\/5.0 (Linux; U; Android 4.0.1; th-th; DROID RAZR HD Build\/IMM76D) AppleWebKit\/534.30 (KHTML, like Gecko) Version\/4.0 Mobile Safari\/534.30"}
The list is compressed as RAR. It contains almost 1.5M different user agents.
I hope you will find this list useful.

Sunday, December 14, 2014

Nikon V1 Viewfinder/Display problem

I own a Nikon V1 camera. It is considered to be quite old and outdated these days, but still I find it useful from time to time.

Few days ago I had this strange problem: when I turned on the camera, things were shown properly on the display, but when I put my eye on the viewfinder and then removed it again the image stayed on the viewfinder and refused to go back to the display.

Took me quite some time to understand that the sensor on the left side of the viewfinder was simply covered with too much dust. It tricked the sensor to think that my eye is all the time on the viewfinder and therefore showed the image on the viewfinder instead of the display.

I though it might be useful to share this information in case one of you out there is still using Nikon V1 and experience the same problem. Of course that cleaning the sensor solved the problem.

Here is where the sensor is located:




Thursday, December 11, 2014

List of cities as SQL inserts

There are times you might need a list of cities as SQL inserts.
For this reason I extracted quite a large list of cities from MaxMind database.
The list is composed of 2 columns:
  • Country code as ISO-3166 alpha2 (2 letters for each country)
  • City name
There is also a script that creates the cities table (SQL Server syntax):

 CREATE TABLE [dbo].[city](  
      [country_code] [char](2) NOT NULL,  
      [city] [varchar](100) NOT NULL,  
  CONSTRAINT [PK_city] PRIMARY KEY CLUSTERED   
 (  
      [country_code] ASC,  
      [city] ASC  
 )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]  
 ) ON [PRIMARY]  

DOWNLOAD: You can download the list of cities HERE

Wednesday, December 3, 2014

Show Resultset as HTML table

There are times you simply want to show some result set as a table on the screen.
You do not need anything fancy, just show some tabular data on the screen.

In order to solve this issue I wrote a very small and lightweight Java class named: ResultSetToHtmlTable. Even through this class is doing a quite simple task it still have some nice qualities:

  • It is very fast. It doesn't construct any string. It simply writes the table directly to a writer.
  • It doesn't use any external libraries. All plain and simple Java.
  • It is only a single class.
  • It knows to format the data in each column. It supports the following formats:
    • Integer - Show 1000 as 1,000
    • Float - Show 0.5145235 as 0.51
    • Currency - Show 5.2 as $5.2
    • Percentage - Show 0.5 as 50%
    • Date - Show 12/5/2014 as 5 Dec 2014
    • Date and time - Show 12/5/2014 12:00:00 as 5 Dec 2014 12:00:00
    • Time - Show only the time part of a date. For example: 13:22:15
  • It allows to align the data to the left or right and add titles to columns.
  • If no strict column information is supplied is knows to auto detect:
    • Column types.
    • Column titles - titles are named as column names returned in query.
    • Column alignment - Numbers are aligned to the right.
The code of this class is quite simple and straightforward. Here is how it looks like:
package com.todacell.util.sql;

import java.io.IOException;
import java.io.Writer;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.text.DateFormat;
import java.text.Format;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Bashan
 *         Date: 18/11/2014 15:07
 */
public class ResultSetToHtmlTable {

  public void writeTable(ResultSet rs, Writer writer, Column[] columns) throws IOException, SQLException {
    writer.write("<table>");
    // Write titles
    writer.write("\t<tr>\n");
    for (Column column : columns) {
      writer.write("\t\t<th>" + column.title + "</th>");
    }
    writer.write("\t</tr>\n");

    // Write data
    int cols = columns.length;
    while (rs.next()) {
      writer.write("\t<tr>\n");
      for (int i = 0; i < cols; i++) {
        ColumnType columnType = columns[i].columnType;
        String columnAlign = columnAlignToColumnCss.get(columns[i].columnAlign);
        writer.write("\t\t<td" + columnAlign + ">" + format(columnType, rs.getObject(i + 1)) + "</td>");
      }
      writer.write("\t</tr>");
    }

    writer.write("</table>");
  }

  private static Map<Integer, ColumnType> sqlTypeToColumnType = new HashMap<Integer, ColumnType>();
  private static Map<ColumnType, ColumnAlign> columnTypeTpColumnAlign = new HashMap<ColumnType, ColumnAlign>();
  private static Map<ColumnAlign, String> columnAlignToColumnCss = new HashMap<ColumnAlign, String>();

  static {
    // Map SQL types to column types

    // integer
    sqlTypeToColumnType.put(Types.INTEGER, ColumnType.INTEGER);
    sqlTypeToColumnType.put(Types.BIGINT, ColumnType.INTEGER);
    sqlTypeToColumnType.put(Types.SMALLINT, ColumnType.INTEGER);
    sqlTypeToColumnType.put(Types.TINYINT, ColumnType.INTEGER);
    sqlTypeToColumnType.put(Types.NUMERIC, ColumnType.INTEGER);

    // float
    sqlTypeToColumnType.put(Types.FLOAT, ColumnType.INTEGER);
    sqlTypeToColumnType.put(Types.DOUBLE, ColumnType.INTEGER);
    sqlTypeToColumnType.put(Types.DECIMAL, ColumnType.INTEGER);

    // date
    sqlTypeToColumnType.put(Types.TIME, ColumnType.DATE);
    sqlTypeToColumnType.put(Types.TIMESTAMP, ColumnType.DATE);

    // Map column type to column alignment
    columnTypeTpColumnAlign.put(ColumnType.INTEGER, ColumnAlign.RIGHT);
    columnTypeTpColumnAlign.put(ColumnType.FLOAT, ColumnAlign.RIGHT);
    columnTypeTpColumnAlign.put(ColumnType.CURRENCY, ColumnAlign.RIGHT);
    columnTypeTpColumnAlign.put(ColumnType.DATE, ColumnAlign.LEFT);
    columnTypeTpColumnAlign.put(ColumnType.STRING, ColumnAlign.LEFT);

    // Map column alignment to css style
    columnAlignToColumnCss.put(ColumnAlign.LEFT, "");
    columnAlignToColumnCss.put(ColumnAlign.RIGHT, " style=\"text-align:right\"");
    columnAlignToColumnCss.put(ColumnAlign.CENTER, " style=\"text-align:center\"");
  }

  public void writeTable(ResultSet rs, Writer writer) throws IOException, SQLException {
    ResultSetMetaData meta = rs.getMetaData();
    int cols = meta.getColumnCount();

    Column[] columns = new Column[meta.getColumnCount()];
    for (int i = 0; i < cols; i++) {
      ColumnType columnType = sqlTypeToColumnType.get(meta.getColumnType(i + 1));
      ColumnAlign columnAlign = columnTypeTpColumnAlign.get(columnType);
      columns[i] = new Column(
          columnType != null ? columnType : ColumnType.STRING,
          meta.getColumnName(i + 1),
          columnAlign != null ? columnAlign : ColumnAlign.LEFT);
    }

    writeTable(rs, writer, columns);
  }

  public enum ColumnType {
    STRING, INTEGER, FLOAT, DATE, DATE_TIME, TIME, CURRENCY, PERCENTAGE
  }

  public enum ColumnAlign {
    LEFT, RIGHT, CENTER
  }

  private static NumberFormat integerFormat = NumberFormat.getInstance();
  private static NumberFormat floatFormat = NumberFormat.getInstance();
  private static final NumberFormat percentFormat = NumberFormat.getPercentInstance();
  private static final NumberFormat currencyFormat = NumberFormat.getCurrencyInstance();
  private static final DateFormat dateFormat = new SimpleDateFormat("dd MMM yyyy");
  private static final DateFormat dateTimeFormat = new SimpleDateFormat("dd MMM yyyy hh:mm:ss");
  private static final DateFormat timeFormat = new SimpleDateFormat("hh:mm:ss");

  static {
    floatFormat.setMaximumFractionDigits(2);
    integerFormat.setMaximumFractionDigits(0);
  }

  public String format(ColumnType columnType, Object value) {
    String result;
    if (value != null) {
      if (columnType == ColumnType.STRING) {
        result = value.toString();
      } else {
        Format format;
        if (columnType == ColumnType.FLOAT) {
          format = floatFormat;
        } else if (columnType == ColumnType.CURRENCY) {
          format = currencyFormat;
        } else if (columnType == ColumnType.PERCENTAGE) {
          format = percentFormat;
        } else if (columnType == ColumnType.DATE) {
          format = dateFormat;
        } else if (columnType == ColumnType.DATE_TIME) {
          format = dateTimeFormat;
        } else if (columnType == ColumnType.TIME) {
          format = timeFormat;
        }else {
          format = integerFormat;
        }

        result = format.format(value);
      }
    } else {
      result = "N/A";
    }

    return result;
  }

  public static class Column {
    ColumnType columnType;
    String title;
    ColumnAlign columnAlign;

    public Column(ColumnType columnType, String title, ColumnAlign columnAlign) {
      this.columnType = columnType;
      this.title = title;
      this.columnAlign = columnAlign;
    }
  }
}

And here is a simple example of how to use this code in a JSP file:
 <%@ page import="com.todacell.management.SessionSingleton" %>  
 <%@ page import="com.todacell.util.sql.ResultSetToHtmlTable" %>  
 <%@ page import="org.hibernate.Session" %>  
 <%@ page import="java.sql.Connection" %>  
 <%@ page import="java.sql.ResultSet" %>  
 <%@ page import="java.sql.Statement" %>  
 <%@ page contentType="text/html;charset=UTF-8" language="java" %>  
 <html>  
 <head>  
   <title>Daily Deposits</title>  
   <style type="text/css">  
     table {  
       border-collapse: collapse;  
     }  
     table, th, td {  
       border: 1px solid black;  
     }  
     td, th {  
       padding: 5px;  
     }  
   </style>  
 </head>  
 <body>  
 <jsp:include page="k2_menu.jsp" />  
 <h1>Daily Deposits</h1>  
 <%  
   Session hSession = SessionSingleton.instance();  
   Connection conn = hSession.connection();  
   try {  
     Statement stmt = conn.createStatement();  
     ResultSet rs = stmt.executeQuery("select * from k2_deposits(60)");  
     ResultSetToHtmlTable resultSetToHtmlTable = new com.todacell.util.sql.ResultSetToHtmlTable();  
     resultSetToHtmlTable.writeTable(rs, out,  
         new com.todacell.util.sql.ResultSetToHtmlTable.Column[] {  
             new ResultSetToHtmlTable.Column(ResultSetToHtmlTable.ColumnType.DATE, "Date", ResultSetToHtmlTable.ColumnAlign.LEFT),  
             new ResultSetToHtmlTable.Column(ResultSetToHtmlTable.ColumnType.CURRENCY, "Deposits", ResultSetToHtmlTable.ColumnAlign.RIGHT),  
             new ResultSetToHtmlTable.Column(ResultSetToHtmlTable.ColumnType.CURRENCY, "Allocated", ResultSetToHtmlTable.ColumnAlign.RIGHT),  
             new ResultSetToHtmlTable.Column(ResultSetToHtmlTable.ColumnType.CURRENCY, "Deallocated", ResultSetToHtmlTable.ColumnAlign.RIGHT),  
             new ResultSetToHtmlTable.Column(ResultSetToHtmlTable.ColumnType.CURRENCY, "Ad Spend", ResultSetToHtmlTable.ColumnAlign.RIGHT),  
             new ResultSetToHtmlTable.Column(ResultSetToHtmlTable.ColumnType.CURRENCY, "Potential Spend", ResultSetToHtmlTable.ColumnAlign.RIGHT),  
             new ResultSetToHtmlTable.Column(ResultSetToHtmlTable.ColumnType.INTEGER, "New Users", ResultSetToHtmlTable.ColumnAlign.RIGHT)  
         });  
   } finally {  
     if (hSession != null) {  
       hSession.close();  
     }  
   }  
 %>  
 </body>  
 </html>  
And here is how it looks on the browser:
DOWNLOAD: You can download the ResultSetToHtmlTable here

Tuesday, November 25, 2014

Instagram Photo Cycler JavaSscript widget


A while ago I built for the company I work for a nice Dashboard presenting business and operational data on a TV.

I wanted to add to the Dashboard something cool that will drive people to be more creative.

I had an idea of showing on the dashboard Instagram photos of the company by posting photos to a predefined hashtag. For example: #mycompany.

There was one problem: the real-estate on a dashboard TV screen is very expensive and you can not show more then a single photo.

I remembered that I once encountered a cool JavaScript widget that simply cycles photos with nice transition effects. I thought that it will be nice to connect this widget with Instagram and put it on the dashboard.

Back then I didn't know that I can also get the assistance of Instafeed.js in order to get Instagram data easily, so I had to write this part my self.

The result was pretty cool, so I decided to make a jQuery widget from it to allow others to use it as well. You can download the widget and use it for your own photos or for showing photos of some hashtag.

Here is how the widget looks like for the hashtag #love:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js" type="text/javascript"></script>
<script src="http://cdn.rawgit.com/malsup/cycle/master/jquery.cycle.lite.js" type="text/javascript"></script>
<script src="https://docs.google.com/uc?export=download&id=0B8vXkKUFKJw4anFQam9reXhyNWc" type="text/javascript"></script>

<br />
<div id="instagramCyclerCoderEyeLove" style="width:320px; height:320px;">
</div>
<script language="JavaScript">
 <!--

  $(document).ready(function() {
   $('#instagramCyclerCoderEyeLove').cycleInstagram({
    'get':   'tagged',
    'tagName':  'love',
    'accessToken': '161840.f92bbd9.e0a09d9b00f746c8b2662a4e784e55b0'
   });
  });

 </script>

And here is the result:

In order to show your own photos you can use the property "get" with the "user" value. Please note that in order to show you own photos, you can simply use for "userId" the word "self". In addition you can see how you can show more than just a photo and even control look of the widget very easily with the "template" property and simple usage of CSS:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js" type="text/javascript"></script>
<script src="http://cdn.rawgit.com/malsup/cycle/master/jquery.cycle.lite.js" type="text/javascript"></script>
<script src="https://docs.google.com/uc?export=download&id=0B8vXkKUFKJw4anFQam9reXhyNWc" type="text/javascript"></script>

 <style>
  #instagramCyclerCodeEyerUser {
   background-image: url("https://docs.google.com/uc?export=download&id=0B8vXkKUFKJw4a1JVbTNoY0N0T0U"); 
   background-size: cover; 
   width:326px; 
   height:380px;
  }

  #instagramCyclerCodeEyerUser img {
   padding-top:28px;
   padding-left:36px;
  }

  #instagramCaption {
   margin-top:25px;
   padding-left:36px;
   font-size:18px;
   font-family: ‘Lucida Sans Unicode’, ‘Lucida Grande’, sans-serif;
   width: 250px;
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
  }

 </style>

<div id="instagramCyclerCodeEyerUser"></div>
<script language="JavaScript">

  $(document).ready(function() {
   $('#instagramCyclerCodeEyerUser').cycleInstagram({
    'get':   'user',
    'userId':  'self',
    'tagName':  'todacellmon',
    'accessToken': '161840.f92bbd9.e0a09d9b00f746c8b2662a4e784e55b0',
    'template': '<div><a href="{{link}}"><img src="{{image}}" width="250" height="250" /></a><div id="instagramCaption">{{caption}}</div></div>'
   });
  });

 </script>


Here is the result:

PLEASE NOTE: In order to use Instagram API, you should create an access token. You have nothing to worry that others can see your access token as long as you create an access token only for READING. Frankly, creating the access token on Instagram, at least at the time that I did it, was not a simple task. You can find more help on how to do it on Instagram developers section or on this url

DOWNLOAD: Here you can download the widget

Thursday, November 13, 2014

Working with SHA1 on SQL Server


There are times you might need to convert some information to MD5 on your SQL Server in HEX format. As it is for now there is no out of the box function to do it on SQL Server. But you can easily accomplish this task by using the following function:
create FUNCTION [dbo].[sha1]
(
        @value varchar(4000)
)
RETURNS varchar(40)
AS
BEGIN
  return
    case when @value is not null then
      SUBSTRING(master.dbo.fn_varbintohexstr(HashBytes('SHA1', @value)), 3, 40)
    else null end
END
GO

Testing it is quite straight forward. For example:
select dbo.sha1('123') 

And here is the output:
40bd001563085fc35165329ea1ff5c5ecbdbbeef


 

Wednesday, November 12, 2014

Working with MD5 on SQL Server


There are times you might need to convert some information to MD5 on your SQL Server in HEX format. As it is for now there is no out of the box function to do it on SQL Server. But you can easily accomplish this task by using the following function:
create FUNCTION [dbo].[md5]
(
        @value varchar(4000)
)
RETURNS varchar(40)
AS
BEGIN
  return
    case when @value is not null then
      (SUBSTRING(master.dbo.fn_varbintohexstr(HashBytes('MD5', @value)), 3, 32))
    else null end
END
GO

Testing it is quite straight forward. For example:
select dbo.md5('123') 

And here is the output:
202cb962ac59075b964b07152d234b70 


 

Tuesday, April 9, 2013

PC speaker beeps with no apparent reason

I had this problem for about few months: from time to time with no warning, my PC started beeping from its speakers for no apparent reason.
Sometimes it started with several beeps, sometimes it started with a single long beep. When I restarted my computer the problem seemed to pass till the next time.
First, I suspected I had a virus. I made sure I updated my Kaspersky to the latest version and scanned for viruses with no luck.

I then went to Windows device drivers manager and stopped the speakers service - but still, the beep used to come whenever it wanted. Eventually, I came with the theory that my machine is getting too hot and therefore I get a warning beep. So I opened the case of the PC to make sure my ventilation is working properly - all seemed right.

So, I decided to download this small app named Core Temp. It can give detailed about the temperature of each core of your CPU. It uses information from the CPU itself and not sensors that measure temperature outside the CPU.

After loading the app I noticed the temperature was around 70 degrees. It seems to me a bit high, but nothing unreasonable. So I decided to wait for the next beep to come.
After few days the beep came again. I loaded the Core Temp and was amazed to see that the CPU temperature was on 95 degrees!
I quickly opened my PC case and noticed both ventilation are working properly. So I decided to give a closer look at the hit sink below the CPU ventilation. I noticed a huge amount of dust that filled the hit sink.

I started cleaning all the dust that accumulated there along the time. Then started my computer again and loaded the Core Temp. Then I noticed the temperature was around 35 degrees!
Eventually the mystery was solved: my PC was beeping like crazy, since the CPU was hitting too much and I couldn't tell there was a problem, because ventilation seemed to work properly.
So if your PC starts to beep with no apparent reason, do yourself a favor and give it attention. It might say that something is seriously wrong. Probably your CPU is over hitting and the blame might be more then a low performing ventilation: DUST.
I assume that the dust may have caused 2 major things:
  • Less effective hit dispensation.
  • Increases the drag of the ventilation and therefore cause it to rotate slower.
When my computer was not working too hard: temperature was around 70 degrees, which was not so good, but not so bad.

When my computer was working hard, CPU temperature started climbing higher and higher till  it reached around 95 degrees and the computer started beeping to warn about the hit.
The small difference of removing the excessive dust made the difference for more than 50 degrees! Worth the effort!

Monday, February 4, 2013

Change address bar back to Google on FireFox

Nowadays, when you install new software on your machine, you can never know if it comes with some other bundled packages that during installation simply change the behavior of your browser/system. During the installation process you get a small check box selected by default, usually on the bottom of the window so you do not notice that you are going to install some additional software.

Lately this thing happened to me, even tough I always pay attention to these kind of things. I even do not remember what I installed. But as a result of the installation I was not longer able to directly do search on my FireFox address bar.
Companies that usually change the address bar for you without you wanting it are:
I was able to repair this issue very easily by doing the following steps:
  1. Write on FireFox address bar: "about:config". It will take you to advanced settings of FireFox.
  2. Use the "search" text field on the top to filter: "keyword.URL".
  3. Right click on the resulted row and select: "Reset".
That's it. As simply as that.

It is also a good thing if you will try to filter the list by the strings: "ask" and "conduit" in order to reset other things they might have changed in you browser.
Please make sure that you do not do mistakes in the process.

Thursday, July 12, 2012

Use Google photos screen saver without installing Picasa



Google photo screen saver used to be part of Google Pack. Then Google decided to move it under Picasa. That means, that if you want to use Google photo screen saver you have to install Picasa.


I use Adobe Light Room to edit my photos and I love it. I love Google's photo screen saver. It shows photos much more nicely then Microsoft's built-in photos screen saver and also ads more sources to get photos (like RSS feeds from the internet).


I wanted to install Google's photo screen saver without needing to install Picasa. I managed to do it easily by installing Picasa, grabbing it's screen saver file: GPhoto.scr and then uninstalling Picasa.


If you would like to use Google photo screen saver without needing to install Picasa, you can simply download it here, then place this file under Windows folder: c:\windows (or you own windows installation folder).


When going to screen savers selection on Windows (the location of this option depends on your Windows version, but can be easily found) you should see Google's photos screen saver on the screen savers list.


Enjoy it!