Monday, November 30, 2015

Speed Up Gradle build on Ubuntu

If you find yourself frustrated with the time it takes for Android Studio / Gradle to build your fancy application, here's what can help you out:

-Make sure you have a simple file called gradle.properties located  at /home/{YOURUSERNAME}/.gradle/

-Make sure this file contains these two lines:
org.gradle.daemon=true
org.gradle.parallel=true

Maybe you'll need to restart in order for it to have full effect, but it should be worth it.


Saturday, November 28, 2015

WooCommerce API v3 VB.NET / C# library

Here is a VB.NET port of existing C# library for accessing WordPress WooCommerce API (https://gist.github.com/jakobt/b7400463e90e16928f57).
From my testing experience, the C# library worked very well for API versions v1 and v2. However, in it's original form, it was unable to generate proper OAuth signature for WooCommerce API v3.

Also, I have decided to port it to VB.NET as I'm not aware of currently available VB.NET versions of  WooCommerce API libs (at least , OAuth based ones). This version also includes a tiny modification which will enable easier debugging of possible authentication failures ( try / catch block which is able to fetch original error message from the server).

Possible sources of authentication failures:

-Make sure your WordPress uses mod_rewrite , as you can see WooCommerce's OAuth checking routine expects mod_rewrite format (for example, it expects /wc-api instead of index.php/wc-api).
More details can be found in your WC API authentication file:

includes/api/class-wc-api-authentication.php


