Chrome Mobile Emulation in Action

Step 1

Open a regular website in Chrome.

Step 2

Right click -> Inspect Element to bring up the develop tools.

Step 3

Click on the settings Icon

settings

Verify the mobile emulation is turned on under Appearances

Step 4

Either hit the ESC button or this little icon to open the drawer.
chromeConsoleDrawer

Step 5

Select the device you’d like to emulate.

Step 6

See it in action.
regretlessMobile

Step 7

Read more about all of the features available. This does a lot more than the regular user agent switcher.

Screen scraping census baby name data with nodeJs, cheerio(jQuery) and promises

—->My Soure Code<—-

Goal

Screen scrape census baby names data for the 51 states and produce a single CSV file.

These data are in html table via sites such as

censusStateData2012

Script must translate all of the table data from 51 states (51 requests) into a single csv file that contains

state,rank,gender,maleName,maleBirths
state,rank,gender,femaleName,femaleBirths

Tools

Design

  • Fire 51 post requests.
  • In each request, parse the html data to produce an array of javascript objects that represents the data collected.
  • Once all requests are done, loop through all of the data collected and generate the csv file.

Main Concepts

This blog entry does a fantastic job explaining the programming used in my code.

Lexical Scope/IIFE/Closure

You need to understand the lexical scope in Javascript so you can understand why async calls inside of a loop will not behave correctly unless you wrap your code in an IIFE. This is explained in details in the blog entry.

For example, the following code will NOT work correctly

for(var i = 0; i < states.length; i++) {
	var stateCode = states[i];
	request(url + stateCode, function(error, response, body){
		// this is wrong
	});
}

It needs to be like

for(var i = 0; i < states.length; i++) {
	var stateCode = states[i];
	(function(stateCode) {
		request(url + stateCode, function(error, response, body){
			// this is right
		});
	})(stateCode);
}

Promises

Promises are used to collect all data from all of the async calls.
This concept works similar to the jQuery promise e.g.

// array of promises
var ajaxCalls = [];

// unknown number of ajaxCalls
ajaxCalls.push(
	$.ajax(....)
);

var group = $.when.apply($, ajaxCalls);
group.done(function() {
    // all ajax calls are done
});

Using promise-io, the syntax will be

// lib
var promiseIo = require("promised-io/promise");
var Deferred = promiseIo.Deferred;

var allStates = []; // array of promises
for(var i = 0; i < states.length; i++) {
	allStates[i] = new Deferred();
}

// when all of the async call return
var group = promiseIo.all(allStates);
group.then(function(array){
	for(var i = 0; i < array.length; i++) {
		// array[i] contains the value returned by the promise
	}
});

// somewhere in an async call
... { ....
allStates[i].resolve('my promise value to return');
... }

Execution

  • You must first install nodeJs
  • Then download/clone my source code
  • Follow my read me instructions for
    npm install ...
    
  • Open censusBabyNamesState.js and update any variables
  • Run
    > node censusBabyNamesState.js
    

    and your csv file will be generated

HttpFox helps filter http requests

Was looking for something for work that filters all of the requests on a page.

Finally spotted the HttpFox plugin that pretty closely achieves what I need.

Install the plugin and click on the tiny icon httpFoxIcon at the lower right of the browser.

Once open, click on the start (to record requests)
httpFoxStart

Load a page of interest, you will see the requests being captured.

Once done, you may filter the results based on anything in the requested URLs such as
httpFoxFilter

How to Help Others Without Compromising Yourself

1. You can’t help someone who is not taking responsibility for helping themselves.

Sometimes, no matter how much you give, the other person doesn’t seem to meet you halfway. It seems like the more you try to help them, the more they stay the same, or worse, regress.

Maybe they have become so used to your helping them that they no longer have the ability to see where they need to help themselves. Or maybe they take your helping for granted so they feel they no longer need to participate.

2. Sometimes, doing nothing is helping them.

When someone asks you for help in some tangible way or when you see the obvious need in others, especially a loved one, it’s very hard to say no. However, before you say yes, ask yourself what’s the cost to you.

Are you compromising yourself in some way that is beyond your personal boundaries? Sometimes by saying no and doing nothing, you’re giving them a chance to take responsibility for their own lives and help themselves.

