Tuesday, December 13, 2016

Make gpg-signing work with WebStorm git commit

Add these two lines, on ~/.gnupg/gpg.conf:

no-tty
use-agent


Install the following tools using brew:
$ brew install gnupg gnupg2 pinentry-mac


Add this in ~/.gnupg/gpg-agent.conf (gpg-agent.conf not yet existing on my machine):
pinentry-program /usr/local/bin/pinentry-mac 

Run this:
$ git config –global gpg.program gpg2


Solution seen here: https://youtrack.jetbrains.com/issue/IDEA-110261


Happy Coding!

Friday, December 2, 2016

Error: connect ECONNREFUSED 192.168.254.176:3306

In macOS environment there is no explicit file for my.cnf. It's weird, before I introduced .my.cnf in home directory, applications can connect to remote host (e.g., 192.168.254.176) just fine.

The solution is to force the TCP on .my.cnf

[client]
protocol=tcp


Restart:
$ brew services restart mysql



It turns out that the MySQL installation on my machine is using socket. What's odd is I'm not using localhost (e.g., 192.168.254.176) for database connection's host despite server and client are same machine, yet MySQL still resorts to using socket.


On Unix, if you are running the server and the client on the same machine, connect to localhost. For connections to localhost, MySQL programs attempt to connect to the local server by using a Unix socket file, unless there are connection parameters specified to ensure that the client makes a TCP/IP connection
-- https://dev.mysql.com/doc/refman/5.5/en/problems-connecting.html

Thursday, December 1, 2016

Enabling MySQL's binary logging on macOS

MySQL 5.7.16, installed on macOS Sierra using Homebrew.

With Homebrew installation, it's convenient to access mysql commandline. Whereas using its DMG installer, the mysql commandline can only be accessed using its full path.

mysql --user root --password -e 'SHOW VARIABLES' | grep log_bin

By default, log_bin is disabled
log_bin OFF
log_bin_basename 
log_bin_index 
log_bin_trust_function_creators OFF
log_bin_use_v1_row_events OFF
sql_log_bin ON



Create directory where to put the binary logging files and its index:
sudo mkdir /var/log/kel-mysql-log-bin/
sudo touch /var/log/kel-mysql-log-bin/binlogging.index
sudo chown -R `whoami` /var/log/kel-mysql-log-bin/


Check the binary logging directory:
ls -la /var/log/kel-mysql-log-bin/

Output:
drwxr-xr-x   3 jack  wheel   102 Dec  1 19:55 .
drwxr-xr-x  60 root  wheel  2040 Dec  1 19:55 ..
-rw-r--r--   1 jack  wheel     0 Dec  1 19:55 binlogging.index


Create .my.cnf in user's home path:
vim ~/.my.cnf

.my.cnf content:
[mysqld]
log-bin=/var/log/kel-mysql-log-bin/binlogging
server-id=1


Restart MySQL:
mysql.server restart


Check if the binary logging is enabled:
mysql --user root --password -e 'SHOW VARIABLES' | grep log_bin

Output:
log_bin ON
log_bin_basename /var/log/kel-mysql-log-bin/binlogging
log_bin_index /var/log/kel-mysql-log-bin/binlogging.index
log_bin_trust_function_creators OFF
log_bin_use_v1_row_events OFF
sql_log_bin ON


Check the binary logging directory:
ls -la /var/log/kel-mysql-log-bin/

Output:
drwxr-xr-x   4 jack  wheel   136 Dec  1 19:57 .
drwxr-xr-x  60 root  wheel  2040 Dec  1 19:55 ..
-rw-r-----   1 jack  wheel   154 Dec  1 19:57 binlogging.000001
-rw-r-----   1 jack  wheel    44 Dec  1 19:57 binlogging.index


log_bin variable is not something that is being set directly, it's a read-only variable. To turn the log_bin on, the binary logging directory and index must be specified.


Happy Coding!

Wednesday, October 5, 2016

Destructuring

Destructuring makes code readable

// We could use this directly, but the parameter names won't be obvious
//      EmployeeViewResource.get($state.params)
            
// So let's do this:
const {employeeId,userId} = $state.params;

