Wednesday, January 18, 2017

PGP on BlackBerry 10

In BlackBerry 10, there is an option for importing PGP keys under Security & Privacy. But to import the secret keys exported by GnuPG, you need to append the public key in the exported private key armored file. Then PGP will import fine. As per the documentation, you will be able to encrypt, decrypt from hub if you have active sync or Lotus Notes. So for personal keys with IMAP account, a great alternative is to sideload OpenKeychain android app. Import your exported .asc private key. To decrpyt a received email, copy the content, tap share and choose decrypt. Similarly, you can encrypt and share. Unfortunately there is no direct hub integration. Quick UI tip for Passport, swipe down from top and tap Size. Choose Zoomed out Full Screen option (middle one) for better experience. Most android apps looks great with this option.

Tuesday, January 17, 2017

Updating Gmail Password on BlackBerry Passport

To my surprise, I am not able to update the gmail account password on my BlackBerry Passport. Figured that if you choose the default setup where the hub does all the configuration, there won't be any options to edit the server settings or passwords later on. So if you intend to change passwords later on, then you should choose the advanced option and choose IMAP account. Key in the details manually, and you will be able to update the password if required. And for the current setup, you will have to delete the account from the device and add it again using the above method.

Saturday, January 7, 2017

EBNF Grammer for Parsing Chrome Bookmarks

The bookmarks html exported by Chrome is not a valid html. It has different rules with a different DTD. Here is an ANTLR 4 grammar for parsing the bookmarks with support for unicode characters in bookmark names.
grammar Bookmarks;
 
document : prolog? misc* meta* misc* dl misc*;

prolog : DTD;

misc 
    : COMMENT 
    | S
    ;

meta 
    : '<' TEXT '>' TEXT '</' TEXT '>'
    | '<' TEXT attribute* '>'
    ;

dl : '<' TEXT '><' TEXT '>' misc* dt* misc* '</' TEXT '><' TEXT '>';

dt 
    : '<' TEXT '><' tag attribute* '>' content '</' tag '>' 
    | '<' TEXT '><' tag attribute* '></' tag '>'
    | dl
    ;

attribute 
    : attributeName '=' attributeValue 
    | S
    ;

tag 
    : H3 
    | TEXT
    ;

attributeName : TEXT;

attributeValue : VAL;

content : TEXT+;

DTD : '<!'.*?'>';

COMMENT : '<!--' .*? '-->' S;

H3 : 'H3';

VAL : '"'.*?'"';

TEXT : [A-Za-z0-9:\/\.@\-_;\s*]+ | NameChar+;

fragment
NameChar
    : NameStartChar
    | '0'..'9'
    | '_'
    | '\u00B7'
    | '\u0300'..'\u036F'
    | '\u203F'..'\u2040'
    ;

fragment
NameStartChar
    : 'A'..'Z' | 'a'..'z'
    | '\u00C0'..'\u00D6'
    | '\u00D8'..'\u00F6'
    | '\u00F8'..'\u02FF'
    | '\u0370'..'\u037D'
    | '\u037F'..'\u1FFF'
    | '\u200C'..'\u200D'
    | '\u2070'..'\u218F'
    | '\u2C00'..'\u2FEF'
    | '\u3001'..'\uD7FF'
    | '\uF900'..'\uFDCF'
    | '\uFDF0'..'\uFFFD'
    ;


S : [ \t\r\n]+ -> skip;