3. Helping someone doesn’t mean fixing them.

Often, you think you know what is best for another person, but you don’t truly know what is for their highest good or what life has in store for them. They are in a situation because they need to learn some spiritual or life lessons.

You can’t shortchange their learning process, no matter how hard you try to help them, if they’re not in the right place and time to learn those lessons.

4. You can help by accepting them as and where they are.

We all have judgments about ourselves and others. However, helping means accepting the other person as they are and where they are on their life’s path.

It can be excruciatingly painful to sit by and watch the other person self-destruct or seemingly do nothing to help themselves, but maybe this is what they need right now in order to become more aware in themselves.

5. Don’t be attached to the outcome of your helping.

You may have expectations of what someone would become and what they’d do with their lives once you help them. You want to see this person feel better, be happier, healthier, and make better life decisions.

However, it’s not up to you to put intention in the other person’s space. What’s good for them may not be what you expect, and you might not like or agree with the outcome. Let go of attachment to your own ego and your own vision of what the other person will become once they’re helped.

6. Send loving, compassionate intention.

Know that your intention to help another person, when it’s from a place of neutrality, love, and compassion, will always be helpful, whether or not you feel you’re doing enough. Just having the intention to help and sending your peaceful, loving energy to the other person and their situation is sometimes the best thing to do.

Thoughts have energy, so even if you just send compassionate thoughts to the other person, you are doing something to help.

Reblogged from tiny buddha.

How I made tiny carousel swipeable

On parents.com, we previously used the jquery plugin tiny carousel to display various lists of links mostly used to track pregnancy month/week:

For example:
tinyCarousel

The concept is easy. You have a list of items that you want to scroll horizontally by using nav buttons. In our case, all of the content are lists of links. Since parents.com is responsive, the style of the carousel adapts based on screen width. To make parents.com more mobile friendly, we wanted to make these carousels swipeable on touch devices and I was assigned this task.

My immediate thought here is to add a swipe event to the content area to move items left and right. So I tried out the jquery plugin touchSwipe.

So this pen is close to what I came up with. Load the pen with your touch device and swipe on weeks. If an alert is shown, that means the swipe event is detected.

I noticed the swipe event doesn’t get detected consistently especially when you swipe over the links. I do not understand enough about how the swipe event is captured to do anything about it. I do not believe this will be a good experience for the user.

Another issue is that tiny carousel doesn’t expose public methods for its navigation. I would have to do some ‘hacking’ to make it react to the swipe event.

When I showed this example to my coworker, she wondered whether the swipe plugin is really a good use here. If it’s implemented this way, it would mean no matter how much you swipe, you always get the same amount of scrolling back and forth leveraging tiny carousel.

Great thought! A light bulb popped in my head. Why am I trying so hard to fake the scrolling by using javascript? I should rely on the browser’s native scrolling. Why didn’t I think of overflow: auto?

My idea is to use the multiple layers and the overflow css property to show the horizontal scrolling. Javascript is added on the previous and next links to scroll a certain amount. In my example, the amount is the outerWidth of the content area.