EmployeeViewResource.get({employeeId, userId}).$promise.then(result =>

Sunday, October 2, 2016

newing from dynamically-loaded type

newing an object from a dynamically-loaded/reflected type from statically language such as C# and Java requires an API (e.g., Activator.CreateInstance for C# developers). Whereas in node you can still use the new keyword

> new (require('./api/-core/protocol-buffer/proto-mapping')['com.puter.platform.protocols.users.AccountUpdated'])({account: { uuid: {id: '021e4feb-99c4-419b-8891-b38bd6b00897'}}}).encode64();


Don't forget the parenthesis after the new keyword.

Have yet to know what's the difference of the above dynamic object creation from ES6's Reflect.construct.


Happy Coding!

Thursday, September 29, 2016

Protobufjs decoding base64

These are same:

var obj = MessageName.decode(Buffer.from(base64string, 'base64'));

var obj = MessageName.decode64(base64string);

Saturday, July 30, 2016

Error with: npm install pdf-fill-form

The solution to following error..

pdf-fill-form@2.0.0 install /Users/jack/node-playground/test-pdf/node_modules/pdf-fill-form
node-gyp rebuild
CXX(target) Release/obj.target/pdf_fill_form/src/pdf-fill-form.o
CXX(target) Release/obj.target/pdf_fill_form/src/NodePopplerAsync.o
CXX(target) Release/obj.target/pdf_fill_form/src/NodePoppler.o
../src/NodePoppler.cc:9:10: fatal error: 'poppler/qt4/poppler-form.h' file not found
#include 
^
1 error generated.
make: *** [Release/obj.target/pdf_fill_form/src/NodePoppler.o] Error 1
gyp ERR! build error 
gyp ERR! stack Error: make failed with exit code: 2
gyp ERR! stack at ChildProcess.onExit (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:276:23)
gyp ERR! stack at emitTwo (events.js:106:13)
gyp ERR! stack at ChildProcess.emit (events.js:191:7)
gyp ERR! stack at Process.ChildProcess._handle.onexit (internal/child_process.js:204:12)
gyp ERR! System Darwin 15.5.0
gyp ERR! command "/usr/local/bin/node" "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /Users/jack/node-playground/test-pdf/node_modules/pdf-fill-form
gyp ERR! node -v v6.0.0
gyp ERR! node-gyp -v v3.4.0
gyp ERR! not ok 
npm WARN test-pdf@1.0.0 No description
npm WARN test-pdf@1.0.0 No repository field.
npm ERR! Darwin 15.5.0
npm ERR! argv "/usr/local/bin/node" "/usr/local/bin/npm" "install" "pdf-fill-form" "--save"
npm ERR! node v6.0.0
npm ERR! npm v3.10.5
npm ERR! code ELIFECYCLE

npm ERR! pdf-fill-form@2.0.0 install: node-gyp rebuild
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the pdf-fill-form@2.0.0 install script 'node-gyp rebuild'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the pdf-fill-form package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! node-gyp rebuild
npm ERR! You can get information on how to open an issue for this project with:
npm ERR! npm bugs pdf-fill-form
npm ERR! Or if that isn't available, you can get their info via:
npm ERR! npm owner ls pdf-fill-form
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR! /Users/jack/node-playground/test-pdf/npm-debug.log

..is to install Xcode first:

xcode-select --install

Then re-run:
npm install pdf-fill-form


Happy Coding!

Friday, July 29, 2016

Show invalid inputs upon submit

Old approach was to set all the controls dirty upon submit. This is the better way:

    form .ng-invalid.ng-dirty, form.ng-submitted .ng-invalid  {
        border-color: red;
    }

Friday, July 22, 2016

Little-known capability of require

require can also read JSON file for you:
let c = path.join(os.homedir(), 'connection.json');

let connectionJson = require(c);

let connectionString =
        'postgres://'
        + connectionJson.user
        + ':' + connectionJson.password
        + '@' + connectionJson.host
        + '/' + connectionJson.database;

let massiveInstance = massive.connectSync({connectionString: connectionString});
app.set('db', massiveInstance);

So no more need to open and read the JSON file manually:
let c = path.join(os.homedir(), 'connection.json');

fs.readFile(c, 'utf8', (err, data: any) => {

    console.log(data);

    let connectionJson = JSON.parse(data);

    let connectionString =
            'postgres://'
            + connectionJson.user
            + ':' + connectionJson.password
            + '@' + connectionJson.host
            + '/' + connectionJson.database;

    let massiveInstance = massive.connectSync({connectionString: connectionString});
    app.set('db', massiveInstance);
});



Happy Coding!

Thursday, July 21, 2016

Smart Data Structure vs Smart Code

Smart data structures and dumb code works a lot better than the other way around." -- Eric S. Raymond

"Bad programmers worry about the code. Good programmers worry about data structures and their relationships." -- Linus Torvalds

"The best code is no code at all" -- Jeff Atwood

I'm proud of my dumb codes, as I create smart data structures instead.

With smart data structure, the code can be simple, smaller and easy to read. And sometimes, you don't even need to write any code at all if you are using smart data structure.

With dumb data structure, the code tend to become smart/clever/tricky. Sometimes I'm ceasing to look at the smart/clever/tricky code as smart/clever/tricky, they are sometimes looking like a show-off codes.

And some programmers call their codes a hack when oftentimes it's really a poor code compensating for dumb data structure.

Some programmers are giving the word hack a bad name.

I hate writing codes.

I should fully qualify that sentence. I hate writing codes against dumb data structures.

http://www.ienablemuch.com/2014/07/when-using-stringly-typed-code-eliminate-boilerplate-codes.html
http://programmers.stackexchange.com/questions/163185/torvalds-quote-about-good-programmer
https://blog.codinghorror.com/the-best-code-is-no-code-at-all/

Monday, July 18, 2016

Prefer type declaration instead of casting

If casting is use, you may incur typos or spelling errors and the compiler won't even flag you about it. Prefer type declaration, use let-variable-colon-type-assignment.





Happy Coding!

Sunday, July 17, 2016

Making unnecessary promises?

That's a sign of cargo culting

getOptions(): ng.IPromise<IOption[]> {

    let defer = $q.defer();

    http.get('options.json').then(result => {
        defer.resolve(result.data);
    });

    return defer.promise;
}

That should be improved to:

getOptions(): ng.IPromise<IOption[]> {

    return $http.get('options.json').then(result => {
        return result.data;
    });

}


Read from codelord.net



Cargo Culting, unnecessary rituals. Yes, no matter how logical programmers are, they are not immune to blind faith too. Sometimes, it's because of lack of understanding of how the tool should be used. Sometimes also, the documentation is lacking.

Some programmers have too much faith in their own code, when in fact they should not be writing codes at all or should just write a minimal amount of code in the first place.

https://blog.codinghorror.com/the-best-code-is-no-code-at-all/

http://haacked.com/archive/2010/08/26/not-paid-to-write-code.aspx/

https://en.wikipedia.org/wiki/Cargo_cult_programming


Another good read on promises anti-pattern: http://taoofcode.net/promise-anti-patterns/


Happy Coding!

Saturday, July 16, 2016

Broken Promises? Bluebird Solves It!

Broken promises. denodeify and Q's denodeify both doesn't work on MassiveJS:

let find = denodeify(db.notification.email.find)
let find = Q.denodeify(db.notification.email.find)

And even bluebird's promisify doesn't work:

let find = bluebird.promisify(db.notification.email.find)


All of them when this is performed:

find({locationId: 168}).then(result => {
}


Results to this:

TypeError: Cannot read property 'query' of undefined
    at Queryable.find (/Users/geek/WebstormProjects/personal/node_modules/massive/lib/queryable.js:108:12)


Those promisifier libraries might be having a hard time converting MassiveJS callback to promise as the target method(find) are dynamically generated.


And then I read bluebird's promisifyAll method. It can create a promise version of each methods in the object.

let email = bluebird.promisifyAll(db.notification.email);

With that, it will generate a promise version of all the methods found in db.notification.email object. The promise version of the method have the Async suffix on the method name.


An example use:

email.findAsync({locationId: 168}).then(result => 
});

And it works!


Then I found another approach that works in bluebird, it can also target specific method to promisify. You just have to pass the immediate object of the method you want to promisify on the second parameter.

let find = bluebird.promisify(db.notification.email.find, db.notification.email);

find({locationId: 168}).then(result => {

});


Happy Coding!

Monday, July 11, 2016

Sample XML XSLT

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes" method="html"/>

    <xsl:template match="data">
        <link href="/bootstrap/css/bootstrap.min.css" type="text/css" rel="stylesheet"/>
        <table class="table table-bordered table-condensed table-striped">
            <xsl:apply-templates/>
        </table>
    </xsl:template>

    <xsl:template match="titles">
        <tr>
          <xsl:apply-templates mode="header"/>
        </tr>    
    </xsl:template>

    <xsl:template match="row" name="standardRow">
        <tr>
          <xsl:apply-templates/>
        </tr>
    </xsl:template>

    <xsl:template match="row/*">
        <td>
          <xsl:apply-templates select="node()"/>
        </td>
    </xsl:template>

    <xsl:template match="title" mode="header">
        <th>
          <xsl:value-of select="node()"/>
        </th>
    </xsl:template>

</xsl:stylesheet>

<?xml version="1.0"?>

<?xml-stylesheet type="text/xsl" href="sample.xslt"?>


<data>

    <titles>
        <title>Pangalan</title>
        <title>Apelyido</title>    
    </titles>


    <rows>

        <row><Lastname>Abbas</Lastname><FirstName>Syed</FirstName></row>
        <row><Lastname>Abel</Lastname><FirstName>Catherine</FirstName></row>
        <row><Lastname>Abercrombie</Lastname><FirstName>Kim</FirstName></row>

        
    </rows>

</data>


Using TypeScript feels like you are in the Matrix, you can bend things(types) at will

Using TypeScripts feels like you are in the Matrix, you can bend things(types) at will.


Improved the code from this..


export function pageBuilder(req: express.Request, res: express.Response, next: Function)
{

    let dRequest = denodeify(request);

    let cookie = request.cookie(req.headers["cookie"]);

    let headers = {cookie};

    let parts = {
        header : dRequest({url: "http://localhost:168/ui/header.html", headers}),
        toolbox: dRequest({url: "http://localhost:168/ui/toolbox.html", headers}),
        footer : dRequest({url: "http://localhost:168/ui/footer.html", headers})
    };


    Q.all(<any>parts).then(result =>
    {
     
        let html = buildPage(result.header.body, result.toolbox.body, result.footer.body);

        res.send(html);
    });

}

..to this:


export function pageBuilder(req: express.Request, res: express.Response, next: Function)
{

    let dRequest = denodeify(request);

    let cookie = request.cookie(req.headers["cookie"]);

    let headers = {cookie};

    let parts = {
        header : dRequest({url: "http://localhost:168/ui/header.html", headers}),
        toolbox: dRequest({url: "http://localhost:168/ui/toolbox.html", headers}),
        footer : dRequest({url: "http://localhost:168/ui/footer.html", headers})
    };


    Q.all(<any>parts).then(result =>
    {
        let partsResult: {
            header: express.Request,
            toolbox: express.Request,
            footer: express.Request
        } = <any>result;


        let html = buildPage(partsResult.header.body, partsResult.toolbox.body, partsResult.footer.body);

        res.send(html);
    });

}

The current signature of Q's TypeScript definition does not allow dictionary, but you can do adhoc'y types even in the code's body, don't necessarily need to put the type in the global context.


Happy Coding!

Thursday, July 7, 2016

Using array instead of creating a junction table with foreign keys

Joining is slow on junction table:

explain analyze
select coupons.coupon_id 
from coupons join coupons_products using (coupon_id) 
where coupons.user_id is null and product_id = 1000 group by coupon_id;

Planning time: 0.931 ms
Execution time: 676.687 ms

Try to query against another query:

explain analyze
select coupons.coupon_id 
from coupons 
where coupons.user_id is null 
    and coupons.coupon_id in (select cp.coupon_id from coupons_products cp where cp.product_id = 100);

Planning time: 0.769 ms
Execution time: 0.075 ms

The above has same performance with array approach:

explain analyze
select coupons.coupon_id 
from coupons 
where coupons.user_id is null and product_ids @> array[1000];

Planning time: 0.211 ms
Execution time: 0.075 ms


Array query and junction table query(no-join) has same performance, 0.075 ms. The advantage of array query is its planning takes less time. 0.211 ms vs 0.769 ms.


This is an observation made on denormalizing junction table to array


Happy Coding!

NodeJS choosing between req.params and req.query, and when to use them both.

req.params.memberId

actual url:
    http://example.com/member/thisGoesToParam

nodejs's routing: 
    http://example.com/member/:memberId

req.params.memberId == "thisGoesToParam"


req.query.memberId
actual url:
    http://example.com/member?memberId=thisGoesToQuery

nodejs's routing: 
    http://example.com/member

req.query.memberId == "thisGoesToQuery"



req.params is most often used since it can directly/explicitly identify a resource right in the URL itself, and it's SEO-friendly. Search engines prefer URLs that has no question marks in them, clean URLs, req.params can facilitate clean URL.


req.query is mostly used on searching or paging. Anything that are extra to the identifier, goes to req.query. An example, getting the list of person (uses paging since there are too many persons in a country) from a country should better use req.query instead of req.param.


actual url:
    http://example.com/country/PH/person?page=1

routing: 
    http://example.com/country/:countryCode/person

req.params.countryCode == "PH"
req.params.page == 1

that might return:

{
 country: "Philippines"
 persons: ["Schwarzenegger", "Zach"]
}


Anything that goes to req.params are called resource identifier, meaning even how many times the url with embedded resource is called/submitted to, result is always the same. REST has a terminology for that, idempotent. Idempotent meaning, when something is called/submitted to a url with a primary key, the result of calling/submitting to a URL should be always the same even how many times it is called/submitted to.

Parameters that goes to req.params returns idempotent result. While parameters that goes to req.query returns non-idempotent result, as req.query's result today would not be same as req.query's result tomorrow, later or any point in time


Let's say later there are new persons added to a country, the country identifier (req.params.countryCode) will always return idempotent result, same country even how many times it is called. While with req.query.page, it returns non-idempotent result, a value passed to req.query even it's the same might not be the same(say page number 1 is called/refreshed on the browser many times) depending on when the url is called/submitted.

http://example.com/country/PH/person?page=1

So even we use the same Country and same Page, although the country's parameter always return the same result(Philippines), the page's parameter might return different results depending on when the url is called/submitted.

{
 country: "Philippines"
 persons: ["Adams", "Applegate", "Ashley"]
}


It's much better to use req.params, not only it is SEO-friendly for search engines, in code it's also easy to spot the required parameters(mostly primary key) as they are explicitly part of the url itself.


routing: 
    http://example.com/country/:countryCode/person

actual url: 
    http://example.com/country/PH/person


To access countryCode from req.params. Simply read it from: req.params.countryCode


If a country REST API (that fetches the country name and its people) uses req.query instead of req.params, the REST's URL would have a routing design like this:

http://example.com/country/person 


The URL is not so intuitive, some non-native English speaker might think if "person" is a country code.

Note that question marks can't be included on node.js's routing, so the consumer of the REST's URL would have to guess what is the name of the country parameter for the country, is it countryCode? is it countryId? req.query parameters have to be always documented, while req.params is so intuitive it doesn't even need documentation.


Happy Coding!

Tuesday, July 5, 2016

JavaScript's C# SelectMany

C# has a convenient method for flattening collections' collection, that method is SelectMany:

var result = 
    from account in areas.SelectMany(area => area.Accounts)
    where account.Selected
    select account.AccountId;



In JavaScript:

interface IAccountDto
{
    accountId: number;
    accountName: string;

    selected?: boolean; // not in actual DTO, just used in UI
}

interface IAreaDto
{
    areaName: string;
    accounts: IAccountDto[];
}



class Something {

   
    areas: IAreaDto[] = [
            {
                areaName: "Philippines",
                accounts: [
                    {
                        accountId  : 168,
                        accountName: "Account 168",
                        selected: true
                    },
                    {
                        accountId  : 169,
                        accountName: "Account 169",
                        selected: true
                    },
                ]
            },
            {
                areaName: "China",
                accounts: [
                    {
                        accountId  : 170,
                        accountName: "Account 170"
                    },
                    {
                        accountId  : 171,
                        accountName: "Account 171",
                        selected: true
                    },
                ]
            },


        ];   
   
   
   getResult(): number[] {

       let result = 
            this.areas.map(ar => ar.accounts)
            .reduce((a,b) => a.concat(b), [])
            .filter(ac => ac.selected)
            .map(ac => ac.accountId)
            
       return result;
   }
}



let s = new Something();

let x = JSON.stringify(s.getResult());

document.body.innerHTML = x;

Happy Coding!

Tuesday, June 28, 2016

Design for the default

If the library doesn't work out of the box, there must be a problem with the library.

node-soap generates xmlns prefix (tns), but it doesn't apply it to SOAP's method:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:tns="http://v5.soap.platform.helloworld.com/">
    <soap:Body>
         <authenticate>
             <apiKey>meh</apiKey>
             <username>ryan</username>
             <password>dahl</password>
        </authenticate>
    </soap:Body>
</soap:Envelope>

This is the right XML, as tested in Google Chrome's Boomerang extension, there is tns prefix in SOAP's method (authenticate):
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:tns="http://v5.soap.platform.helloworld.com/">
    <soap:Body>
         <tns:authenticate>
             <apiKey>meh</apiKey>
             <username>ryan</username>
             <password>dahl</password>
        </tns:authenticate>
    </soap:Body>
</soap:Envelope>



To fix the node-soap's broken default, add this option on createClient method:

var options = {
    ignoredNamespaces: {
        namespaces: [],
        override: true
    }
}


soap.createClient ( url, options, function ( err, client ) {


Using that, node-soap will apply the tns prefix to the SOAP's method name.


.NET's generated SOAP works out of the box, notice that there is no prefix in SOAP call:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
    <s:Header>
        <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none" />
    </s:Header>
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <authenticate xmlns="http://v5.soap.platform.helloworld.com/">
            <apiKey xmlns="">meh</apiKey>
            <username xmlns="">ryan</username>
            <password xmlns="">dahl</password>
        </authenticate>
    </s:Body>
</s:Envelope>


Happy Coding!

Sunday, June 26, 2016

Make further proxy requests authenticated

app.get('/hoo/ray', (req,res,next) => {


    let url = "https://www.helloworld.com/ui/fragments/header.html";

    let cookie = request.cookie(req.headers["cookie"]);

    let headers = {cookie};

    request({url, headers}, (error, response, body) => {

        url = "https://www.helloworld.com/ui/fragments/toolbox.html";

        request({url, headers}, (toolboxError, toolboxResponse, toolboxBody) => {

            let html = body + toolboxBody;

            res.writeHead(200, {
                'Content-Type'  : 'text/html',
                'Content-Length': html.length,
                'Expires'       : new Date().toUTCString()
            });


            res.end(html);

        });

    });

});


Next step, convert those callback hell to promises.

Sunday, May 1, 2016

pm2 must not be ran with sudo

If you got an EACCES error when you run pm2 without sudo..

me@ubuntu:~/myapp$ pm2 start ./bin/www
events.js:160
      throw er; // Unhandled 'error' event
      ^

Error: connect EACCES /home/me/.pm2/rpc.sock
    at Object.exports._errnoException (util.js:896:11)
    at exports._exceptionWithHostPort (util.js:919:20)
    at PipeConnectWrap.afterConnect [as oncomplete] (net.js:1073:14)


..chances are you might try to run pm2 with sudo and it will work.

However, it will cause an undefined value on process.env.PWD, and then it will cause SPA page that are refreshed or re-loaded from bookmark not to load.

var base = process.env.PWD;

res.sendFile('index.html', {root: path.join(base, '/public')});


To fix the error, make the following your own file /home/yourUsernameHere/.pm2/rpc.sock

sudo chown yourUsernameHere ~/.pm2/rpc.sock


Doing the above you can now run your pm2 without the sudo.

After running:

$ pm2 start ./bin/www

Run this:

$ pm2 save
$ pm2 startup

Then follow the instruction of that pm2 startup command.


Happy Coding!

Thursday, April 28, 2016

TypeScript productivity

Not only you can do adhoc-y parameters, you can also do adhoc-y return types.


customComplete(dto: { onboardId: number; session: string; }): ng.resource.IResource<{ completed: boolean}>;


Happy Coding!

Naming

Darn, decade (note the singular :P) of experience in the programming industry, and I still don't have a hard and fast rule on names in program like in Firstname vs First Name.

Correct form is First Name, so that gives us these valid names for the program: first_name, firstName, FirstName; words have boundary. Hence these are invalid: firstname, Firstname.

It's a different rule on Username though, correct form is Username, not User Name.These are valid names for the program: username, Username. These are invalid: user_name, userName, UserName.

Thursday, April 14, 2016

Refusing deeply nested code

I have this angular directive, and I don't want nested code, so I don't embed the function directly in the link property:

angular.module("AcroformBuilder", [])
    .directive('afBuilder', [() => {
            return <ng.IDirective>{
                restrict: 'E',
                scope: {
                    metaDataGetter: '&',
                    savedDataGetter: '&',
                    afObject: '='
                },
                link: FormBuilder
            };

        }]);

.
.
.
function FormBuilder(scope: IScopeProperties, element: ng.IRootElementService, attrs: ng.IAttributes) {





Eventually, I needed the $q service. Since the link property cannot be dependency injected, the easiest way to solve the problem is to move the function directly to link property. However did I say I refuse deeply nested code? And if you can infer from the code above, directly embedding the function in the directive's link would make the function deeply nested, around 16 spaces or 4 tabs from the left.



To cut to the chase, javascript has this magical function to pass invisible parameter whenever a function is called. That magical function is called bind.

Just bind two parameters, first the object and then the parameter itself. The link's function is called and not instantiated (javascript functions are like a class, can be instantiated too), so we just pass undefined on first parameter and then pass the $q service on the second parameter.

angular.module("AcroformBuilder", [])
    .directive('afBuilder', ['$q',($q: ng.IQService) => {
            return <ng.IDirective>{
                restrict: 'E',
                scope: {
                    metaDataGetter: '&',
                    savedDataGetter: '&',
                    afObject: '='
                },
                link: FormBuilder.bind(undefined, $q)
            };

        }]);

.
.
.
function FormBuilder($q: ng.IQService, scope: IScopeProperties, element: ng.IRootElementService, attrs: ng.IAttributes) {




Happy Coding!

Tuesday, March 29, 2016

Add column with default value and nullity

create table something
(
p int not null
);

insert into something(p) values(1);


alter table something
add q int default 6 not null;


alter table something
add r int default 8 null;


select * from something;



Postgresql output:
p q r
1 6 8



Sql Server output:
p q r
1 6 null

Tuesday, January 12, 2016

First gulp is the best gulp

var gulp = require('gulp');
var ts = require('gulp-typescript');

var tsProject = ts.createProject('theApp/tsconfig.json');


gulp.task('typings', function () {
    return gulp.src('theApp/**/*.d.ts')
        .pipe(gulp.dest('./xdeploy'));
});



gulp.task('genjs', ['typings'], function () {
    return tsProject.src('theApp/**/*.ts')
        .pipe(ts(tsProject))
        .pipe(gulp.dest('./xdeploy'));
});

gulp.task('copyjs',  ['genjs'], function () {
    return gulp.src('theApp/**/*.js')
        .pipe(gulp.dest('./xdeploy'));
});

gulp.task('copyjson',  ['copyjs'], function () {
    return gulp.src('theApp/**/*.json')
        .pipe(gulp.dest('./xdeploy'));
});



gulp.task('default', ['copyjson'], function () {
    return gulp.src('theApp/node_modules/**/*', { 'base' : 'theApp/node_modules' })
        .pipe(gulp.dest('./xdeploy/node_modules'));
});