Saturday, February 4, 2017

BlackBerry 10 Platform is Useless

This is more of a list of things that doesn't work with the BB10 platform and how I am so done with it. Everyone I know who has a BlackBerry stopped using it, and that too they aren't many. And now, I am abandoning it as well. The OS, QNX Neutrino RTOS which is a microkernel is all cool and great. It's used in many embedded systems from ECUs, drones, medical devices to nuclear power plants. But alas, no apps :D. The keyboard and screen is also awesome. It's great for emails and writing notes, but that's all about it. App developers simply don't write apps for BB10. So the ones which I wanted to use are not present. Here is my list, and I'm comparing it with Android.
1. I use Uber most of the time, but there is no app for it. I requested Uber mobile web access, which the support guy told they cannot give it to me! But I have access somehow. Requesting ride works, but cannot pay through the web or side loaded app even after installing the patched Google Play and supporting services by Cobolt. So I have to always pay using my Android phone.
2. There is no official Slack app. S10 app is very minimal. It does not show snippets, emoticons, reactions. It's all text only. Feels like IRC to me. So I side loaded Slack apk, which works in normal cases, but then login through SSO does not work which is important to me as BB10 browser is not able to invoke Slack after successful login. Plus I don't get any notification from S10.
3. There is no Wi-Fi tethering. BB10 can connect to Wi-Fi hotspot but it cannot tether the Wi-Fi via USB with my computer. I have a special personal computer ;). It can tether only mobile data. Android does this well.
4. No push notifications get received for side loaded Android apps. I like Pinterest, but I don't get any push notifications and has to resort to email notifications.
5. Some websites like zomato and others doesn't even load in the BB10 browser, and most mobile sites are feature restricted as they have a dedicated app which are not on BlackBerry World.
6. The official LinkedIn app stopped working and doesn't load the feeds, which makes the app useless. It gives notifications and contact sync only.
7. Everyone knows that Facebook stopped supporting BB10, so does Whatsapp (soon to be). I don't use FB app on any phones as it eats up the battery like crazy and I don't have Whatsapp, so not much of a problem.
8. No 2FA authenticator app! How is all this security conscious platform not even having a working 2FA app. BlackBerry Enterprise has one to use with BES only. Too bad. I tried syncing the side loaded Yandex.Key app, but it did not sync.
9. Then there is BBM where we get the sense of security but the messages are scrambled with a global key and are not encrypted. No end-to-end encryption like in Signal. Only enterprise version offers this.
10. Most banking and mobile payment apps are not present and side loading some of them doesn't work as they keeps saying that Google Play Service is required. So the patched one did not work.
11. SoundCloud's native app crashes on a minute by minute basis. Side loaded app sort of works if play services are present but you cannot add music to playlist as it doesn't get synced with the server. Only like gets synced. The app closes if it is not in the foreground when a song ends and it does not play the next one.
12. There is a podcast app Nobex, which works great, but does not have most of the cool podcast channels. So I have to export my Podcast Republic app's OPML, find the feed URL and submit it, wait for some time for the search to pick up and add it in the app. Too much work to listen to a podcast. :)
13. There is a text editor called Editor by HugSoft, but it does not save the session. So I have to open files every time I reopens the app. Another interesting thing is that the save works very differently. Open the app, write something, use save to file. Write some more, and this time using save button does not save to the already saved file. It saves it to it's cache. Save works only if we open an existing file for editing. For new files, we need to always choose save to file, navigate etc. Not so very user friendly. Quoda works great, but it's not a native one.
14. No official PGP support for personal accounts! How dumb is this?
15. And there is no VoLTE support at the hardware level for my device, just LTE only. So I cannot make phone calls, only use data and my carrier's app which can do the calls on LTE only phone doesn't support BlackBerry. So the side loaded app doesn't detect my SIM.
16. There are some work apps, but they are available for Android and iOS only. Also, I cannot install via Google Play as the BB10 Android runtime version is lower.
17. No fast charging. True that the battery lasts longer, but it needs to be charged longer.
18. You cannot use both the email alias and the main email id. You can add either the main email or its alias. K-9 allows send emails from alias as well. Not email integration not so great after all.
Such a stupid platform, it never really caught up. Back to Android. And KNOX is cool.

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.