A few things

  • Originally I was ONLY going to do this on mobile and continue to use tiny carousel on desktop. The worry was about how ugly the horizontal scrollbar is with overflow: auto.
    scrollBar
    But I resolved that issue with some CSS :) To pull off this trick, you need three layers. We will call them container, viewport, content.

    • container layer must have overflow: hidden and position: relative
    • container layer must have overflow: auto and position: absolute
    • content is the list of links. it should have very long width. for me, I created a list with the style:
      ul {
      list-style: none;
      white-space: nowrap;
      }
      ul li {
      display: inline-block;
      }
      

      Then your list will be a horizontal no wrap line that will be as wide as necessary. Add a large bottom padding to this list e.g. padding-bottom: 50px. This will hide the scrollar.

    • This pen contains the full example
  • A little javascript is leveraged to
    • continue the support on previous and next links as in the tiny carousel plugin
    • allow scrolling to an selected item in the html source on page load
    • I used jQuery in my code but you can easily do this without the help of jQuery:
      (function($){
          var opts = {
              viewport: '.viewport'
              ,selected: '.dateCarouselSelected'
              ,prev: '.prev'
              ,next: '.next'
              ,defaultScrollDistance: 200
              ,scrollAnimationDuration: 500 // ms
          };
      
          $.fn.carouselSwipeable = function(options) {
              var options = $.extend({}, opts, options);
              this.each(function(){ new CarouselSwipeable($(this), options); });
              return this;
          };
      
          function CarouselSwipeable(root, options){
              /* init date carousel */
              var wrapper = root.find(options.viewport);
              var wrapperWidth = $(wrapper).outerWidth();
      
              var selectedElement = root.find(options.selected);
      
              if(selectedElement && selectedElement.length === 1) {
                  var parentLi = selectedElement.closest('li');
                  var childPos = parentLi.offset(); // li
                  var parentPos = parentLi.parent().offset(); // ul
                  var childOffset = {
                      top: childPos.top - parentPos.top,
                      left: childPos.left - parentPos.left
                  };
      
                  var startPos = childOffset.left;
      
                  scroll('right', wrapper, startPos);
              }
      
              root.find(options.prev).on('click', function(e) {
                  e.preventDefault();
                  e.stopPropagation();
                  scroll('left', wrapper, wrapperWidth);
              });
              root.find(options.next).on('click', function(e) {
                  e.preventDefault();
                  e.stopPropagation();
                  scroll('right', wrapper, wrapperWidth);
      
              });
      
              function scroll(direction, innerWrapper, distance) {
                  if(distance === undefined) {
                      distance = options.defaultScrollDistance;
                  }
                  var leftPos = $(innerWrapper).scrollLeft();
      
                  if('left' === direction) {
                      leftPos = leftPos - distance;
                  } else {
                      leftPos = leftPos + distance;
                  }
                  $(innerWrapper).animate({scrollLeft: leftPos}, options.scrollAnimationDuration);
              }
          }
      })(jQuery);
      
      $('#dateCarousel').carouselSwipeable();
      

      Obviously, this is not written in a modular format. It really should be done better and made into a plugin :) And I might do that.

    >>>My Awesome Carousel<<<

    What I like about my carousel

    • It is responsive by nature
    • It defers swiping back to the browser’s default scrolling ability
    • It works on any touch device as well as desktop. The scrolling is just hidden on the desktop
    • With tiny carousel, you have a moment of “style flash” when the carousel is generated by javascript. Mine just relies on the default css style of the layers so there is no “style flash”
    • It’s not a traditional image slider but it’s perfect for our unique usage. We just want to scroll some long text horizontally.
    • I got out of the javascript web and thought outside of the box for a simpler solution. YAY!

    Improvement I’d like to make

    Currently the javascript still uses the jQuery animation for the previous & next scrolling effect. I’d like to use CSS animation instead. But I’m not sure how to do that yet…. saw an example here but it’s not exactly applicable to my situation.

Making Semantic Elements Behave Like a Table

CSS has properties to make any element you wish behave as if it was a table element. You’ll need to structure them essentially as you would a table, and it will be subject to the same source-order-dependency as a table, but you can do it. I’m not crapping on it either, it’s genuinely useful sometimes. If that layout style solves a problem and has no negative order implications, use it.

Don’t use inline styles, but just for understanding here’s how that would go:

<section style="display: table;">
  <header style="display: table-row;">
    <div style="display: table-cell;"></div>
    <div style="display: table-cell;"></div>
    <div style="display: table-cell;"></div>
  </header>
  <div style="display: table-row;">
    <div style="display: table-cell;"></div>
    <div style="display: table-cell;"></div>
    <div style="display: table-cell;"></div>
  </div>
</section>

A handy trick here is that you don’t even need the table-row element in there if you don’t want. A bunch of display: table-cell; elements that are children of a display: table; element will behave like they are all in one row.

You always alter the display property of the element to get the table-style behavior. Here’s the values:

display: table                /* <table>     */
display: table-cell           /* <td>        */
display: table-row            /* <tr>        */
display: table-column         /* <col>       */
display: table-column-group   /* <colgroup>  */
display: table-footer-group   /* <tfoot>     */
display: table-header-group   /* <thead>     */