The exported bookmarks sample.
<!DOCTYPE NETSCAPE-Bookmark-file-1>
<!-- This is an automatically generated file.
     It will be read and overwritten.
     DO NOT EDIT! -->
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
<TITLE>Bookmarks</TITLE>
<H1>Bookmarks</H1>
<DL><p>
    <DT><H3 ADD_DATE="1481473849" LAST_MODIFIED="1481473992" PERSONAL_TOOLBAR_FOLDER="true">Bookmarks bar</H3>
    <DL><p>
        <DT><H3 ADD_DATE="1481473866" LAST_MODIFIED="1481473967">Test 1</H3>
        <DL><p>
            <DT><A HREF="https://encrypted.google.com/" ADD_DATE="1481473884" ICON="">Google</A>
            <DT><A HREF="https://yandex.ru/" ADD_DATE="1481473892" ICON="">Яндекс</A>
            <DT><A HREF="http://example.com/" ADD_DATE="1481473954">Example Domain</A>
        </DL><p>
        <DT><H3 ADD_DATE="1481473872" LAST_MODIFIED="1481473980">Test 2</H3>
        <DL><p>
            <DT><A HREF="https://duckduckgo.com/" ADD_DATE="1481473902" ICON="">DuckDuckGo</A>
            <DT><A HREF="https://clojure.news/" ADD_DATE="1481473936" ICON="">Clojure News</A>
            <DT><A HREF="http://example.com/" ADD_DATE="1481473955">Example Domain</A>
        </DL><p>
        <DT><A HREF="https://yandex.ru/" ADD_DATE="1481473893" ICON="">Яндекс</A>
        <DT><A HREF="http://www.echojs.com/" ADD_DATE="1481473986" ICON=""></A>
        <DT><A HREF="https://clojure.news/" ADD_DATE="1481473992" ICON=""></A>
        <DT><H3 ADD_DATE="1481474004" LAST_MODIFIED="1481477692">Test 3</H3>
        <DL><p>
            <DT><A HREF="https://encrypted.google.com/" ADD_DATE="1481474004" ICON="">Google</A>
            <DT><A HREF="https://duckduckgo.com/" ADD_DATE="1481474004" ICON="">DuckDuckGo</A>
            <DT><A HREF="https://clojure.news/" ADD_DATE="1481474004" ICON="">Clojure News</A>
            <DT><H3 ADD_DATE="1481477681" LAST_MODIFIED="1481477681">Test 4</H3>
            <DL><p>
                <DT><A HREF="https://clojure.news/" ADD_DATE="1481477681" ICON="">Clojure News</A>
                <DT><A HREF="https://news.ycombinator.com/" ADD_DATE="1481477681" ICON="">Hacker News</A>
                <DT><A HREF="http://example.com/" ADD_DATE="1481477681">Example Domain</A>
            </DL><p>
            <DT><A HREF="https://news.ycombinator.com/" ADD_DATE="1481474004" ICON="">Hacker News</A>
            <DT><A HREF="http://example.com/" ADD_DATE="1481474004">Example Domain</A>
        </DL><p>
    </DL><p>
