[ ubuntu ] install phantomjs, imagemagick, optipng, jpegoptim

sudo apt-get install phantomjs imagemagick optipng jpegoptim

[ gem ] bundle install mysql; checking for mysql_query() in -lmysqlclient… no


Gem::Ext::BuildError: ERROR: Failed to build gem native extension.Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
current directory:/home/pong/.rvm/gems/ruby-2.1.2@toaster/gems/mysql2-0.3.18/ext/mysql2/home/pong/.rvm/rubies/ruby-2.1.2/bin/ruby -r ./siteconf20171017-2320-19gfum4.rbextconf.rbchecking for ruby/thread.h... yeschecking for rb_thread_call_without_gvl() in ruby/thread.h... yeschecking for rb_thread_blocking_region()... yeschecking for rb_wait_for_single_fd()... yeschecking for rb_hash_dup()... yeschecking for rb_intern3()... yeschecking for mysql_query() in -lmysqlclient... nochecking for main() in -lm... yeschecking for mysql_query() in -lmysqlclient... nochecking for main() in -lz... yeschecking for mysql_query() in -lmysqlclient... nochecking for main() in -lsocket... nochecking for mysql_query() in -lmysqlclient... nochecking for main() in -lnsl... yeschecking for mysql_query() in -lmysqlclient... nochecking for main() in -lmygcc... nochecking for mysql_query() in -lmysqlclient... no*** extconf.rb failed ***Could not create Makefile due to some reason, probably lack of necessarylibraries and/or headers.  Check the mkmf.log file for more details.  You mayneed configuration options.
Provided configuration options: --with-opt-dir --without-opt-dir --with-opt-include --without-opt-include=${opt-dir}/include --with-opt-lib --without-opt-lib=${opt-dir}/lib --with-make-prog --without-make-prog --srcdir=. --curdir --ruby=/home/pong/.rvm/rubies/ruby-2.1.2/bin/ruby --with-mysql-dir --without-mysql-dir --with-mysql-include --without-mysql-include=${mysql-dir}/include --with-mysql-lib --without-mysql-lib=${mysql-dir}/lib --with-mysql-config --without-mysql-config --with-mysql-dir --without-mysql-dir --with-mysql-include --without-mysql-include=${mysql-dir}/include --with-mysql-lib --without-mysql-lib=${mysql-dir}/lib --with-mysqlclientlib --without-mysqlclientlib --with-mlib --without-mlib --with-mysqlclientlib --without-mysqlclientlib --with-zlib --without-zlib --with-mysqlclientlib --without-mysqlclientlib --with-socketlib --without-socketlib --with-mysqlclientlib --without-mysqlclientlib --with-nsllib --without-nsllib --with-mysqlclientlib --without-mysqlclientlib --with-mygcclib --without-mygcclib --with-mysqlclientlib --without-mysqlclientlib
To see why this extension failed to compile, please check the mkmf.log which canbe found here:
extconf failed, exit code 1
Gem files will remain installed in/home/pong/.rvm/gems/ruby-2.1.2@toaster/gems/mysql2-0.3.18 for inspection.Results logged to/home/pong/.rvm/gems/ruby-2.1.2@toaster/extensions/x86_64-linux/2.1.0/mysql2-0.3.18/gem_make.out
An error occurred while installing mysql2 (0.3.18), and Bundler cannotcontinue.Make sure that `gem install mysql2 -v '0.3.18'` succeeds before bundling.
In Gemfile:  mysql2


sudo apt-get install libmysqlclient-dev

ref: https://stackoverflow.com/questions/5795309/gem-install-mysql-fail

[ ubuntu 16.04 ] share clipboard

  • Install Guest Additions CD image
  • Settings > General > advanced tab >
    Shared Clipboard : bidirectional
    Drag and drop : bidirectional

If it does not work, try installing virtualbox-guest-dkms.

sudo apt-get install virtualbox-guest-dkms

Then reboot

ref : https://askubuntu.com/questions/533071/virtualbox-4-12-shared-clipboard-not-working-in-ubuntu14-04,


[ selenium ] 101

GET page

driver.get(baseUrl + "/90719/edit");

Find webElement by anchor/by name

WebElement element = driver.findElement(By.linkText("CREATE A POST"));
WebElement element = driver.findElement(By.name("targetSeoKeyphrase"));

ref : https://loadfocus.com/blog/2013/09/05/how-to-locate-web-elements-with-selenium-webdriver/

webElement action

webElement.sendKeys("test simple article");

check from pageSource




[ mixin ] rhythm : Margins and Padding

Using our 42px <h1> example from earlier we might do something like:

h1 {
  @include rhythm(3, 1, 0, 2, 42px);

Rhythm syntax

rhythm($lines, $font-size, $offset)

Which compiles to:

h1 {
  margin-top: 1.714285714em;    // 3 units or 24*3 = 72px
  padding-top: .571428571em;    // 1 unit or 24px
  padding-bottom: 0;            // 0 units 0px
  margin-bottom: 1.142857143em; // 2 units or 24*2 = 48px

Functions are similar but return values that are used within a css rule. Let’s say I just want to set all 4 margins on my <h1> with a combination of rhythm units and standard CSS notation.

h1 {
  margin: 0 auto rhythm(3, 42px);

Which compiles to

h1 {
  margin: 0 auto 1.714285714em;

ref : https://atendesigngroup.com/blog/vertical-rhythm-compass

[ mixin ] adjust-font-size-to : font-size and line-height


html {
  font-size: 100%;
  line-height: 1.5em;

* 16px is the default font size for most browsers, so 100% = 16px.
* A relative line-height is always relative to the font-size of the current element,
so in this case the line-height is set to 1.5 em ( 1.5 * 16px = 24px).

2) The fun starts when you begin setting font sizes on other elements.
Let’s say we want to make our <h1>s 42px. We do so using the adjust-font-size-to mixin.

Example :

h1 {
  @include adjust-font-size-to(42px);

2.1) First it sets our font-size relative to our element’s container, which in most cases will be our $base-font-size. So we get something like:

font-size: 2.625em;   // 2.625*16px=42px

2.2) Vertical Rhythm also sets line-height to a factor of our baseline grid, larger than the font-size.
So in the case of our 42px font-size, it sets the line-height to 48px or 2 baseline units or technically speaking

line-height: 1.142857143em;  // 1.142857143 * 42px = 48pxish


3) so what happens when you want to go down in font size?
Let’s say 12px on some meta data.
What we learned above would result in a line height of 24px, which would be akwardly large.
Easy! If we want a line height of 16px so that every 3rd line of our meta data lines up with every 2nd baseline.
We just pass the desired number of rhythm units to the same mixin.

In this case:

.meta {
  @include adjust-font-size-to(12px, 2/3);


ref : https://atendesigngroup.com/blog/vertical-rhythm-compass


[ GTM ] google TagManager

0. Installation

1. Create Google tagManager account + container
Go to https://tagmanager.google.com

Typically, you set up one container per web domain. However, if the user experience and tags on a website span more than one domain, it’s best to set up a single container that serves all the domains involved. Here are a few considerations.

1.1 Configuration (rules, triggers, and variables) can’t easily be shared across containers without using container exporting and importing, or by using the API. If the tags and firing logic is similar across domains, it makes sense to use a single container, because maintaining multiple similar configurations is time-consuming and error-prone.

1.2 When someone publishes a container, all changes go live, regardless of domain. If you need to apply changes to one domain without affecting other domains, use a different container for each domain.

2. Copy container code to website

NOTE : Replacing `GTM-XXXX` with your container ID.


add javascript to head

new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],

add html to body

&lt;noscript&gt;&lt;iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXX" height="0" width="0" style="display:none;visibility:hidden"&gt;&lt;/iframe&gt;&lt;/noscript&gt;

ref : https://support.google.com/tagmanager

AMP page

Place the <script> portion of the JavaScript snippet just above the closing </head> tag.

<amp-analytic> section immediately after the opening <body>


If all of your tags fire as pages are loading, and these pages can be identified by their URLs, a basic container implementation may be sufficient for your needs.

  • If your tag firing scenarios are more complex, you may want to implement a more customized container implementation. These custom solutions often implement a data layer, which is code that helps Google Tag Manager pass data from your site or app to your tags. You can learn about why and how you would use a data layer in our solutions guide, and how to set up a data layer on our developer site.

Trobleshooting Container

Preview Mode : https://support.google.com/tagmanager/answer/6107056

Tag Assistant Chrome Extension : https://support.google.com/tagassistant#topic=6000196


1. Create a tag

1. Begin by identifying all of the tags you have deployed on your site and where they are deployed (e.g. in global headers or footers, on landing pages, confirmation pages, in response to button clicks, etc.)

2. Create new tag

  • Trigger ( of new tag ) that we are going to add tag : i.e. when the page is loaded
  • Variable : String, HTML Node element, cookies, random number, custom javascript code
  • dataLayer : If the data you want to collect is not visible on the page, refer to the developer documentation for information on how to pass additional data to tags.

(for example, you can tell GTM to fire a remarketing tag when the purchase_total > $100)

Rather than referencing variables, transaction information, page categories, and other important signals scattered throughout your page, Google Tag Manager is designed to easily reference information that you include in this data layer.

 // dataLayer
 // Example : put the dataLayer when the page is view
 // then fire the google analytic event tag when detected to track data
 dataLayer = [{'destination': 'Hawaii',
 'travelType': 'vacation'

ref : https://developers.google.com/tag-manager/devguide#datalayer

3. Publish


Using google analytics with google tag manager

  1. remove google analytics code on site
  2. add google tag manager code on site
  3. debug using chrome extension “tag assistant”


Troubleshoot : https://developers.google.com/tag-manager/troubleshooting