Notice there is no <th> alternative. That is for semantic value only. It otherwise behaves just like a <td>, so, no need to replicate it in CSS.

There is also display: inline-table; which is pretty interesting. Remember we talked about how weird table elements widths are above. They are only as wide as they need to be, yet break onto new lines. It’s almost like they are inline-block elements which happen to break. This makes them literally like inline-block elements, without the breaking.

Copied from css-tricks

再看《滚滚红尘》

第一次看《滚滚红尘》时很小,还不懂什么叫少女情怀。三十出头再看心中别是滋味。在美国这么多年,但少女时期的初恋还是用中文描述的。那时写了三年的可以叫作情书日记吧。每天对着比自己大十四岁的初恋情人写一篇日记。做梦的年代。叫做梦的年代因为那时随手写就是散文。万物一切都有感情。天天都有时间静下心来,倾听自己的心声。再看《滚滚红尘》唤醒了我的少女情怀。这种影片是不是美在它能捕捉并保存这种情怀呢?无论时代或历史都无法改变有诗的心灵。一种浪漫,一种幻想,一种美好,藏在心底无法抹杀。很多音乐都可以唤醒那种感觉。那种感觉能让时间停留。当我处在那种心境中,我觉得我从未长大。虽然我已经许多年没有碰琼瑶的书了,也不再看以前的日记。可有过的情怀没有丢弃。看琼瑶的时候,家长们都警告看这种书会中毒。看来这就是我的毒,一生的毒。

Samsung’s latest stupidly massive smartphone: The Galaxy Mega

Originally posted on VentureBeat:

galaxy-mega

In terms of smartphones, Samsung seems to have one main imperative these days: Make them larger.

Like the Galaxy Note II, Samsung’s new Galaxy Mega is proof that Samsung is intent on creating smartphones at every conceivable size — even if those sizes are hugely impractical for mobile devices.

The Galaxy Mega comes in two forms — one with a 6.3-inch screen, the other with a 5.8-inch screen. Both devices are larger than the 5.5-inch Galaxy Note II, which is either good or bad depending on which side of the “bigger is better” debate you fall on.

Sean Ludwig of VentureBeat shows how big the 6.1-inch Huawei smartphone is.

Make it stop.

Spec-wise, the two Mega versions offer slightly different numbers. While the 6.3-inch model comes with a HD display, 1.7 GHz processor and LTE/HSPA radios, the smaller version offers a reduced screen resolution and less powerful processor. Little of that really matters, however, because these are devices that Samsung is selling on screen…

View original 121 more words

Twitter API 1.1 php get tweets script

I’ve been using a nice caching php script for getting my latest tweets. Recently twitter completely stopped support for API 1 and everyone must use API 1.1. API 1.1 requires authentication and therefore making it more complicated to use the original script.

I’ve modified the script with the help of the codebird library to do what it used to do.

Set up authentication for your application

  • To use the new getTweets.php, you must go to your twitter dev account and create a new application.
  • Fill in all of the required information.
  • Once created, you will be given the Consumer key and Consumer secret.
  • Click on the Create my access token button, you will be given the Access token and Access token secret.
  • You will need the four pieces of information to use the script.

Set up the script on your server

  • Download my github fork
  • Open the src/getTweets.php file
  • Fill in the CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET
  • Update the time between cache in the Time between cache variable if you wish. Default is 5 min.

To use the script

Once done, upload all files in the src folder to a folder on your server. You may get the latest tweets for the user via ajax such as:

// get latest tweet
$.ajax({
	url: "{PATH TO}/getTweets.php",
	type: "GET",
	data: { count : '2', user : 'dodozhang21' },
	success: function(data, textStatus, jqXHR){
		var html = '<ul>';
		for(var x in data) {
			var tweet = data[x];
			//console.log(tweet);
			html += '<li>';
			html += tweet.text;
			html += '<span>';
			html += tweet.created_at;
			html += '</span></li>';
		}
		html += '</ul>';
		$('#latestTweet').removeClass('loading');
		$('#latestTweet').html(html);
	},
	error: function (jqXHR, textStatus, errorThrown){
		//console.log('Error ' + jqXHR);
	}
});

Additional Information