</DL><p>
clj-antlr library can be used to get the parse tree out of the grammer. Snippet to get the parse tree below. Use compiled version of the grammar for better performance.
(def bm (antlr/parser "/home/kadaj/dev/clojure/bookmarks-parser/grammar/Bookmarks.g4"))
(pprint (bm (slurp "/home/kadaj/dev/clojure/bookmarks-parser/resources/bookmarks.html")))
Which produces the following parse tree.
(:document
 (:prolog "")
 (:misc
  "\n")
 (:meta
  "<"
  "META"
  (:attribute
   (:attributeName "HTTP-EQUIV")
   "="
   (:attributeValue "\"Content-Type\""))
  (:attribute
   (:attributeName "CONTENT")
   "="
   (:attributeValue "\"text/html; charset=UTF-8\""))
  ">")
 (:meta "<" "TITLE" ">" "Bookmarks" "")
 (:meta "<" "H1" ">" "Bookmarks" "")
 (:dl
  "<"
  "DL"
  "><"
  "p"
  ">"
  (:dt
   "<"
   "DT"
   "><"
   (:tag "H3")
   (:attribute
    (:attributeName "ADD_DATE")
    "="
    (:attributeValue "\"1481473849\""))
   (:attribute
    (:attributeName "LAST_MODIFIED")
    "="
    (:attributeValue "\"1481473992\""))
   (:attribute
    (:attributeName "PERSONAL_TOOLBAR_FOLDER")
    "="
    (:attributeValue "\"true\""))
   ">"
   (:content "Bookmarks" "bar")
   "")
  (:dt
   (:dl
    "<"
    "DL"
    "><"
    "p"
    ">"
    (:dt
     "<"
     "DT"
     "><"
     (:tag "H3")
     (:attribute
      (:attributeName "ADD_DATE")
      "="
      (:attributeValue "\"1481473866\""))
     (:attribute
      (:attributeName "LAST_MODIFIED")
      "="
      (:attributeValue "\"1481473967\""))
     ">"
     (:content "Test" "1")
     "")
    (:dt
     (:dl
      "<"
      "DL"
      "><"
      "p"
      ">"
      (:dt
       "<"
       "DT"
       "><"
       (:tag "A")
       (:attribute
        (:attributeName "HREF")
        "="
        (:attributeValue "\"https://encrypted.google.com/\""))
       (:attribute
        (:attributeName "ADD_DATE")
        "="
        (:attributeValue "\"1481473884\""))
       (:attribute
        (:attributeName "ICON")
        "="
        (:attributeValue "\"\""))
       ">"
       (:content "Google")
       "")
      (:dt
       "<"
       "DT"
       "><"
       (:tag "A")
       (:attribute
        (:attributeName "HREF")
        "="
        (:attributeValue "\"https://yandex.ru/\""))
       (:attribute
        (:attributeName "ADD_DATE")
        "="
        (:attributeValue "\"1481473892\""))
       (:attribute
        (:attributeName "ICON")
        "="
        (:attributeValue "\"\""))
       ">"
       (:content "Яндекс")
       "")
      (:dt
       "<"
       "DT"
       "><"
       (:tag "A")
       (:attribute
        (:attributeName "HREF")
        "="
        (:attributeValue "\"http://example.com/\""))
       (:attribute
        (:attributeName "ADD_DATE")
        "="
        (:attributeValue "\"1481473954\""))
       ">"
       (:content "Example" "Domain")
       "")
      "<"
      "p"
      ">"))
    (:dt
     "<"
     "DT"
     "><"
     (:tag "H3")
     (:attribute
      (:attributeName "ADD_DATE")
      "="
      (:attributeValue "\"1481473872\""))
     (:attribute
      (:attributeName "LAST_MODIFIED")
      "="
      (:attributeValue "\"1481473980\""))
     ">"
     (:content "Test" "2")
     "")
    (:dt
     (:dl
      "<"
      "DL"
      "><"
      "p"
      ">"
      (:dt
       "<"
       "DT"
       "><"
       (:tag "A")
       (:attribute
        (:attributeName "HREF")
        "="
        (:attributeValue "\"https://duckduckgo.com/\""))
       (:attribute
        (:attributeName "ADD_DATE")
        "="
        (:attributeValue "\"1481473902\""))
       (:attribute
        (:attributeName "ICON")
        "="
        (:attributeValue "\"\""))
       ">"
       (:content "DuckDuckGo")
       "")
      (:dt
       "<"
       "DT"
       "><"
       (:tag "A")
       (:attribute
        (:attributeName "HREF")
        "="
        (:attributeValue "\"https://clojure.news/\""))
       (:attribute
        (:attributeName "ADD_DATE")
        "="
        (:attributeValue "\"1481473936\""))
       (:attribute
        (:attributeName "ICON")
        "="
        (:attributeValue "\"\""))
       ">"
       (:content "Clojure" "News")
       "")
      (:dt
       "<"
       "DT"
       "><"
       (:tag "A")
       (:attribute
        (:attributeName "HREF")
        "="
        (:attributeValue "\"http://example.com/\""))
       (:attribute
        (:attributeName "ADD_DATE")
        "="
        (:attributeValue "\"1481473955\""))
       ">"
       (:content "Example" "Domain")
       "")
      "<"
      "p"
      ">"))
    (:dt
     "<"
     "DT"
     "><"
     (:tag "A")
     (:attribute
      (:attributeName "HREF")
      "="
      (:attributeValue "\"https://yandex.ru/\""))
     (:attribute
      (:attributeName "ADD_DATE")
      "="
      (:attributeValue "\"1481473893\""))
     (:attribute (:attributeName "ICON") "=" (:attributeValue "\"\""))
     ">"
     (:content "Яндекс")
     "")
    (:dt
     "<"
     "DT"
     "><"
     (:tag "A")
     (:attribute
      (:attributeName "HREF")
      "="
      (:attributeValue "\"http://www.echojs.com/\""))
     (:attribute
      (:attributeName "ADD_DATE")
      "="
      (:attributeValue "\"1481473986\""))
     (:attribute (:attributeName "ICON") "=" (:attributeValue "\"\""))
     ">")
    (:dt
     "<"
     "DT"
     "><"
     (:tag "A")
     (:attribute
      (:attributeName "HREF")
      "="
      (:attributeValue "\"https://clojure.news/\""))
     (:attribute
      (:attributeName "ADD_DATE")
      "="
      (:attributeValue "\"1481473992\""))
     (:attribute (:attributeName "ICON") "=" (:attributeValue "\"\""))
     ">")
    (:dt
     "<"
     "DT"
     "><"
     (:tag "H3")
     (:attribute
      (:attributeName "ADD_DATE")
      "="
      (:attributeValue "\"1481474004\""))
     (:attribute
      (:attributeName "LAST_MODIFIED")
      "="
      (:attributeValue "\"1481477692\""))
     ">"
     (:content "Test" "3")
     "")
    (:dt
     (:dl
      "<"
      "DL"
      "><"
      "p"
      ">"
      (:dt
       "<"
       "DT"
       "><"
       (:tag "A")
       (:attribute
        (:attributeName "HREF")
        "="
        (:attributeValue "\"https://encrypted.google.com/\""))
       (:attribute
        (:attributeName "ADD_DATE")
        "="
        (:attributeValue "\"1481474004\""))
       (:attribute
        (:attributeName "ICON")
        "="
        (:attributeValue "\"\""))
       ">"
       (:content "Google")
       "")
      (:dt
       "<"
       "DT"
       "><"
       (:tag "A")
       (:attribute
        (:attributeName "HREF")
        "="
        (:attributeValue "\"https://duckduckgo.com/\""))
       (:attribute
        (:attributeName "ADD_DATE")
        "="
        (:attributeValue "\"1481474004\""))
       (:attribute
        (:attributeName "ICON")
        "="
        (:attributeValue "\"\""))
       ">"
       (:content "DuckDuckGo")
       "")
      (:dt
       "<"
       "DT"
       "><"
       (:tag "A")
       (:attribute
        (:attributeName "HREF")
        "="
        (:attributeValue "\"https://clojure.news/\""))
       (:attribute
        (:attributeName "ADD_DATE")
        "="
        (:attributeValue "\"1481474004\""))
       (:attribute
        (:attributeName "ICON")
        "="
        (:attributeValue "\"\""))
       ">"
       (:content "Clojure" "News")
       "")
      (:dt
       "<"
       "DT"
       "><"
       (:tag "H3")
       (:attribute
        (:attributeName "ADD_DATE")
        "="
        (:attributeValue "\"1481477681\""))
       (:attribute
        (:attributeName "LAST_MODIFIED")
        "="
        (:attributeValue "\"1481477681\""))
       ">"
       (:content "Test" "4")
       "")
      (:dt
       (:dl
        "<"
        "DL"
        "><"
        "p"
        ">"
        (:dt
         "<"
         "DT"
         "><"
         (:tag "A")
         (:attribute
          (:attributeName "HREF")
          "="
          (:attributeValue "\"https://clojure.news/\""))
         (:attribute
          (:attributeName "ADD_DATE")
          "="
          (:attributeValue "\"1481477681\""))
         (:attribute
          (:attributeName "ICON")
          "="
          (:attributeValue "\"\""))
         ">"
         (:content "Clojure" "News")
         "")
        (:dt
         "<"
         "DT"
         "><"
         (:tag "A")
         (:attribute
          (:attributeName "HREF")
          "="
          (:attributeValue "\"https://news.ycombinator.com/\""))
         (:attribute
          (:attributeName "ADD_DATE")
          "="
          (:attributeValue "\"1481477681\""))
         (:attribute
          (:attributeName "ICON")
          "="
          (:attributeValue "\"\""))
         ">"
         (:content "Hacker" "News")
         "")
        (:dt
         "<"
         "DT"
         "><"
         (:tag "A")
         (:attribute
          (:attributeName "HREF")
          "="
          (:attributeValue "\"http://example.com/\""))
         (:attribute
          (:attributeName "ADD_DATE")
          "="
          (:attributeValue "\"1481477681\""))
         ">"
         (:content "Example" "Domain")
         "")
        "<"
        "p"
        ">"))
      (:dt
       "<"
       "DT"
       "><"
       (:tag "A")
       (:attribute
        (:attributeName "HREF")
        "="
        (:attributeValue "\"https://news.ycombinator.com/\""))
       (:attribute
        (:attributeName "ADD_DATE")
        "="
        (:attributeValue "\"1481474004\""))
       (:attribute
        (:attributeName "ICON")
        "="
        (:attributeValue "\"\""))
       ">"
       (:content "Hacker" "News")
       "")
      (:dt
       "<"
       "DT"
       "><"
       (:tag "A")
       (:attribute
        (:attributeName "HREF")
        "="
        (:attributeValue "\"http://example.com/\""))
       (:attribute
        (:attributeName "ADD_DATE")
        "="
        (:attributeValue "\"1481474004\""))
       ">"
       (:content "Example" "Domain")
       "")
      "<"
      "p"
      ">"))
    "<"
    "p"
    ">"))
  "<"
  "p"
  ">"))