-Make sure your storeURL is exactly the same as the site URL in WordPress settings (for example, if you query link http://127.0.0.1/wp/wc-api, and your WP site settings are set to http://localhost, you will get authentication failures.)


Imports System.Security.Cryptography
Imports System.Text
Imports System.Web
Imports System.Net
Imports System.Text.RegularExpressions
Imports System.IO


'VB.NET port  of https://gist.github.com/jakobt/b7400463e90e16928f57 by JakobT. 
'Author of the port: Gogi (http://www.softwarehorizont.com/2015/11/woocommerce-api-v3-vbnet-c-library.html)
'This port includes v3 API support and simple try catch code for easier debugging of invalid auth.requests
'To use it for API versions v1 and v2, just comment the line below USE v3 and uncomment line above (USE v1/v2) in GenerateSignature function



'C# version original header info:
'C# port of the https://github.com/kloon/WooCommerce-REST-API-Client-Library

'Including handling of woocommerce insisting on uppercase UrlEncoded entities
Public Class WoocommerceApiClient
    Private Shared Function HashHMAC(key As Byte(), message As Byte()) As Byte()
        Dim hash = New HMACSHA256(key)
        Return hash.ComputeHash(message)
    End Function

    Private Function Hash(input As String) As String
        Using sha1 As New SHA1Managed()
            Dim hash__1 = sha1.ComputeHash(Encoding.UTF8.GetBytes(input))
            Dim sb = New StringBuilder(hash__1.Length * 2)

            For Each b As Byte In hash__1
                ' can be "x2" if you want lowercase
                sb.Append(b.ToString("X2"))
            Next

            Return sb.ToString()
        End Using
    End Function

    Public Const API_ENDPOINT As String = "wc-api/v3/"
    Public Property ApiUrl() As String
        Get
            Return m_ApiUrl
        End Get
        Set(value As String)
            m_ApiUrl = Value
        End Set
    End Property
    Private m_ApiUrl As String
    Public Property ConsumerSecret() As String
        Get
            Return m_ConsumerSecret
        End Get
        Set(value As String)
            m_ConsumerSecret = Value
        End Set
    End Property
    Private m_ConsumerSecret As String
    Public Property ConsumerKey() As String
        Get
            Return m_ConsumerKey
        End Get
        Set(value As String)
            m_ConsumerKey = Value
        End Set
    End Property
    Private m_ConsumerKey As String
    Public Property IsSsl() As Boolean
        Get
            Return m_IsSsl
        End Get
        Set(value As Boolean)
            m_IsSsl = Value
        End Set
    End Property
    Private m_IsSsl As Boolean

    Public Sub New(consumerKey As String, consumerSecret As String, storeUrl As String, Optional isSsl As Boolean = False)
        If String.IsNullOrEmpty(consumerKey) OrElse String.IsNullOrEmpty(consumerSecret) OrElse String.IsNullOrEmpty(storeUrl) Then
            Throw New ArgumentException("ConsumerKey, consumerSecret and storeUrl are required")
        End If
        Me.ConsumerKey = consumerKey
        Me.ConsumerSecret = consumerSecret
        Me.ApiUrl = Convert.ToString(storeUrl.TrimEnd("/"c) + "/") & API_ENDPOINT
        Me.IsSsl = isSsl
    End Sub

    Public Function GetAllProducts() As String
        Return MakeApiCall("products", New Dictionary(Of String, String)() From { _
            {"filter[limit]", "2000"} _
        })
    End Function
    Public Function GetProducts() As String
        Return MakeApiCall("products")
    End Function

    Private Function MakeApiCall(endpoint As String, Optional parameters As Dictionary(Of String, String) = Nothing, Optional method As String = "GET") As String
        If parameters Is Nothing Then
            parameters = New Dictionary(Of String, String)()
        End If
        parameters("oauth_consumer_key") = Me.ConsumerKey
        parameters("oauth_timestamp") = DateTime.UtcNow.Subtract(New DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds.ToString()
        parameters("oauth_timestamp") = parameters("oauth_timestamp").Substring(0, parameters("oauth_timestamp").IndexOf(","))
        parameters("oauth_nonce") = Hash(parameters("oauth_timestamp"))
        parameters("oauth_signature_method") = "HMAC-SHA256"
        parameters("oauth_signature") = GenerateSignature(parameters, method, endpoint)
        Dim wc As New WebClient()
        Dim sb As New StringBuilder()
        For Each pair As KeyValuePair(Of String, String) In parameters
            sb.AppendFormat("&{0}={1}", HttpUtility.UrlEncode(pair.Key), HttpUtility.UrlEncode(pair.Value))
        Next
        Dim url = (Me.ApiUrl & endpoint) + "?" + sb.ToString().Substring(1).Replace("%5b", "%5B").Replace("%5d", "%5D")
        Dim result As String = ""



        Try
            result = wc.DownloadString(url)
        Catch wex As WebException
            Dim wexResp As HttpWebResponse
            wexResp = wex.Response

            Dim sr As New StreamReader(wexResp.GetResponseStream())

            Dim exceptionDetails As String

            'put a breakpoint here to check for exception details (response body)
            exceptionDetails = sr.ReadToEnd




        End Try


        Return result


    End Function

    Private Function GenerateSignature(parameters As Dictionary(Of String, String), method As String, endpoint As String) As String
        Dim baserequesturi = Regex.Replace(HttpUtility.UrlEncode(Me.ApiUrl & endpoint), "(%[0-9a-f][0-9a-f])", Function(c) c.Value.ToUpper())
        Dim normalized = NormalizeParameters(parameters)

        Dim signingstring = String.Format("{0}&{1}&{2}", method, baserequesturi, String.Join("%26", normalized.OrderBy(Function(x) x.Key).ToList().ConvertAll(Function(x) x.Key + "%3D" + x.Value)))

        'this is valid for v1 and v2:
        'USE v1/v2:
        'Dim signature = Convert.ToBase64String(HashHMAC(Encoding.UTF8.GetBytes(Me.ConsumerSecret + "&"), Encoding.UTF8.GetBytes(signingstring)))

        'this is valid for v3 (extra & added to consumer secret):
        'USE v3:
        Dim signature = Convert.ToBase64String(HashHMAC(Encoding.UTF8.GetBytes(Me.ConsumerSecret + "&"), Encoding.UTF8.GetBytes(signingstring)))



        Console.WriteLine(signature)
        Return signature
    End Function

    Private Function NormalizeParameters(parameters As Dictionary(Of String, String)) As Dictionary(Of String, String)
        Dim result = New Dictionary(Of String, String)()
        For Each pair As KeyValuePair(Of String, String) In parameters
            Dim key = HttpUtility.UrlEncode(HttpUtility.UrlDecode(pair.Key))
            key = Regex.Replace(key, "(%[0-9a-f][0-9a-f])", Function(c) c.Value.ToUpper()).Replace("%", "%25")
            Dim value = HttpUtility.UrlEncode(HttpUtility.UrlDecode(pair.Value))
            value = Regex.Replace(value, "(%[0-9a-f][0-9a-f])", Function(c) c.Value.ToUpper()).Replace("%", "%25")
            result.Add(key, value)
        Next
        Return result
    End Function
End Class

Monday, November 23, 2015

Java libs on Android cannot use local resources

If you are developing an Android library in Eclipse or Android Studio, and you are having problems using it in your Android application, please make sure that your library does not use local resource in its res/ folder. Those resources won't be exported to final lib(.jar), and your target application will miss them (by generating either ClassNotFound or similar Exception). EDIT: If you want to deploy resources with your library, you can use AAR format instead of JAR format.

Debugging AJAX with Chrome Developer Tools

If you're trying to monitor AJAX requests using Chrome Development tools, and nothing is showing up in your Network tab, make sure you have "Preserve log" option checked. In case of any redirection, Chrome Development Tool will clear the request list, leaving you without any clue from where does data arrived. Once you mark Preserve log as checked, clear the log and refresh the page. It should now show all actual requests to the web server(s).

Monday, November 16, 2015

Port forwarding behind NAT on VirtualBox

If you want to telnet your guest VM machine from host, you should try with:

telnet 127.0.0.1 [HOST_PORT]

The "catch" is to use 127.0.0.1 and not guest's IP (i.e. 10.0.2.15).

If everything is working properly, VirtualBox port forwarding will forward you to appropriate guest's port.

Example of setting port forwarding:



Also, it's sometimes a good idea (at least in testing phase) to leave both Host IP and Guest IP blank. That way, no IP filtering will be done on any end.

Sunday, November 15, 2015

Two (or more) Java Android controls with the same android:id property can be dangerous

If you doesn't seem to obtain the right control with findViewById() (although your code compiles perfectly), please check this article: https://mttkay.github.io/blog/2013/01/31/use-android-s-id-notation-with-care/ Basically, you should be very careful with doubling android:id values in different layouts! It's probably the best thing to have a unique android:id!

Some functions work only in some contexts - example of Java / Android findViewById()

Calling findViewById() on the Activity object will only work if the current Activity layout is set by setContentView. If you add a layout through some other means, then you need the View object of the layout and call findViewById() on it.

View v = inflater.inflate(id_number_of_layout);
View innerView = v.findViewById(id_number_of_view_inside_v);


Original thread:

http://stackoverflow.com/questions/9228777/findviewbyid-not-working-in-a-not-mainactivity-class

If you go with Unit Testing or TDD approach, and split the problem into tiny subproblems, then you are more likely to find a solution quickly. In this case, it was a matter of context in which findViewById() was called.

Saturday, November 14, 2015

Java regex - matching multiple groups in a string:

If you want to be able to extract each captured group as a separate Matcher group, then make sure you put greedines sysmbol INSIDE the bracket. For example, this will be fetched correctly as a whole expression: Pattern.compile("(\r|\n\|.)+?=(\r|\n|.)+?") Matcher.group(0) will return whole fetched text. However, Matcher.group(1) and Matcher.group(2) will return something like empty strings! In order to properly obtain group 1 and 2, you should use this: Pattern.compile("(\r|\n\|.+?)=(\r|\n|.+?)") Now you will have it all : group 0 (all), group 1 and group 2!

Java Regex match any character including newlines

Here's a short regex which is able to match any character including newlines in Java:


(\r|\n|.)+
For example, to remove all CPP comments, you can use something like this:
String str=str.replaceAll("/\\*(\r|\n|.)+\\*/", "");

Tuesday, November 10, 2015

Can interaction with emulator window and ADB window in Android Studio make deployment and debugging faster?

More interesting information here:
http://stackoverflow.com/questions/7597309/slow-uploads-to-running-android-emulator

Ubuntu 14 - Make clickable application shortcut on Ubuntu's Desktop

In order to create a clickable application icon on Ubuntu's Desktop, you should create new .desktop file with the following content:

[Desktop Entry]
Name=My script
Comment=Test hello world script
Exec=/home/user/yourscript.sh
Icon=/home/user/youricon.gif
Terminal=false
Type=Application

Original credits to: terdon
Also, make sure you set the .desktop file as Executable (otherwise, you'll get the errror - unauthorized)

Dealing with complexity in software

These two techniques can be really helpful in both building and debugging large projects:

-Unit Testing
Unit Testing enables us to narrow down problematic area and save time.

-Event Tracking (Backtrace)
Backtrace can tell if we are editing the right section of code. If the edited section of code is never fired, then we should see what is being run instead of it.

Monday, November 9, 2015

Genymotion - adb devices returns Device Offline

I have planned to use Genymotion emulator VM to debug my Android application which is being developed in my VirtualBox hosted Ubuntu's Android Studio.
However, I had problems connecting my adb using adb connect IP. It always  returned device offline status.

When I have tried from Windows (with latest version of adb), it worked ok.
Then, after upgrading my Linux adb to latest version, it worked ok from Linux as well.

So , in case you have status "Device offline" when issuing adb devices command, you should consider obtaining latest possible adb/sdk version!!!!

Connect Genymotion emulator to Android Studio running in VM

Great tutorial here:
http://scrumsofanarchy.com/adb-over-wi-fi-with-genymotion-android-emulator/

Run your Genymotion device. Use adb tool command line to connect to your development machine via TCP.


Default IP address of Genymotion device:
192.168.56.101


Command for adb to connect to Genymotion device:

adb connect 192.168.56.101

After this, you should be able to run your apps on Genymotion emulator, instead of physical mobile phone or tablet.

Thursday, November 5, 2015

Finding event handlers in jQuery

Finding right event handler in jQuery apps is not always easy. Here is a tool that can help you out :

findHandlersJS

git repository of the tool

Hope it well help you in some debugging problems.

Tuesday, November 3, 2015

Blender - how to apply texture to a face of a 3D object

Blender version 2.73 - Unwrapping textures and exporting model to Assimp

1.
Select an object

2.

In Object data properties window (one with triangle icon) add new UV map

3.
 In Material window add new Material

4.
In Texture properties window add new texture and choose type "Image or movie".
In Image options below, find the image on HDD.
In Mapping section select the recently created UVMap (choose Coordinates: UV).

5.

Now go to Edit mode (TAB) and select a face on this object. Click U to unwrap, and unwrap for any other face you want to texturize.

Export to .OBJ and loading using Assimp library should now work. Make sure you have normals correct and that they are included in the Export (CTRL N in edit mode switches normals, in case you have problems with lighting in OpenGL).

Also, for real time results, choose Texture View in header of your active preview window.

Magento 1.9 - custom extension settings return error 404

In case your custom Magento extension cannot open it's Settings page in System->Configuration, make sure you have set proper ACL for it in adminhtml.xml.

The returned error code is 404.

Monday, November 2, 2015

C++ Access Violation errors

C++ Access Violation errors are always a sign of a invalid or null pointer.

While debugging in VS, you should be careful with the arrow VS uses to indicate the failing line. It can be one line lower on screen then the actual failing line.

Also, these errors can be generated by violating required command order.
For example , if one calls :


GLuint textureID;
glGenTextures(1, &textureID);

before gl is initialized, it will fail with Access Violation error, as the function cannot find the variables it rely on.

Integrating Abraham's Twitter OAuth library into Magento 1.9 lib folder

Recently, in an attempt to include excellent TwitterOAuth library to my Magento 1.9 lib folder, I have found a problem with array_map function in Util.php file (in TwitterOAuth\Util). The namespace used with that call must be modified to match the one used by Magento (usually empty).

Otherwise, error 32 is generated - "Couldn't authenticate".

Besides this little problem, library classes must be renamed to comply to Magento's autoloading rules (i.e. class Config should become Twitteroauh_Config, while being installed to lib/Twitteroauth/Config.php).

PSR-1 and PSR-2 coding standards for PHP

Visual aspects of code play a significant role in raising or drowning developer's productivity. In case that there's too much clutte...