Thursday, December 15, 2016

Subclassing Custom Java Class in Clojure

Here are the ways to subclass a your custom Java class from Clojure. I have been fiddling to get this to work with lein for some time now and SO to the rescue of course. In your lein project say you have java source at src/java. You want to extend a class from clojure, call super class method etc. There are two ways to extend, proxy and gen-class.
It's important to note that you need to have a package structure for the java classes. Naked classes don't work because it's getting qualified to java.lang namespace when you try to run giving a ClassNotFoundException.
// src/java/com/example/BaseClass.java
package com.example;

public class BaseClass {
    public String greet() {
        return "Hello from BaseClass";
    }
}
You need to specify the java source location using :java-source-paths in project.clj. If you are using :gen-class to extend, then you need to aot compile your clojure file. When running project with :java-source-paths added under Windows, I am getting the following error even if JAVA_HOME is set to JDK location and bin is in path.
Java compiler not found; Be sure to use java from a JDK
rather than a JRE by modifying PATH or setting JAVA_CMD.
Adding JAVA_CMD env variable to point to java_home-path\bin\java works.
; project.clj
(defproject subclass "0.1.0-SNAPSHOT"
    :dependencies [[org.clojure/clojure "1.8.0"]]
    :java-source-paths ["src/java"]
    :main subclass.core
    :target-path "target/%s"
    :aot [subclass.core]
    :profiles {:uberjar {:aot :all}})
Extending using :gen-class use :extends keyword. If you want to call a super class method, use :expose-methods to specify an alias under which that method will be available locally. Here the greet from BaseClass is locally referred as pgreet
; src/subclass/core.clj
(ns subclass.core
    (:gen-class
     :extends com.example.BaseClass
     :exposes-methods {greet pgreet}))

; greet method override. gen-class prefixes generated classes with '-' by default.
(defn -greet [this]
    ; this arg is the object of this class, i.e., subclass.core.
    (.pgreet this) ; calls super class' greet()
    (println "hi from clj"))

(defn -main [& args]
    (.greet (subclass.core.)))
Running the above gives
$ lein run
subclass.core=> (-main)
Hello from BaseClass
hi from clj
nil
Extending using proxy.
; src/subclass/core.clj
(ns subclass.core
    (:import com.example.BaseClass))

(defn my-greet [] 
    (proxy [BaseClass] []  ;the class to extend
        ; override greet()
        (greet []
            (proxy-super greet) ;call super class method
            (println "hi from my-greet"))))

(defn -main [& args]
    ; calling my-greet returns a proxy object. invoke greet method on it.
    (.greet (my-greet)))
Running the proxy version gives
$ lein repl
subclass.core=> (-main)
Hello from BaseClass
hi from my-greet
nil
Using proxy or gen-class for extending depends on your use case.

Thursday, December 8, 2016

Slideshare Upload Failing With 307 Internal Redirect

If you try to upload files to slideshare from Chome and the upload fails with a status code of 307 Internal Redirect (in Network tab of dev console) with Non-Authoritative-Reason: Delegate as response header and you get XMLHttpRequest cannot load http://uploads-slideshare.s3.amazons.com/. Response for preflight is invalid (redirect) error, means that your browser is redirecting an http request to https and it is failing. In my case it was because of the HTTPS Everywhere chrome extension. You want to uncheck Amazon Web Services from the extension for the upload to work. Also, if you have PrivacyBadger, then adjust it for the site if login fails.


Use .gitattributes to Override Language Detection in Github

Github uses linguist library to detect the languages used in a repository. It ignores library codes from counting towards the language percentage. So if you have files that are not part of the main code which are not in the vender specific path and you wanted to ignore them from the statistics, you can tell github to not count them by specifying it in .gitattributes file. Say I have a public folder which contains documentation or support files which I wanted to ignore, then the .gitattributes file will look like below.
public/js/libs/* linguist-vendored
public/* linguist-documentation
You can add linguist-vendored or linguist-documentation to ignore the files from counting. You can see the difference in the language statistics bar of your repository.

PrivacyBadger - Commenting on Blogger using Google Account

If you are using PrivacyBadger, your comments at blogger using Google account won't work. Also you cannot preview the comments as this extension blocks cookies. You need to enable cookie from www.blogger.com in PrivacyBadger for this to work.