2011年12月28日 星期三

Xen VPS Hosting

Deploy your Linode cloud servers worldwide, including our newest facility in Tokyo, Japan.

url : http://www.linode.com/

結婚習俗 - 結婚紅包行情

結婚紅包行情價:
 
600元---一般訂婚習俗和結婚習俗,紅包是由600元開始起跳,但那是指非常不熟悉的禮金數。
1200元---就是一般辦公室朋友的[價位] ,三分熟交情;只包紅包 祝賀,不出席喜宴。
1600元---是可以一起吃飯逛街的朋友,另外;如果你還可以拿到 一盒新娘的喜餅,那就不好再少於這個數字。
2000~2600元---可以交換一些心事,倒些垃圾的朋友,平日相交已有些推心置腹的感覺。
3600元---親密的姐姐淘,兄弟情,如熟透的親密感。
6000元---親姐妹、親兄弟血濃於水,不容取代的手足情深,自然就從6000元以上起跳。
  紅包的由來:
  紅包袋---亦稱為紅封包,是將金錢放置紅色封套內做成的一種小禮物。訂婚結婚包紅包是中國傳統民俗,在各種喜慶場合如過年、小孩滿月及各式送金錢作禮物時都會使用。紅色在中國文化當中象徵著喜慶,紅包當中一般會放入有吉祥數字的金錢,例如有8字或以雙數結尾的數目,而且結婚紅包賀詞寫法也是有重要的象徵意義。
   
   
  小叮嚀
 
如果女方是訂婚收禮金,而男方是結婚收禮金;或是訂結婚一起舉辦,男女雙方都在現場擺禮桌收禮金,所以;要包給她,最好跟她說一聲,如果男方那邊收走了,至少她看過禮金簿時,知道你有包紅包給她,日後;你結婚時她才有包紅包的參考值。
紅包討吉利,新郎倌可不要忘了準備紅包給幫忙的親友;諸如:前來開新郎車門的舅爺,及六名隨新郎前去迎娶新娘的親友,捧洗臉水的女方親友、媒婆禮等。金額多為600、1200及2000元等。
   
  紅包賀詞寫法
 
紅包上可寫上結婚賀詞,但紅包左下方寫上自己的名字(例如:xxx賀)
百年琴瑟 花好月圓 天緣巧合 金石同心 白頭偕老 情聯碧合 宜爾室家 花開並蒂 情投意合 天作之合 相親相愛 永浴愛河 緣訂三生......更多結婚賀詞
   
 
  起源 | 訂婚流程 | 迎娶流程 | 歸寧流程 | 南北差異 | 結婚禁忌 | 結婚紅包行情  


本網站部分相關資料於各大雜誌及網站收集而來,單純為了提供網友方便,不作他用,若原作者不同意引用,請與我們聯絡。

reference : http://www.myloving.com.tw/WedInfo_MoresPacket.asp

結婚紅包行情

最近好日子很多,因此收到不少朋友寄來請帖為此我希望得知包多少才得體,同時(1)顧及情感程度(2)顧及對方是否好回禮,台灣習俗:回禮不能比當初收到禮金少(至少等價),因此包得好是祝福包不好是負擔,可能是自己的負擔也是對方的負擔。



此圖來自: veryWed討論區







這是PTT網友peegoo7 (瓜瓜瓜)整理出來的價目表




結論(參考朋友的看法):
(1)有分 人到 和 禮到 兩種金額,由於結婚禮金是要補助新人的做法,因此不難看出,扣除每桌費用後多少補貼的做法,好比一桌一萬元,每桌抓5-7個紅包(假設洽好是5對10人),包2000是剛好餐費,則2200到2600甚至更多是較佳的包法,這樣的算法因人、地而異


(2)人到最少得包1600,如果帶的人數太多要酌量多加一點。


(3)由於只用雙數,不用單數!不用「四」和「八」(八有「別」之意) !因此能用的數字只有600、1000、1200、1600、2000、2200、2600、3600、6000、6600等組合。


(4)你包3600給別人,碰上台灣習俗:回禮不能比當初收到禮金少(至少等價),雖可回同樣的禮數,但是由於下個數字是6000,會有你要別人包6000的味道在。




依照景氣不同會有不同的包法,法無定法可由自己的狀態、友好度等做為考量,透過網路資料的整理可提供大家一個參考的方案。

reference : http://im88.tw/?p=1243

2011年12月19日 星期一

Gridow - Presenting Yourself in the simplest way

Make your own Gridow video,
All you need is a laptop,
with a camera and internet access.

Take a BITE out of Bugs and Redundant Labor

In a time when more and more of the web is becoming streamlined, the process of filing bugs for websites remains tedious and manual. Find an issue. Switch to your bug system window. Fill out boilerplate descriptions of the problem. Switch back to the browser, take a screenshot, attach it to the issue. Type some more descriptions. The whole process is one of context switching; from the tools used to file the bug, to gather information about it, to highlight problematic areas, most of your focus as the tester is pulled away from the very application you’re trying to test.

The Browser Integrated Testing Environment, or BITE, is an open source Chrome Extension which aims to fix the manual web testing experience. To use the extension, it must be linked to a server providing information about bugs and tests in your system. BITE then provides the ability to file bugs from the context of a website, using relevant templates.



When filing a bug, BITE automatically grabs screenshots, links, and problematic UI elements and attaches them to the bug. This gives developers charged with investigating and/or fixing the bug a wealth of information to help them determine root causes and factors in the behavior.



When it comes to reproducing a bug, testers will often labor to remember and accurately record the exact steps taken. With BITE, however, every action the tester takes on the page is recorded in JavaScript, and can be played back later. This enables engineers to quickly determine if the steps of a bug repro in a specific environment, or whether a code change has resolved the issue.

Also included in BITE is a Record/Playback console to automate user actions in a manual test. Like the BITE recording experience, the RPF console will automatically author javascript that can be used to replay your actions at a later date. And BITE’s record and playback mechanism is fault tolerant; UI automation tests will fail from time to time, and when they do, it tends to be for test issues, rather than product issues. To that end, when a BITE playback fails, the tester can fix their recording in real-time, just by repeating the action on the page. There’s no need to touch code, or report a failing test; if your script can’t find a button to click on, just click on it again, and the script will be fixed! For those times when you do have to touch the code, we’ve used the Ace (http://ace.ajax.org/) as an inline editor, so you can make changes to your javascript in real-time.

Check out the BITE project page at http://code.google.com/p/bite-project. Feedback is welcome at bite-feedback@google.com. Posted by Joe Allan Muharsky from the Web Testing Technologies Team (Jason Stredwick, Julie Ralph, Po Hu and Richard Bustamante are the members of the team that delivered the product).

reference : http://googletesting.blogspot.com/2011/10/take-bite-out-of-bugs-and-redundant.html

2011年12月14日 星期三

What is it? Raphaël is a small JavaScript library that should simplify your work with vector graphics on the web.

What is it?
Raphaël is a small JavaScript library that should simplify your work with vector graphics on the web. If you want to create your own specific chart or image crop and rotate widget, for example, you can achieve it simply and easily with this library.
Raphaël ['ræfeɪəl] uses the SVG W3C Recommendation and VML as a base for creating graphics. This means every graphical object you create is also a DOM object, so you can attach JavaScript event handlers or modify them later. Raphaël’s goal is to provide an adapter that will make drawing vector art compatible cross-browser and easy.
Raphaël currently supports Firefox 3.0+, Safari 3.0+, Chrome 5.0+, Opera 9.5+ and Internet Explorer 6.0+.
How to use it?
Download and include raphael.js into your HTML page, then use it as simple as:
// Creates canvas 320 × 200 at 10, 50
var paper = Raphael(10, 50, 320, 200);

// Creates circle at x = 50, y = 40, with radius 10
var circle = paper.circle(50, 40, 10);
// Sets the fill attribute of the circle to red (#f00)
circle.attr("fill", "#f00");

// Sets the stroke attribute of the circle to white
circle.attr("stroke", "#fff");

reference : http://raphaeljs.com/

2011年11月29日 星期二

Mar30Speeding up Mootools with createDocumentFragment()

A couple of days ago David Walsh posted a blog entry where he recommended a video from Google about JavaScript. I’ve found this very interesting and I have done some research about how to implement this very easy to Mootools. There are a lot of do’s and dont’s but what is the best practice for us as a Mootools developer? How to avoid the basic Mootools solutions and speed up your plugins? Well, I’ll post my neat workarounds to get your speed up.

I’ll start with modifying the DOM by injecting elements with the Mootools function inject(). Injecting elements to the DOM is very common with Mootools but it will make it slow down. To speed up you’ll have to do as little DOM modification as possible.

For example you load a JSON file and add elements depending on the content of the request. In this example we don’t avoid the Mootools each() function. We focus on the point that we don’t call the inject() function every time. This is my solution.Add the following lines to you general JavaScript file to implement a new function. I’ll recommend this if you

view plaincopy to clipboardprint?
window.addEvent('domready', function() {
Element.implement({
docFragment: function(){
return document.createDocumentFragment();
}
});
});
We’re going to add options to a select element, based on the JSON request.

view plaincopy to clipboardprint?
var fragment = Element.docFragment();

json.each(function(o){
var option = new Element('option',{'value': o.value, 'html': o.html});
fragment.appendChild(option); //No reflow
});

$('select').appendChild(fragment); //Reflow!
Results
I’ve done some testing and I think it helped me pretty good to speed up my scripts. I’ve modified my cvLinkSelect class and did some testing with it. Here are the results. Not very impressive at this point but you can see it will help the performance.



The test handles a 12 lined JSON request and for each record an option element will be added to the DOM. Not a very big effort for a browser, but you’ll see that there is some difference on the most common browsers and it’s no surprise that IE is the slowest of them all. If you scale this up it has to be a large difference and I’m confident with that.

Read more about createDocumentFragment on Mozilla Developer Center.

reference : http://youngdutchdesign.com/speeding-up-mootools-with-createdocumentfragment

2011年11月19日 星期六

Flipping Out

Flickr is somewhat unique in that it uses a code repository with no branches; everything is checked into head, and head is pushed to production several times a day. This works well for bug fixes that we want to go out immediately, but presents a problem when we’re working on a new feature that takes several months to complete. How do we solve that problem? With flags and flippers!

Feature Flags


Flags allow us to restrict features to certain environments, while still using the same code base on all servers. In our code, we’ll write something like this:

if ($cfg.enable_unicorn_polo) {
// do something new and amazing here.
}
else {
// do the current boring stuff.
}
We can then set the value of $cfg.enable_unicorn_polo on each environment (false for production, true for dev, etc.). This has the additional benefit of making new feature launches extremely easy: Instead of having to copy a bunch of new code over to the production servers, we simply change a single false to true, which enables the code that has already been on the servers for months.

Feature Flippers


Flags allows us to enable features on a per environment basis, but what if we wanted to be more granular and enable features on a per user basis? For that we use feature flippers. These allow us to turn on features that we are actively developing without being affected by the changes other developers are making. It also lets us turn individual features on and off for testing.

Here is what the Feature Flip page looks like:



Continuously Integrating
Feature flags and flippers mean we don’t have to do merges, and that all code (no matter how far it is from being released) is integrated as soon as it is committed. Deploys become smaller and more frequent; this leads to bugs that are easier to fix, since we can catch them earlier and the amount of changed code is minimized.

This style of development isn’t all rainbows and sunshine. We have to restrict it to the development team because occasionally things go horribly wrong; it’s easy to imagine code that’s in development going awry and corrupting all your data. Also, after launching a feature, we have to go back in the code base and remove the old version (maintaining separate versions of all features on Flickr would be a nightmare). But overall, we find it helps us develop new features faster and with fewer bugs.

reference : http://code.flickr.com/blog/2009/12/02/flipping-out/

Quantum of Deployment

Deployinator is now Open Source!
Grab it on github: https://github.com/etsy/deployinator

We deploy a lot of code. Deployinator is our creation to make that as easy and painless as possible. Deployinator is a one button web-based deployment app. Hit that button and code goes to our webservers and is serving requests in almost no time. Using Deployinator we’ve brought a typical web push from 3 developers, 1 operations engineer, everyone else on standby and over an hour (when things went smoothly) down to 1 person and under 2 minutes.

At Etsy, we’re doing what’s come to be called Continuous Deployment. However, what we’ve learned is that having a tool like Deployinator is useful for more than just enabling that. This post is about those benefits – for anyone deploying web code.

Why

Our job as engineers (and ops, dev-ops, QA, support, everyone in the company actually) is to enable the business goals. We strongly feel that in order to do that you must have the ability to deploy code quickly and safely. Even if the business goals are to deploy strongly QA’d code once a month at 3am (it’s not for us, we push all the time), having a reliable and easy deployment should be non-negotiable.

It’s a metric I’ve come to call the “quantum of deployment”: what’s the smallest number of steps, with the smallest number of people and the smallest amount of ceremony required to get new code running on your servers? This isn’t a trivial question. Even if you’re on a slow release cycle, and have a push engineer, what happens if there’s an emergency push needed? Does it go through your normal process, or is there a fast-lane? Do your fast-lane deployments get logged? Are they measured for speed? Is everyone aware that it happened the way they would for a normal deployment, or is it your dirty little secret?

It’s not hard to get started. If you currently have a bunch of shell scripts that move everything in place, wrap those up with a single shell script. The most important thing is that it’s ONE easy step. This might require changing your process. Try to remove or replace special cases. The less thought it takes to deploy, the more you can focus on getting stuff done.

Once deploying is No Big Deal, a lot of things can change. Features can go out a piece at a time instead of one all-or-nothing push. Your app configuration options can be in code – and changed quickly. Your hair can grow back. Puppies will lick your face!

What

Custom software? There’s a lot of choice out there, and we generally try to not reinvent the wheel whenever possible (and this wheel has been invented again and again). After comparing our requirements with the available software, we decided to roll our own. Here’s what we were looking for:

Web based
Logged (When, What and Who)
Adaptable to our network
Run from a central location
Announced in our IRC and email
Transparent in regards to its actions
Integrated with our graphing/monitoring tools
A lot of our requirements are inspired by the way Flickr deploys, as documented in Building Scalable Websites (Written by Friend of Etsy, Cal Henderson).

For anyone deploying code (engineers, designers… anyone really), it’s an easy process. Once your code is ready to go, you go to Deployinator and push the button to get it on QA. From there it visits Princess (see the sidebar). Then, when it’s ready to go live, you hit the “Prod” button and soon your code is live, and everyone in IRC knows who pushed what code, complete with a link to the diff. For anyone not on IRC, there’s the email that everyone gets with the same information.

What it looks like
This is the main Deployinator screen. Here is how we deploy the “web stack”.



Sidebar: What the heck is a “Princess”?

Princess is our staging environment. So why didn’t we just call it “staging”? Partly, that’s just how we roll. We used to have an environment called “Staging” that was the last stop before code went live to everyone. However, it was not ideally set up; the first time your code would interact with actual production hardware was when you deployed. Princess uses production data stores, our production network and production hardware. In order to make a clean mental break from the old way, one of our rad engineers, Eric Fixler, came up with “Princess”.

Here’s our IRC bot telling everyone that something went out. It also includes a link to the commits that went live.



How

When we first brought Deployinator online, it was just a web frontend to the shell scripts that moved everything in the right place. What we gained by putting a screen in front of it was the ability to iterate the backend without changing the experience for people deploying. Deployinator currently uses svn to update the code, then rsync to move it between environments.

Another important part of Deployinator is that the environments are a one way street. Code going from Princess to production is unaffected by any commits that have happened since getting on princess. This creates something of a “mantrap“, so that we know exactly what we’re deploying. No surprises!

Deployinator isn’t used just for our web stack either. With the simple architecture we’ve built, we can add all kinds of stuff to it easily. It’s currently used for many different things such as the API, Lists service, internal admin-only tools and others. Having a single deployment process has removed a lot of complexity.

When

This isn’t a post about continuous deployment. Having a very simple deployment procedure is something you should do even if the thought of deploying your code 20 times a day scares you. Deployment can be a contentious subject with many stakeholders. Getting it simple and repeatable allows everyone to share a common vocabulary.

For the nerds…

Transporting the bits and bytes
Here’s a rundown of some of the interesting parts of how Deployinator actually moves bits around. As mentioned above, this has changed and will change again. We analyze our entire process and have some low-hanging performance fruit to pick. As of today, an API push takes about 18 seconds, a Princess push takes about the same, and a production web push is 70-150 seconds. Here are the steps that a web push goes through:

From the repo of truth

We’re deploying directly from trunk (that’s a whole other post!). So the first step of deploying is to update the code on the deploy host.

Builda what now?

After the code is updated, we run “builda”, an app we wrote to take our assets and bundle them up with lots of magic. We use a combination of javascript async loading, Google’s closure and versioned directories to make things like css, javascript and sprites as fast as possible.

Rsync

At this point, we have a bunch of directories on our deploy host that represent our web tree. We then rsync to a staging area on each web box.

Fanout

At some number of boxes, rsyncing back to a single push host stops working. We’re employing a strategy called fan out. We rsync in chunks of 10 hosts at a time. This is one area where a lot of speed ups will be happening soon.

First they came for our assets…

Pop quiz, hotshot: Someone visits the site during a deployment and box 1 (the one they randomly get) has the new code. The html they’re returned refers to a new image. When they request that image, they end up on box 451.. which doesn’t have that asset yet. What do you do? WHAT DO YOU DO?

We’ve solved this with two steps. The first (mentioned above) is versioned asset directories. The next is to get those assets on ALL hosts before ANY host has the new code referring to it.

Graceful

We’re using APC user caching, and expect it to have fresh data each deployment. Things like some application settings, database fields and routes are all cached for super fast lookups. However, if someone changes something in some code going out, we need to make sure that it’s fresh. We’re currently issuing a graceful restart to our apaches on each deployment.

Deployinator itself
One of the design goals of Deployinator has been to be as simple as possible. It’s a sinatra web app, but could really be written in anything. The script that does the svn updating (and checking out for new stacks) is in PHP and some of the straight-up simplest code possible.

The commands that Deployinator runs through for each different stack are listed in ruby methods, and are mostly strings (with servers and such interpolated). It’s easy for anyone to come in and change how something works. Simple, understandable software that gets the job done.

The one fancy bit of Deployinator is the streaming rack middleware that powers the live updating code window:



Database DDLs aren’t code
An awesome feature of Capistrano is the ability to run schema migrations as part of your deployment. At a certain scale, however, database changes become more time consuming and dangerous. All of our schema changes go through a stringent process with several checks in place. However, not all schema is defined in the database. Whenever we have schema that’s defined in code, or inside the data itself, it’s just a normal code push.

Conclusion

Our deployment process is a very important part of how we work at Etsy. We treat it just like our web code, databases or other “serious” things. Deployinator has helped us to get more features out faster with less defects and drama. As we triple our engineering team in 2010 (we’re hiring!), tools like this are what make it possible for us to change the world.

reference : http://codeascraft.etsy.com/2010/05/20/quantum-of-deployment/

2011年11月17日 星期四

Mysql忘記root密碼

1.先停掉mysql

# /etc/init.d/mysql stop

2.以–skip-grant-table& 的參數啟動mysql
/usr/bin/mysqld_safe --skip-grant-table&

3. 更改root 密碼

# mysql mysql
mysql> UPDATE user SET password=password('123456') WHERE user='root';
mysql> exit

4.停掉mysql再重跑

# /etc/init.d/mysql stop
# mysql -u root -p

reference : http://tw.myblog.yahoo.com/cherry-liang/article?mid=579&prev=633&next=-2&page=1&sc=1

2011年11月14日 星期一

You could use the DOMDocument class to reformat your xml


$dom = new DOMDocument('1.0');
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($simpleXml->asXML());
echo $dom->saveXML();

2011年10月28日 星期五

PHP : XML Create-Add-Edit-Modify using DOM , SimpleXML , XPath

Over the last few working days, I spent a quite a bit of time playing around with XML. While searching through the net, I found few comprehensive PHP XML guides. There never was a ’1 stop all operations’ guide for learning XML.
As such I decided to club together examples of all kinds of operations I ever did on XML in a single post. I hope it benefits others out there who wish to learn more about XML manipulation.
Note : Since the post got quite large, I decided to only use the Tree Map style parsers – DOM & Simple XML.




Operations Performed:
(1) Create XML OR Array to XML Conversion OR CDATA Element Eg
(2) Edit XML – Edit/Modify Element Data (accessed serially)
(3) Edit XML – Edit specific Elements (accessed conditionally)
(4) Edit XML – Element Addition (to queue end)
(5) Edit XML – Element Addition (to queue start)
(6) Edit XML – Element Addition (before a specific node)
(7) Delete Elements (accessed serially)
(8) Delete Elements (accessed conditionally)
(9) Rearrange / Reorder Elements
(10) Display Required data in XML Form itself OR Remove all children nodes save one OR Copy/Clone Node Eg OR Compare/Search non numeric data (like date or time) to get result.

library.xml will be used in all operations.
ps : I have added the indention & spaces outside the tags in the below xml for a presentable xml form.
Remove them before saving your xml file else most of the usual XML functions wont work in the desired manner.

01

02

03

04
<![CDATA[The Fountainhead]]>
05
Ayn Rand
06
300
07

08

09
<![CDATA[The Lord of the Rings]]>
10
J.R.R.Tolkein
11
500
12

13

14
<![CDATA[The Dark Tower]]>
15
Stephen King
16
200
17

18


#######################################
// (1) Create XML OR
Array to XML Conversion OR
CDATA Element Eg
#######################################

// (i) SimpleXML :

01
// Cant create CDATA element for title in SimpleXML.
02
function fnSimpleXMLCreate()
03
{
04
$arr = array(array('isbn'=>'1001', 'pubdate'=>'1943-01-01', 'title'=>'The Fountainhead',
05
'author'=>'Ayn Rand', 'price'=>'300'),
06
array('isbn'=>'1002', 'pubdate'=>'1954-01-01',
07
'title'=>'The Lord of the Rings', 'author'=>'J.R.R.Tolkein',
08
'price'=>'500'),
09
array('isbn'=>'1003', 'pubdate'=>'1982-01-01', 'title'=>'The Dark Tower',
10
'author'=>'Stephen King', 'price'=>'200'));
11

12
$library = new SimpleXMLElement('');
13

14
for($i=0;$i<3;$i++)
15
{
16
$book = $library->addChild('book');
17
$book->addAttribute('isbn', $arr[$i]['isbn']);
18
$book->addAttribute('pubdate', $arr[$i]['pubdate']);
19
$book->addChild('title', $arr[$i]['title']); //cant create CDATA in SimpleXML.
20
$book->addChild('author', $arr[$i]['author']);
21
$book->addChild('price', $arr[$i]['price']);
22
}
23

24
$library->asXML('library.xml');
25
}

// (ii) DOM :

01
function fnDomCreate()
02
{
03
$arr = array(array('isbn'=>'1001', 'pubdate'=>'1943-01-01', 'title'=>'The Fountainhead',
04
'author'=>'Ayn Rand', 'price'=>'300'),
05
array('isbn'=>'1002', 'pubdate'=>'1954-01-01',
06
'title'=>'The Lord of the Rings', 'author'=>'J.R.R.Tolkein',
07
'price'=>'500'),
08
array('isbn'=>'1003', 'pubdate'=>'1982-01-01', 'title'=>'The Dark Tower',
09
'author'=>'Stephen King', 'price'=>'200'));
10

11
$dom = new DOMDocument();
12
$library = $dom->createElement('library');
13
$dom->appendChild($library);
14

15
for($i=0;$i<3;$i++)
16
{
17
$book = $dom->createElement('book');
18
$book->setAttribute('isbn',$arr[$i]['isbn']);
19
$book->setAttribute('pubdate',$arr[$i]['pubdate']);
20

21
//$prop = $dom->createElement('title', $arr[$i]['title']);
22
$prop = $dom->createElement('title');
23
$text = $dom->createCDATASection($arr[$i]['title']);
24
$prop->appendChild($text);
25
$book->appendChild($prop);
26

27
$prop = $dom->createElement('author', $arr[$i]['author']);
28
$book->appendChild($prop);
29
$prop = $dom->createElement('price', $arr[$i]['price']);
30
$book->appendChild($prop);
31
$library->appendChild($book);
32
}
33
//header("Content-type: text/xml");
34
$dom->save('library.xml');
35
}

#######################################
// (2) Edit XML – Edit/Modify Element Data (accessed serially)
#######################################

// (i) SimpleXML :

1
// Edit Last Book Title
2
function fnSimpleXMLEditElementSeq()
3
{
4
$library = new SimpleXMLElement('library.xml',null,true);
5
$num = count($library);
6
$library->book[$num-1]->title .= ' - The Gunslinger';
7
header("Content-type: text/xml");
8
echo $library->asXML();
9
}

// (ii) DOM :

01
//Edit Last Book Title
02
function fnDOMEditElementSeq()
03
{
04
$dom = new DOMDocument();
05
$dom->load('library.xml');
06
$library = $dom->documentElement;
07
$cnt = $library->childNodes->length;
08

09
$library->childNodes->item($cnt-1)->getElementsByTagName('title')->item(0)->nodeValue .= ' Series';
10
// 2nd way #$library->getElementsByTagName('book')->item($cnt-1)->getElementsByTagName('title')->item(0)->nodeValue .= ' Series';
11

12
//3rd Way
13
//$library->childNodes->item($cnt-1)->childNodes->item(0)->nodeValue .= ' Series';
14
header("Content-type: text/xml");
15
echo $dom->saveXML();
16
}

#######################################
// (3) Edit XML – Edit specific Elements (accessed conditionally)
#######################################

// (i) SimpleXML :

1
//Edit Title of book with author J.R.R.Tolkein
2
function fnSimpleXMLEditElementCond()
3
{
4
$library = new SimpleXMLElement('library.xml',null,true);
5
$book = $library->xpath('/library/book[author="J.R.R.Tolkein"]');
6
$book[0]->title .= ' Series';
7
header("Content-type: text/xml");
8
echo $library->asXML();
9
}

// (ii) DOM (with XPath):

01
//Edit Title of book with author J.R.R.Tolkein
02
function fnDOMEditElementCond()
03
{
04
$dom = new DOMDocument();
05
$dom->load('library.xml');
06
$library = $dom->documentElement;
07
$xpath = new DOMXPath($dom);
08
$result = $xpath->query('/library/book[author="J.R.R.Tolkein"]/title');
09
$result->item(0)->nodeValue .= ' Series';
10
// This will remove the CDATA property of the element.
11
//To retain it, delete this element (see delete eg) & recreate it with CDATA (see create xml eg).
12

13
//2nd Way
14
//$result = $xpath->query('/library/book[author="J.R.R.Tolkein"]');
15
// $result->item(0)->getElementsByTagName('title')->item(0)->nodeValue .= ' Series';
16
header("Content-type: text/xml");
17
echo $dom->saveXML();
18

19
}

#######################################
// (4) Edit XML – Element Addition (to queue end)
#######################################

// (i) SimpleXML :

01
//Add another Book to the end
02
function fnSimpleXMLAddElement2End()
03
{
04
$library = new SimpleXMLElement('library.xml',null,true);
05
$book = $library->addChild('book');
06
$book->addAttribute('isbn', '1004');
07
$book->addAttribute('pubdate', '1960-07-11');
08
$book->addChild('title', "To Kill a Mockingbird");
09
$book->addChild('author', "Harper Lee");
10
$book->addChild('price', "100");
11
header("Content-type: text/xml");
12
echo $library->asXML();
13
}

// (ii) DOM :

01
//Add another Book to the end
02
function fnDOMAddElement2End()
03
{
04
$dom = new DOMDocument();
05
$dom->load('library.xml');
06
$library = $dom->documentElement;
07

08
$book = $dom->createElement('book');
09
$book->setAttribute('isbn','1000');
10
$book->setAttribute('pubdate','1960-07-11');
11

12
$prop = $dom->createElement('title');
13
$text = $dom->createTextNode('To Kill a Mockingbird');
14
$prop->appendChild($text);
15
$book->appendChild($prop);
16

17
$prop = $dom->createElement('author','Harper Lee');
18
$book->appendChild($prop);
19
$prop = $dom->createElement('price','100');
20
$book->appendChild($prop);
21

22
$library->appendChild($book);
23
header("Content-type: text/xml");
24
echo $dom->saveXML();
25
}

#######################################
//(5) Edit XML – Element Addition (to queue start)
#######################################

// (i) SimpleXML :

01
// Add a Book to List Start
02
// Insert Before Functionality not present in SimpleXML
03
// We can integrate DOM with SimpleXML to do it.
04
function fnSimpleXMLAddElement2Start()
05
{
06
$libSimple = new SimpleXMLElement('library.xml',null,true);
07
$libDom = dom_import_simplexml($libSimple);
08

09
$dom = new DOMDocument();
10
//returns a copy of the node to import
11
$libDom = $dom->importNode($libDom, true);
12
//associate it with the current document.
13
$dom->appendChild($libDom);
14

15
fnDOMAddElement2Start($dom); //see below DOM function
16
}

// (ii) DOM :

01
function fnDOMAddElement2Start($dom='')
02
{
03
if(!$dom)
04
{
05
$dom = new DOMDocument();
06
$dom->load('library.xml');
07
}
08
$library = $dom->documentElement;
09
#var_dump($library->childNodes->item(0)->parentNode->nodeName);
10
$book = $dom->createElement('book');
11
$book->setAttribute('isbn','1000');
12
$book->setAttribute('pubdate','1960-07-11');
13

14
$prop = $dom->createElement('title','To Kill a Mockingbird');
15
$book->appendChild($prop);
16
$prop = $dom->createElement('author','Harper Lee');
17
$book->appendChild($prop);
18
$prop = $dom->createElement('price','100');
19
$book->appendChild($prop);
20

21
$library->childNodes->item(0)->parentNode->insertBefore($book,$library->childNodes->item(0));
22
header("Content-type: text/xml");
23
echo $dom->saveXML();
24
}

#######################################
// (6) Edit XML – Element Addition (before a specific node)
#######################################

// (i) SimpleXML :

01
// Add a Book Before attribute isbn 1002
02
// Insert Before Functionality not present in SimpleXML
03
// We can integrate DOM with SimpleXML to do it.
04
function fnSimpleXMLAddElementCond()
05
{
06
$libSimple = new SimpleXMLElement('library.xml',null,true);
07
$libDom = dom_import_simplexml($libSimple);
08

09
$dom = new DOMDocument();
10
//returns a copy of the node to import
11
$libDom = $dom->importNode($libDom, true);
12
//associate it with the current document.
13
$dom->appendChild($libDom);
14

15
fnDOMAddElementCond($dom); //see below DOM eg.
16
}

// (ii) DOM :

01
// Add a Book Before isbn 1002
02
function fnDOMAddElementCond($dom='')
03
{
04
if(!$dom)
05
{
06
$dom = new DOMDocument();
07
$dom->load('library.xml');
08
}
09
$library = $dom->documentElement;
10

11
$book = $dom->createElement('book');
12
$book->setAttribute('isbn','1000');
13
$book->setAttribute('pubdate', '1960-07-11');
14

15
$prop = $dom->createElement('title','To Kill a Mockingbird');
16
$book->appendChild($prop);
17
$prop = $dom->createElement('author','Harper Lee');
18
$book->appendChild($prop);
19
$prop = $dom->createElement('price','100');
20
$book->appendChild($prop);
21

22
$xpath = new DOMXPath($dom);
23
$result = $xpath->query('/library/book[@isbn="1002"]');
24
$library->childNodes->item(0)->parentNode->insertBefore($book,$result->item(0));
25
header("Content-type: text/xml");
26
echo $dom->saveXML();
27
}

#######################################
// (7) Delete Elements (accessed serially)
#######################################

// (i) SimpleXML :

01
// Delete 2nd book
02
function fnSimpleXMLDeleteSeq()
03
{
04
$library = new SimpleXMLElement('library.xml',null,true);
05
//$library->book[1] = null; // this only empties content
06
unset($library->book[1]);
07
header("Content-type: text/xml");
08
echo $library->asXML();
09

10
}

// (ii) DOM :

01
// Delete 2nd Book
02
function fnDOMDeleteSeq()
03
{
04
$dom = new DOMDocument();
05
$dom->load('library.xml');
06
$library = $dom->documentElement;
07

08
$library->childNodes->item(0)->parentNode->removeChild($library->childNodes->item(1));
09

10
header("Content-type: text/xml");
11
echo $dom->saveXML();
12
}

#######################################
// (8) Delete Elements (accessed conditionally)
#######################################

// (i) SimpleXML :

01
// Delete a book with 20002
// Not possible to delete node found via XPath in SimpleXML. See below.
03
function fnSimpleXMLDeleteCond()
04
{
05
$library = new SimpleXMLElement('library.xml',null,true);
06
$book = $library->xpath('/library/book[price>"200" and price<"500"]');
07

08
//Problem here....not able to delete parent node using unset($book[0]);
09
// unset of parent node only works when accessing serially. eg : unset($library->book[0]);
10

11
//header("Content-type: text/xml");
12
//echo $library->asXML();
13

14
}

// (ii) DOM :

01
// Delete the book with 20002
function fnDOMDeleteCond()
03
{
04
$dom = new DOMDocument();
05
$dom->load('library.xml');
06
$library = $dom->documentElement;
07
$xpath = new DOMXPath($dom);
08
$result = $xpath->query('/library/book[price>"200" and price<"500"]');
09
$result->item(0)->parentNode->removeChild($result->item(0));
10
header("Content-type: text/xml");
11
echo $dom->saveXML();
12
}

#######################################
// (9) Rearrange / Reorder Elements
#######################################

// (i) SimpleXML :

01
// Exchange Position of 2nd book with 3rd : fnSimpleXMLRearrange(2,3);
02
// Due to absence of an inbuilt function (DOM has it), we have to make our own function in SimpleXML.
03
//Better to use DOM.
04
function fnSimpleXMLRearrange($num1,$num2)
05
{
06
$libSimple= new SimpleXMLElement('library.xml',null,true);
07
//$library->book[3] = $library->book[0]; // this doesnt work
08

09
$libDom = dom_import_simplexml($libSimple);
10

11
$dom = new DOMDocument();
12
//returns a copy of the node to import
13
$libDom = $dom->importNode($libDom, true);
14
//associate it with the current document.
15
$dom->appendChild($libDom);
16
fnDOMRearrange($num1,$num2,$dom); // see below DOM function
17
}

// (ii) DOM :

01
// Exchange Position of 2nd book with 3rd : fnDOMRearrange(2,3);
02
function fnDOMRearrange($num1,$num2,$dom=0)
03
{
04
if(!$dom)
05
{
06
$dom = new DOMDocument();
07
$dom->load('library.xml');
08
}
09
$dom = new DOMDocument();
10
$dom->load('library.xml');
11
$library = $dom->documentElement;
12

13
$book = $dom->createElement('book');
14
$book->setAttribute('isbn','1000');
15
$book->setAttribute('pubdate','1960-07-11');
16

17
$num1 = fnDOMConvIndex($num1);
18
$num2 = fnDOMConvIndex($num2);
19
$library->childNodes->item(0)->parentNode->insertBefore($library->childNodes->item($num2),$library->childNodes->item($num1));
20
header("Content-type: text/xml");
21
echo $dom->saveXML();
22
}
23
function fnDOMConvIndex($num)
24
{
25
$num = ($num==1)?$num:$num+1;//If its 1 then do nothing.
26
$num = ($num%2)?$num:$num+1; //Always odd index due to nature of DOM Element Index.
27
return $num;
28
}

#######################################
// (10) Display Required data in XML Form itself OR
Remove all children nodes save one OR
Copy/Clone Node Eg OR
Compare/Search non numeric data (like date or time) to get result.
#######################################

// (i) SimpleXML :

1
// Display Books published after 1980 in XML Form itself.
2
// No function to copy node directly in SimpleXML.
3
// Its simpler for this functionality to be implemented in DOM.
4
function fnSimpleXMLDisplayElementCond()
5
{
6
$library = new SimpleXMLElement('library.xml',null,true);
7
$book = $library->xpath('/library/book[translate(@pubdate,"-","")>translate("1980-01-01","-","")]');
8
// Manually create a new structure then add searched data to it (see create xml eg.)
9
}

// (ii) DOM :

01
// Display Books published after 1980 in XML Form itself.
02
function fnDOMDisplayElementCond()
03
{
04
$dom = new DOMDocument();
05
$dom->load('library.xml');
06
$library = $dom->documentElement;
07
$xpath = new DOMXPath($dom);
08

09
// Comparing non numeric standard data
10
$result = $xpath->query('/library/book[translate(@pubdate,"-","")>translate("1980-01-01","-","")]');
11
// For simpler search paramater use this :
12
//$result = $xpath->query('/library/book[author="J.R.R.Tolkein"]');
13

14
// Copy only node & its attributes not its contents.
15
$library = $library->cloneNode(false);
16
// Add the 1 element which is search result.
17
$library->appendChild($result->item(0));
18

19
header("Content-type: text/xml");
20
echo $dom->saveXML($library);
21
}
Lessons Learn’t :
SimpleXML is fantastic for those who will only briefly flirt with XML (or beginners) & perform simple operations on XML.
DOM is an absolute necessity for performing complex operations on XML data. Its learning curve is higher than SimpleXML off course but once you get the hang of it , you will know its very logical.
Use XPath for conditional access to data. For serial access (like last book) XPath is not needed (but u can use it) since I can use normal DOM / SimpleXML node access.

reference : http://quest4knowledge.wordpress.com/2010/09/04/php-xml-create-add-edit-modify-using-dom-simplexml-xpath/

2011年10月27日 星期四

PHP中的生成XML文件的4种方法

Xml代码




title1
content1
2009-10-11


title2
content2
2009-11-11




【直接生成字符串】
方法1:使用纯粹的PHP代码生成字符串,并把这个字符串写入一个以XML为后缀的文件。这是最原始的生成XML的方法,不过有效!
PHP代码如下:
Php代码

$data_array = array(
array(
'title' => 'title1',
'content' => 'content1',
'pubdate' => '2009-10-11',
),
array(
'title' => 'title2',
'content' => 'content2',
'pubdate' => '2009-11-11',
)
);
$title_size = 1;

$xml = "\n";
$xml .= "
\n";

foreach ($data_array as $data) {
$xml .= create_item($data['title'], $title_size, $data['content'], $data['pubdate']);
}

$xml .= "
\n";

echo $xml;

// 创建XML单项
function create_item($title_data, $title_size, $content_data, $pubdate_data)
{
$item = "\n";
$item .= "" . $title_data . "\n";
$item .= "" . $content_data . "\n";
$item .= " " . $pubdate_data . "\n";
$item .= "
\n";

return $item;
}

?>


【DomDocument】
方法2:使用DomDocument生成XML文件
创建节点使用createElement方法,
创建文本内容使用createTextNode方法,
添加子节点使用appendChild方法,
创建属性使用createAttribute方法
PHP代码如下:
Php代码

$data_array = array(
array(
'title' => 'title1',
'content' => 'content1',
'pubdate' => '2009-10-11',
),
array(
'title' => 'title2',
'content' => 'content2',
'pubdate' => '2009-11-11',
)
);

// 属性数组
$attribute_array = array(
'title' => array(
'size' => 1
)
);

// 创建一个XML文档并设置XML版本和编码。。
$dom=new DomDocument('1.0', 'utf-8');

// 创建根节点
$article = $dom->createElement('article');
$dom->appendchild($article);

foreach ($data_array as $data) {
$item = $dom->createElement('item');
$article->appendchild($item);

create_item($dom, $item, $data, $attribute_array);
}

echo $dom->saveXML();

function create_item($dom, $item, $data, $attribute) {
if (is_array($data)) {
foreach ($data as $key => $val) {
// 创建元素
$$key = $dom->createElement($key);
$item->appendchild($$key);

// 创建元素值
$text = $dom->createTextNode($val);
$$key->appendchild($text);

if (isset($attribute[$key])) {
// 如果此字段存在相关属性需要设置
foreach ($attribute[$key] as $akey => $row) {
// 创建属性节点
$$akey = $dom->createAttribute($akey);
$$key->appendchild($$akey);

// 创建属性值节点
$aval = $dom->createTextNode($row);
$$akey->appendChild($aval);
}
} // end if
}
} // end if
} // end function
?>


【XMLWriter】
方法3:使用XMLWriter类创建XML文件
此方法在PHP 5.1.2后有效
另外,它可以输出多种编码的XML,但是输入只能是utf-8
PHP代码如下:
Php代码

$data_array = array(
array(
'title' => 'title1',
'content' => 'content1',
'pubdate' => '2009-10-11',
),
array(
'title' => 'title2',
'content' => 'content2',
'pubdate' => '2009-11-11',
)
);

// 属性数组
$attribute_array = array(
'title' => array(
'size' => 1
)
);

$xml = new XMLWriter();
$xml->openUri("php://output");
// 输出方式,也可以设置为某个xml文件地址,直接输出成文件
$xml->setIndentString(' ');
$xml->setIndent(true);

$xml->startDocument('1.0', 'utf-8');
// 开始创建文件
// 根结点
$xml->startElement('article');

foreach ($data_array as $data) {
$xml->startElement('item');

if (is_array($data)) {
foreach ($data as $key => $row) {
$xml->startElement($key);

if (isset($attribute_array[$key]) && is_array($attribute_array[$key]))
{
foreach ($attribute_array[$key] as $akey => $aval) {
// 设置属性值
$xml->writeAttribute($akey, $aval);
}

}

$xml->text($row); // 设置内容
$xml->endElement(); // $key
}

}
$xml->endElement(); // item
}

$xml->endElement(); // article
$xml->endDocument();

$xml->flush();
?>


【SimpleXML】
方法4:使用SimpleXML创建XML文档
Php代码


$data_array = array(
array(
'title' => 'title1',
'content' => 'content1',
'pubdate' => '2009-10-11',
),
array(
'title' => 'title2',
'content' => 'content2',
'pubdate' => '2009-11-11',
)
);

// 属性数组
$attribute_array = array(
'title' => array(
'size' => 1
)
);

$string = <<


XML;

$xml = simplexml_load_string($string);

foreach ($data_array as $data) {
$item = $xml->addChild('item');
if (is_array($data)) {
foreach ($data as $key => $row) {
$node = $item->addChild($key, $row);

if (isset($attribute_array[$key]) && is_array($attribute_array[$key]))
{
foreach ($attribute_array[$key] as $akey => $aval) {
// 设置属性值
$node->addAttribute($akey, $aval);
}
}
}
}
}
echo $xml->asXML();
?>


reference : http://haroldphp.iteye.com/blog/1090240

【教學】縮放式的簡報工具--Prezi

Prezi是今年初竄起的簡報工具,由 匈牙利人所開發的,其炫麗的簡報畫面,讓人眼睛為之一亮!

數週前,由 小弟的啟蒙師父、雙白金資訊教師--鄭文榤老師 推薦 Prezi,

自己也玩過後,那自由奔放、有條理且人性化的操作介面,覺得超優的,

但因是英文介面,加上介面的使用方法很創新,故寫下這篇教學文,做個紀錄!



其類似 心智圖 般的從中間擴散出去,先觀看全局,再分述細部,打破傳統簡報一頁一頁的單向延伸,更符合人類思考的本質;

尤其是 Zooming 的 縮放功能 很實用,動一下滑鼠滾輪,即可讓讀者 Focus 目前的重點;

簡報路徑的呈現功能也是一絕,很像 攝影鏡頭 般,把目光從這一個物件忽然拉過去到另一個物件,時時牽引讀者的心;

個人覺得Prezi兼具 較 PowerPoint 製作更容易的優點,以及有 心智圖 擴散性思考的優點,其把呆版的簡報,開創了新的局面,原來上台簡報可以這麼有趣,這麼有條理~

※操作簡介:

操作介面平易近人,就像在一面牆上,貼滿 便利貼 似的,

藉由十幾個按鈕,把文字、圖片、影片、框框、線條等物件放入,

每個物件就像一個 便利貼,皆可直覺式的搬移、縮放、旋轉;

放置定位後,再規劃簡報時的呈現路徑,以便簡報時,Zooming、Focus某一個物件;

若是第一次使用可能會不甚習慣,但因操作介面簡潔,用個一兩次就順手了;

加入會員後,可免費在線上編輯簡報,容量限 100MB,

若付費後,可下載單機版來編輯簡報,也支援多人編輯簡報。

Prezi 有提供教育版,容量有 500 MB,可以不公開自己的作品,並移除 Prezi 的Logo,

申請教育版的步驟:

1. 必須是含有 .edu 的 e-Mail,

2. 選左邊的[Upgrade]選項,

3. 接著點選左邊的,填一些資料,即可升級為教育版囉!







網站名稱:Prezi

連結網址:http://prezi.com/

官網教學:Learn

互動式教學:四分鐘學會Prezi(英文)、使用Prezi的小技巧(英文)

中文教學:Prezi中文教學檔

官網作品:Showcase

本人拙作:維謙老師的自我介紹(Prezi製)、海報設計原則(Prezi製)



※中文教學

若覺得線上觀看略有模糊,請下載高清版的教學 prezi-full.swf

※幾項使用的小技巧(感謝 虎尾國中 生生不息的林老師 提供)

(1)路徑 設在區塊上,FOCUS效果較好。

(2)小線條無法選取時,滑鼠左鍵要按久一點,再放開才可選取。

(3)免費版做出的簡報必為publish版,公開發表出來,付費版則可選 隱藏發表。

(4)登入後方下載自己的簡報可成為 單機播放 使用。



※Prezi 目前的缺點(其製作團隊企圖心很強,這些問題應該有望解決):

1. 中文支援的問題

1-1 雖支援中文輸入,但有的文字還是闕漏。

1-2 中文模板只有一種。

1-3 只有英文操作介面。

1-4 不支援中文檔名的上傳檔案。

2. 影片、圖片支援的問題

2-1 只支援 .FLV 格式,上傳 .SWF 格式亦可,但播放偶而有問題。(上傳 .WMV 格式有時成功有時失敗)。

2-2 下載的播放檔,在播放影片時,其下方的影片控制按鈕消失了。

2-3 圖片 .GIF 格式上傳後,不支援動畫功能,形成單純的圖片。

3. 文字編輯的問題

3-1 文字顏色太少,只有三種。

3-2 無法選擇字體。

4. 物件的問題

4-1 缺少編輯圖層的功能。

4-2 缺少物件變形的功能。

4-3 編輯物件路徑錯誤時。

4-4 缺少自訂框架的功能。



延伸閱讀:

ZuiPrezi~強力建議Google必買的超炫線上簡報器

Prezi超炫的線上簡報

reference : http://163.32.219.6/blog/u882061/e-originality/2011/06/10/1294

【程式】PHP : Curl with Session

今天同事問了一個問題
A.php 用 Curl 去抓 B.php 。
然後 B.php 寫在 Session 的東西,
為什麼 A.php 抓不到 (當然 B.php 也抓不到 A.php 的值),
這是因為 curl 其實產生了另一個 session,
所以就算存了也抓不到。
當然也有解決的方法,就是使用 session_id()
程式如下:
A.php
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function doHttpRequest($url, $args='') {
$ch = curl_init();
//Post Data
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'sid='.session_id());

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}

session_start();
$_SESSION['aa']='[A.php]';
session_write_close();

$url = 'http://cw.dev.com/B.php';
echo doHttpRequest($url);

session_id(session_id());
session_start();
var_dump($_SESSION);
B.php
?
1
2
3
4
session_id($_POST['sid']);
session_start();
$_SESSION['bb']='[B.php]';
var_dump($_SESSION);
執行結果:
array 'aa' => string '[A.php]' (length=7) 'bb' => string '[B.php]' (length=7)
array 'aa' => string '[A.php]' (length=7) 'bb' => string '[B.php]' (length=7)

以上,記錄一下…

reference : http://ching119.pixnet.net/blog/post/59676045-%E3%80%90%E7%A8%8B%E5%BC%8F%E3%80%91php-%3A-curl-with-session

Agilefant 軟體

在跑 Agile 的人可以試試看

2011年10月26日 星期三

Introducing Phake Mocking Framework

I have used PHPUnit heavily now for the last 4 years. As anyone that is heavily involved in writing Unit Tests knows, test doubles (commonly referred to as mock objects) are a necessary part of your toolbox. The mocking options that we used to have for PHP unit testing have traditionally been fairly limited and most all of them in some form or another were ports of JMock. The way PHP operates as well as some decisions made to more closely emulate how JMock does things lead to functionality in the existing mock library for PHPUnit that for some are a hassle. This ranges from PHPUnit implicitly calling the “mockee’s” constructor (you have to explicitly specify that you do not want to call the constructor) to the pain of trying to stub or verify multiple invocations of the same method with different parameters.

Over the last three years, my experience as well as the musing of some of my colleagues has led me to believe that a lot of what I don’t like about mocking in php is the result of the fundamental notions of combining stubbing with verification and setting expectations ahead of method calls instead of verifying that what you expected to happen has indeed happened. This was essentially proven to me over the last year and a half as I have been heavily working with Java code and as a result have been using the Mockito mocking library for Java. The result of this work is the Phake Mocking Framework.

Now I am fairly certain that at least 5 or 6 people (which may constitute everyone who reads this) are rolling their eyes by now. So instead of going further into why I like this style of mocking I’ll just show you how to use it. Phake was designed with PHPUnit in mind, however I don’t really see any reason why it couldn’t be used in other testing frameworks as well. It is on my roadmap to confirm support for other frameworks. In any case, I will be using PHPUnit for my examples.

This document assumes you already have a good understanding of the basics of mocking. If the terms ‘Mocking’, ‘Stubbing’, and ‘Test Doubles’ mean nothing to you, I would recommend checking out the following links:

PHPUnit on Mock Objects
Wikipedia on Mock Objects
The Universe on Mock Objects
Getting Started

You can get a copy of Phake from Github. If you are familiar and comfortable with with git you can just clone my repository. If you would rather avoid the trappings of Github, you can also download Phake’s latest release tarball. Either way will result in a directory with two subdirectories: src and test. You will want to move the contents of the src directory to somewhere in your include path (such as /usr/share/php). Once you have done this, you can simply include “Phake.php” in any of your tests or in your bootstrap script and you will be off to the races.

UPDATE!!!

I just set up a pear channel to distribute phake as well. So if you would like to install Phake using pear, just do the following:

pear channel-discover pear.digitalsandwich.com
pear install channel://pear.digitalsandwich.com/Phake-1.0.0alpha
To show you some of the basics of how to use this framework, I am going to write various bits of codes to mock, verify, stub, etc the following class:


class MyClass
{
private $value;

public function __construct($value)
{
$this->value = $value;
}

public function getValue()
{
return $this->value;
}

public function subtract($int)
{
return $this->value - $int;
}
}

?>
Stubbing


require_once 'Phake.php';
class Test extends PHPUnit_Framework_TestCase
{
public function testStubbingGetValue()
{
// Sets up the mock object.
// Analogous to $this->getMock() in PHPUnit
$mock = Phake::mock('MyClass');

// Builds the stub for getValue.
// Essentially any call to getValue will return 42
Phake::when($mock)->getValue()->thenReturn(42);

$this->assertEquals(42, $mock->getValue());
}
}
You can also do conditional stubbing based on passed in parameters.

public function testStubbingGetValue2()
{
$mock = Phake::mock('MyClass');

// You can pass parameters into the stubbed method to indicate you
// only want to stub matching invocations. By default, anything
// passed in must be loosely matched ('==')
Phake::when($mock)->subtract(42)->thenReturn(30);

$this->assertEquals(30, $mock->subtract(42));

// It is important to note that any unstubbed calls will return null.
// Since 41 != 42 this call will return null.
$this->assertNull($mock->subtract(41));
}
If a specific invocation or call of a mock object has not been stubbed, it will return null. This behavior is different than the default behavior of PHPUnit’s mocking framework. If you need the default PHPUnit behavior then you could use something called partial mocks. Partial mocks are setup to call the constructor of the class being mocked and for any call that has not been stubbed, the parent method will be called.

public function testStubbingGetValue3()
{
// Creates a mock object whose constructor will call
// MyClass::__construct(42);
$mock = Phake::partMock('MyClass', 42);

Phake::when($mock)->subtract(42)->thenReturn(0);

// Since 18 != 42, the real method gets call
$this->assertEquals(24, $mock->subtract(18));
}
You can also specify on a per call basis that you want to call the parent, using the thenCallParent() method instead of thenReturn(). The different values you can use for stubbing are referred to as ‘Answers’. Here are a list of them and what they will do when a matching invocation is called:

thenReturn(mixed $var) – Will return the exact value passed in.
thenCallParent() – Will return the results of calling the mocked parent method.
thenThrow(Exception $e) – Will throw $e.
captureReturnTo(&$variable) – Acts exactly like thenCallParent() however it also captures the value that the parent returned to $variable. This allows you to run assertions. This comes in very handy for testing legacy code with protected or private factory methods whose return values are never returned out of the tested method’s scope.
The other thing to take note of stubbing is that any PHPUnit constraints are supported.

public function testStubbingGetValue4()
{
$mock = Phake::mock('MyClass');

//Matches any call to subtract() where the passed in value equals 42
Phake::when($mock)->subtract(42)->thenReturn(30);

//Matches any call to subtract() where the passed in value is less
// than 42. Notice that this is a phpunit constraint
Phake::when($mock)->subtract($this->lessThan(42))->thenReturn(29);

$this->assertEquals(30, $mock->subtract(42));
$this->assertEquals(29, $mock->subtract(41));
}
This gives you the same kind of stubbing flexibility that you have present in PHPUnit.

Verification

Verifying that methods on your stub are called is starkly different then how it is done in PHPUnit. The most apparent symptom of this difference is that you verify calls after the calls to your test methods have been made.

public function testVerify1()
{
// You can apply stubbings and verifications to the same mock objects
$mock = Phake::mock('MyClass');

$mock->getValue();

//Notice, getValue() has already been called
Phake::verify($mock)->getValue();
}
You of course have the same matching functionality at your disposal.

public function testVerify2()
{
$mock = Phake::mock('MyClass');

$mock->subtract(40);

//Notice the constraint
Phake::verify($mock)->subtract($this->lessThan(42));
}
By default, verify only allows a single matching invocation. You can also specify that a specific number of invocations should be allowed.

public function testVerify3()
{
$mock = Phake::mock('MyClass');

$mock->subtract(40);
$mock->subtract(39);

//The number of times is passed as the second parameter of
//Phake::verify()
Phake::verify($mock, Phake::times(2))->subtract($this->lessThan(42));
}
You can also use Phake::atLeast($n) and Phake::atMost($n) instead of Phake::times($n).

You can also specify that you don’t expect there to be any interactions with a mock.

public function testVerify4()
{
$mock = Phake::mock('MyClass');

// This will ensure that UP TO THIS POINT no methods on $mock have
// been called
Phake::verifyNoInteraction($mock);

// This would not result in an error, this can be prevented with
// another method explained below
$mock->getValue();

}
I am sure you noticed the comment that Phake::verifyNoInteraction() only verifies that no calls were made up to that point. You can essentially freeze a mock with another method

public function testVerify5()
{
$mock = Phake::mock('MyClass');

$mock->getValue();

// This will ensure that no methods on $mock will be called after this
// point
Phake::verifyNoFurtherInteraction($mock);
}
There are a few more advanced things you can do with something called argument captors.

public function testVerify6()
{
$mock = Phake::mock('MyClass');

$mock->subtract(42);

// Phake::capture tells Phake to store the parameter passed to
// subtract as the variable $val
Phake::verify($mock)->subtract(Phake::capture($val));

$this->assertEquals(42, $val);
}
This is a very pedestrian example, but it is not that uncommon for fairly complicated objects to passed in and out of methods. Argument capturing allows you to much more succinctly assert the state of those types of parameters. It is definitely overkill for asserting scalar types or simple objects.

More to Come

This really does cover the very basics of the Phake framework. In the coming days I will be putting out smaller more focused articles discussing some of the specific functionality. In the meantime I would love to get some feedback from anyone who is brave enough to play with this. My future roadmap basically involves shoring up the current code base a little bit more, adding a few pieces of missing or suboptimal functionality (I’m not so sure I have implemented ‘consecutive calls’) but I anticipate releasing an RC version no later than the end of January. Also, I am currently using and monitoring the issue tracker for Phake at github, so if you have some functionality you would like or find any bugs in your exploring, you can also open an issue there. Also, if you would like to help out with contributions, they are certainly welcome.

reference : http://digitalsandwich.com/archives/84-introducing-phake-mocking-framework.html

2011年10月23日 星期日

Front-end Code Standards & Best Practices

Overview

This document contains guidelines for web applications built by the Creative Technology (front end engineering) practice of Isobar US. It is to be readily available to anyone who wishes to check the iterative progress of our best practices. If you have any feedback, please leave a comment on the announcement blog post.

This document's primary motivation is two- fold: 1) code consistency and 2) best practices. By maintaining consistency in coding styles and conventions, we can ease the burden of legacy code maintenance, and mitigate risk of breakage in the future. By adhering to best practices, we ensure optimized page loading, performance and maintainable code.


General Guidelines◊Back to Top
Pillars of Front-end Development◊

Separation of presentation, content, and behavior.
Markup should be well-formed, semantically correct and generally valid.
Javascript should progressively enhance the experience.
General Practices◊

Indentation◊

For all code languages, we require indentation to be done via soft tabs (using the space character). Hitting Tab in your text editor shall be equivalent to four spaces.

Readability vs Compression◊

We prefer readability over file-size savings when it comes to maintaining existing files. Plenty of whitespace is encouraged, along with ASCII art, where appropriate. There is no need for any developer to purposefully compress HTML or CSS, nor obfuscate JavaScript.

We will use server-side or build processes to automatically minify and gzip all static client-side files, such as CSS and JavaScript.


Markup◊Back to Top
The first component of any web page is the tag-based markup language of HTML. The Hyper Text Markup Language (HTML) has a sordid history but has come into its own in the last few years. After a lengthy experimentation with the XML-based XHTML variant the industry has accepted that HTML is the future of the web.

Markup defines the structure and outline of a document and offers a structured content. Markup is not intended to define the look and feel of the content on the page beyond rudimentary concepts such as headers, paragraphs, and lists. The presentation attributes of HTML have all been deprecated and style should be contained in style sheets.

HTML5◊

HTML5 is a new version of HTML and XHTML. The HTML5 draft specification defines a single language that can be written in HTML and XML. It attempts to solve issues found in previous iterations of HTML and addresses the needs of web Applications, an area previously not adequately covered by HTML. (source).

We will use the HTML5 Doctype and HTML5 features when appropriate.

We will test our markup against the W3C validator, to ensure that the markup is well formed. 100% valid code is not a goal, but validation certainly helps to write more maintainable sites as well as debugging code. Isobar does not guarantee code is 100% valid, but instead assures the cross-browser experience is fairly consistent.

Template◊

For HTML5 Documents we use a fork of H5BP modified for our own project needs. Fork the Github repository.

Doctype◊

A proper Doctype which triggers standards mode in your browser should always be used. Quirks mode should always be avoided.

A nice aspect of HTML5 is that it streamlines the amount of code that is required. Meaningless attributes have been dropped, and the DOCTYPE declaration has been simplified significantly. Additionally, there is no need to use CDATA to escape inline JavaScript, formerly a requirement to meet XML strictness in XHTML.

HTML5 Doctype
1.

Character Encoding◊

All markup should be delivered as UTF-8, as its the most friendly for internationalization. It should be designated in both the HTTP header and the head of the document.

Setting the character set using tags.

1.

In HTML5, just do:

1.

General Markup Guidelines◊

The following are general guidelines for structuring your HTML markup. Authors are reminded to always use markup which represents the semantics of the content in the document being created.

Use actual P elements for paragraph delimiters as opposed to multiple BR tags.
Make use of DL (definition lists) and BLOCKQUOTE, when appropriate.
Items in list form should always be housed in a UL, OL, or DL, never a set of DIVs or Ps.
Use label fields to label each form field, the for attribute should associate itself with the input field, so users can click the labels. cursor:pointer; on the label is wise, as well. note 1 note 2
Do not use the size attribute on your input fields. The size attribute is relative to the font-size of the text inside the input. Instead use css width.
Place an html comment on some closing div tags to indicate what element you're closing. It will help when there is lots of nesting and indentation.
Tables shouldn't be used for page layout.
Use microformats and/or Microdata where appropriate, specifically hCard and adr.
Make use of THEAD, TBODY, and TH tags (and Scope attribute) when appropriate.
Table markup with proper syntax (THEAD,TBODY,TH [scope])
01.

02.

03.

04.

05.

06.

07.

08.

09.

10.

11.

12.

13.

14.
Table header 1 Table header 2
Table data 1 Table data 2

Always use title-case for headers and titles. Do not use all caps or all lowercase titles in markup, instead apply the CSS property text-transform:uppercase/lowercase.
Quoting Attributes◊

While the HTML5 specification defines quotes around attributes as optional for consistency with attributes that accept whitespace, all attributes should be quoted.

1.

This is my paragraph of special text.



CSS◊Back to Top
The second component of a web page is the presentation information contained in the Cascading Style Sheet (CSS.) Web browsers successful implementation of CSS has given a whole generation of web authors site-wide control over the look and feel of their web sites.

Just as the information on a web page is semantically described in the HTML Markup, CSS describes all presentation aspects of the page via a description of it's visual properties. CSS is powerful in that these properties are mixed and matched via identifiers to control the page's layout and visual characteristics through the layering of style rules (the "cascade").

General Coding Principles◊

Add CSS through external files, minimizing the # of files, if possible. It should always be in the HEAD of the document.
Use the LINK tag to include, never the @import.
Including a stylesheet
1.

Don't use inline styling
1.

This is poor form, I say


Don't include styles inline in the document, either in a style tag or on the elements. It's harder to track down style rules.
Use a reset CSS file (like the one present in H5BP or the Eric Meyers reset) to zero our cross-browser weirdness.
Use a font-normalization file like YUI fonts.css
Elements that occur only once inside a document should use IDs, otherwise, use classes.
Understand cascading and selector specificity so you can write very terse and effective code.
Write selectors that are optimized for speed. Where possible, avoid expensive CSS selectors. For example, avoid the * wildcard selector and don't qualify ID selectors (e.g. div#myid) or class selectors (e.g. table.results.) This is especially important with web applications where speed is paramount and there can be thousands or even tens of thousands of DOM elements. More on writing efficient CSS on the MDC.
CSS Box Model◊

Intimate knowledge and understanding of the CSS and browser-based box model is necessary for conquering the fundamentals of CSS layouts.


3D CSS Box Model diagram by Jon Hicks.
CSS Validation◊

We typically don't use the W3C validator.

CSS Formatting◊

At minimum, format CSS with selectors on one line and each property on its own line. The declarations are indented.

As an enhancement to that style, related or child styles and additional 2 or 4 spaces. That allows for hierarchical scanning and organization and makes (for some people) an easier-to-read style sheet.

01.
.post-list li a{
02.
color:#A8A8A8;
03.
}
04.
.post-list li a:hover{
05.
color:#000;
06.
text-decoration:none;
07.
}
08.
.post-list li .author a, .post-list li .author a:hover{
09.
color:#F30;
10.
text-transform:uppercase;
11.
}
For multiple author environments, single line CSS should be avoided because it can cause issues with version control.

Alphabetize◊
If you're performance obsessed alphabetizing CSS properties increases the odds of larger repeatable patterns being present to aid in GZIP compression.

Classes vs. IDs◊

You should only give elements an ID attribute if they are unique. They should be applied to that element only and nothing else. Classes can be applied to multiple elements that share the same style properties. Things that should look and work in the same way can have the same class name.

1.

    2.
  • Category 1

  • 3.
  • Category 2

  • 4.
  • Category 3

  • 5.

Naming Conventions for Selectors◊

It is always preferable to name something, be it an ID or a class, by the nature of what it is rather than by what it looks like. For instance, a class name of bigBlueText for a special note on a page is quite meaningless if it has been changed to have a small red text color. Using a more intelligent convention such as noteText is better because when the visual style changes it still makes sense.

Selectors◊

The CSS Selectors Level 3 specification introduces a whole new set of CSS Selectors that are extremely useful for better selection of elements.

Pseudo-classes◊
Pseudo-classes enable you to dynamically style content. Some pseudo-classes have existed since CSS1 (:visited, :hover, etc.) and CSS2 (:first-child, :lang). As of CSS3, 16 new pseudo-classes have been added to the list and are especially useful for styling dynamic content. Learn how to use pseudo-classes in-depth.

Combinators & Attribute Selectors◊
Combinators provide shortcuts for selecting elements that are a descendant element, a child element, or an element's sibling.

Attribute Selectors are great for finding elements that have a specific attribute and/or specific value. Knowledge of regular expressions helps with attribute selectors.

Specificity◊
Browsers calculate a selector's specificity to determine which CSS rule should apply. If two selectors apply to the same element, the one with the higher specificity wins.

IDs have a higher specificity than attribute selectors do, and class selectors have higher specificity than any number of element selectors. Always try to use IDs to increase the specificity. There are times when we may try to apply a CSS rule to an element and it does not work no matter what we try. This is likely because the specificity of the selector used is lower than another one and the properties of the higher one are taking precedence over those you want to apply. This is more common in working with larger more complex stylesheets. It isn't a big issue with smaller projects usually.

Calculating specifity◊

When working with a large and complex stylesheet it helps to know how to calculate the value of a selector's specificity, to save you time and to make your selectors more efficient.

Specificity is calculated by counting various components of your CSS and expressing them in a form (a,b,c,d).

Element, Pseudo Element: d = 1 – (0,0,0,1)
Class, Pseudo class, Attribute: c = 1 – (0,0,1,0)
Id: b = 1 – (0,1,0,0)
Inline Style: a = 1 – (1,0,0,0)
However, it may be better to use a specificity calculator.

Specificity Calculator
Some things you should know about specificity
IE Specificity bugs
Using !important overrides all specificity no matter how high it is. We like to avoid using it for this reason. Most of the time it is not necessary. Even if you need to override a selector in a stylesheet you don't have access to, there are usually ways to override it without using !important. Avoid using it if possible.

Pixels vs. Ems◊

We use the px unit of measurement to define font size, because it offers absolute control over text. We realize that using the em unit for font sizing used to be popular, to accommodate for Internet Explorer 6 not resizing pixel based text. However, all major browsers (including IE7 and IE8) now support text resizing of pixel units and/or full-page zooming. Since IE6 is largely considered deprecated, pixels sizing is preferred. Additionally, unit-less line-height is preferred because it does not inherit a percentage value of its parent element, but instead is based on a multiplier of the font-size.

Correct
1.
#selector {
2.
font-size: 13px;
3.
line-height: 1.5; /* 13 * 1.5 = 19.5 ~ Rounds to 20px. */
4.
}
Incorrect
1.
/* Equivalent to 13px font-size and 20px line-height, but only if the browser default text size is 16px. */
2.
#selector {
3.
font-size: 0.813em;
4.
line-height: 1.25em;
5.
}
Internet Explorer Bugs◊

Inevitably, when all other browsers appear to be working correctly, any and all versions of Internet Explorer will introduce a few nonsensical bugs, delaying time to deployment. While we encourage troubleshooting and building code that will work in all browsers without special modifications, sometimes it is necessary to use conditional if IE comments for CSS hooks we can use in our stylesheets. Read more on paulirish.com

Fixing IE
1.

2.

3.

4.

5.

1.
.box { float: left; margin-left: 20px; }
2.
.ie6 .box { margin-left: 10px; }
If you're using HTML5 (and the HTML5 Boilerplate) we encourage the use of the Modernizer JavaScript library and this pattern:

1.

2.

3.

4.

5.

Shorthand◊

In general, CSS shorthand is preferred because of its terseness, and the ability to later go back and add in values that are already present, such as the case with margin and padding. Developers should be aware of the TRBL acronym, denoting the order in which the sides of an element are defined, in a clock-wise manner: Top, Right, Bottom, Left. If bottom is undefined, it inherits its value from top. Likewise, if left is undefined, it inherits its value from right. If only the top value is defined, all sides inherit from that one declaration.

For more on reducing stylesheet code redundancy, and using CSS shorthand in general:
http://qrayg.com/journal/news/css-background-shorthand
http://sonspring.com/journal/css-redundancy
http://dustindiaz.com/css-shorthand
Images◊

For repeating images, use something larger than 1x1 pixels
You should never be using spacer images.
Use CSS sprites generously. They make hover states easy, improve page load time, and reduce carbon dioxide emissions.
Typically, all images should be sliced with a transparent background (PNG8). All should be cropped tightly to the image boundaries.
However, the logo should always have a background matte and have padding before the crop. (so other people can hotlink to the file)
General Text and Font Styling◊

Headings◊
Define default styling for h1-h6 headings including headings as links. It's helpful to declare these at the top of your CSS document, and modify them with as necessary for consistency across the site.
Headings should show a hierarchy indicating different levels of importance from the top down starting with h1 having the largest font size.
SEO: To get a rough idea of how your page hierarchy is organized and read, use your Developer Toolbar to disable CSS. You'll end up with a text-based view of all your h1-h6 tags, strong, em, etc.
Links◊
Default styles for links should be declared and different from the main text styling, and with differing styles for hover state.
When styling links with underlines use border-bottom and some padding with text-decoration: none;. This just looks better.
Web Typography◊

The use of custom fonts and typefaces on the web has been growing more popular the past few years. with native browser support on the rise and several supporting services and APIs now available there is real momentum in this space. Each of these approaches have their own pros and cons. Before a project kicks off it's best to do research into technology and licensing limitations to choose the proper approach for the specific project.

All of these approaches have drawbacks in code overhead, development time and performance (clock and perceived). Familiarizing yourself with these issues and communicating them to the other members of the team and to the client will save significant problems later on in the project.

Listed here are some popular methods of embed custom fonts, list in the order of our preference for implementation.

@font-face◊

The @font-face at-rule allows you to define custom fonts. It was first defined in the CSS2 specification, but was removed from CSS2.1. Currently, it's a draft recommendation for CSS3.

Our first and most preferred choice for customizing fonts on the web is @font-face, simply because it is part of the CSS Fonts Module working draft which means it will continue to grow in popularity as browser support grows, and ease of use for it improves as it becomes more stable.

For now, when using @font-face it's recommended to declare the source for each font format. This is important if you want it to work in the most number of browsers, though it is not a requirement for use.

The font formats included in the specification are:
woff: WOFF (Web Open Font Format)
ttf: TrueType
ttf, otf: OpenType
eot: Embedded OpenType
svg, svgz: SVG Font
Bulletproof @font-face◊
For full cross-browser compatibility use Fontsprings' new bulletproof @font-face syntax (latest version as of 2/21/11).

01.
@font-face {
02.
font-family: 'MyFontFamily';
03.
src: url('myfont-webfont.eot'); /* IE9 Compat Modes */
04.
src: url('myfont-webfont.eot?iefix') format('eot'), /* IE6-IE8 */
05.
url('myfont-webfont.woff') format('woff'), /* Modern Browsers */
06.
url('myfont-webfont.ttf') format('truetype'), /* Safari, Android, iOS */
07.
url('myfont-webfont.svg#svgFontName') format('svg'); /* Legacy iOS */
08.
font-weight: ;
09.
font-style: ;
10.
// etc.
11.
}
Here's a working demo using this version of implementation.

Cross-Browser Compatibility◊
Safari, IE 6-9, IE 9 Compatibility Modes, Firefox, Chrome, iOS, Android, Opera

Prevent Compatibility Mode◊
Sometimes IE can have a mind of its own and will switch to compatibility mode without you knowing. Include the following in the site to prevent your site from defaulting to compatibility mode:

1.

Tips for @font-face◊
IE 6–8 will only accept a TrueType font packaged as an EOT.
font-weight and font-style have different meanings within @font-face. Declarations where font-weight:bold; means this is the bold version of this typeface, rather than apply bold to this text
@font-face gotchas
Pros
Easy to implement
Large variety of APIs
Customizable
Easy to add to elements
Nothing required besides CSS
Is currently part of the working draft of CSS Fonts Module 3
Cons
Limited browser support if used improperly
Some older versions of modern browsers (Chrome, Opera) don't always render well. Text can have rough edges. **I have not been able to confirm whether this is still an issue now or not.
Google WebFonts API & Font Loader◊

There are two options available with Google Webfonts. Both options have their downsides of course but they can be just as good to use as @font-face, it all depends on a projects needs.

Webfonts API◊
Google's Webfonts API essentially does the same thing as @font-face, it just does all the hard work for you, providing wider browser support.The major drawback to this method is the very small font library it uses. To make it work all you need to do is include the stylesheet + the font name.

1.

Then define a style for the selector you want to apply the font to:
1.
CSS selector {
2.
font-family: 'Font Name', serif;
3.
}
Webfont Loader◊

Another option Google offers is the Webfont Loader which is a JavaScript library that allows for more control than the font API does. You can also use multiple webfont providers like Typekit. To use it include the script in your page:

01.

Including the webfont.js file this way is faster if not already using the Ajax APIs. Otherwise you should use this:
1.

2.

By using the Webfont Loader you have more ability to customize things including the use of more fonts, not just those in the Google Webfont library which is not large. However, it then requires you to load JavaScript, sacrificing one thing for another.

Pros
Very easy to implement
Wide browser support
Can be combined with Typekit
Customizable when using the font loader
API does the same thing as @font-face
Cons
Very small font library if using the font API
Using the Webfont Loader requires the use of JavaScript to work
Most browsers will load the rest of the page first, leaving a blank space where the text would be, or otherwise show the fallback option if one exists, until the page fully loads.
Some fonts in the webfont library render poorly on Windows
Cufon◊

If you choose to use Cufon, it is highly recommended you use the Cufon compressed version. You will need to convert your font using the generator.

1.

2.

3.

We recommend using Cufon sparingly since it can cause a lot of overhead if applied to a large amount of text. For more info visit the Cufon Wiki.

Pros
Wide browser support
Renders well in supported browsers
Customizable
Easy to implement
Cons
Requires use of JS to work
Text can't be selected that uses it
Not all characters can be used
Customization can be a pain
Not always easy to apply to multiple elements, especially when adding effects like hovers
Typekit◊

Using Typekit has its advantages and shouldn't be completely disregarded when choosing which method to use for adding custom fonts to a web site. It has strong platform integration and is a scalable and popular service. It can be used with Google Webfonts and is easily added to WordPress, Posterous, Typepad, and other similar CMS powered sites.

However, full use of Typekit doesn't come without a cost. If you need to use it on more than 2 sites or on a site that gets a high amount of pageviews you will need to pay an annual cost of $49.99, and for sites with a million+ pageviews it costs twice as much. Though, you probably have the money to cover the cost if you're getting over a million pageviews. If not then you may want to rethink your business model.

Pros
Large font library, including Adobe fonts
Easy implementation
Google Webfont API and blogging platform integration
Free plan has limits but doesn't expire
Cons
Requires JavaScript to use
Limited font library access without paying
Free and cheapest plans only allow use on 1-2 web sites and 2-5 fonts per site
You have to pay to use it on more than 1 site
Scalable Inman Flash Replacement (sIFR)◊

We do not recommend that you use this method but because of how widely used it is we felt it was necessary to include so you could make a properly informed decision when choosing which method to go with for customized webfonts.

Despite its wide popularity among web designers, and its decent support in most browsers, the drawbacks to its use outweigh its convenience. The biggest and most obvious reason to not use sIFR is the fact that it uses Flash. Plus, in order for the Flash to even work, it requires JavaScript and the scripts must be loaded before the text you use it on is visible on the page. Not to mention that it increases page load time, and can cause a slow site to be even slower.

We'll let you do the math here.
Pros
Text can be selected
Support on most browsers
Renders okay on supported browsers
Cons
It uses Flash
Requires JavaScript for the Flash to work
It's Flash!
Text doesn't appear until the scripts load
...and it's Flash...
Font Licensing◊

Even though you can transform just about any font into a web font file, you should still make sure it is legally okay for you to do so. Many foundries have updated their conditions to specify how their fonts can be used on the web. View Font Licensing and Protection Details for more information.

Specifications & Font File Formats◊

CSS 2 Fonts – May 1998 (Obsolete)
CSS 3 Fonts – Working Draft 2009
CSS Fonts Module – W3C Working Draft March 2011
WOFF Font Format – Working Draft 2010
SVG Font Format
Embedded Open Type (EOT) File Format
Microsoft Open Type Specification
OpenType Feature File Specification
Apple True Type Reference

JavaScript◊Back to Top
JavaScript is the third major component of a web page. JavaScript code, when properly applied to a web page, enhances the overall user and browser-based experience through attaching to events and controlling the overall behavior layer.

JavaScript has seen an explosion in popularity in recent years as powerful new browser implementations have finally empowered the creation of full on browser-based web applications. Additionally, careful use of JavaScript allows for full manipulation and control over the other two components of web page authoring, HTML Markup and CSS. Today the structure of pages and the visual styles of pages can be manipulated real time without full web page refreshes.

JavaScript Libraries◊

We primarily develop new applications in jQuery, though we have expertise in plain JavaScript as well as all major modern javascript libraries.
General Coding Principles◊

99% of code should be housed in external javascript files. They should be included at the END of the BODY tag for maximum page performance.
Don't rely on the user-agent string. Do proper feature detection. (More at Dive Into HTML5: Detection & jQuery.support docs)
Don't use document.write().
All Boolean variables should start with "is".
Test for positive conditions
1.
isValid = (test.value >= 4 && test.success);
Name variables and functions logically: For example: popUpWindowForAd rather than myWindow.
Don't manually minify. With the exception of the traditional i, etc. for for loops, variables should be long enough to be meaningful.
Documentation should follow NaturalDocs structure.
Constants or configuration variables (like animation durations, etc.) should be at the top of the file.
Strive to create functions which can be generalized, take parameters, and return values. This allows for substantial code reuse and, when combined with includes or external scripts, can reduce the overhead when scripts need to change. For example, instead of hard coding a pop-window with window size, options, and url, consider creating a function which takes size, url, and options as variables.
Comment your code! It helps reduce time spent troubleshooting JavaScript functions.
Don't waste your time with comments surrounding your inline javascript, unless you care about Netscape 4. :)
Organize your code as an Object Literal/Singleton, in the Module Pattern, or as an Object with constructors.
Minimize global variables - the less globals you create, the better. Generally one, for your application namespace, is a good number.
When specifying any global variable, clearly identify it
1.
window.globalVar = { ... }
White-space◊

In general, the use of whitespace should follow longstanding English reading conventions. Such that, there will be one space after each comma and colon (and semi-colon where applicable), but no spaces immediately inside the right and left sides of parenthesis. In short, we advocate readability within reason. Additionally, braces should always appear on the same line as their preceding argument.

Consider the following examples of a JavaScript for-loop...

Correct
1.
for (var i = 0, j = arr.length; i < j; i++) {
2.
// Do something.
3.
}
Incorrect
1.
for ( var i = 0, j = arr.length; i < j; i++ )
2.
{
3.
// Do something.
4.
}
Also incorrect
1.
for(var i=0,j=arr.length;i2.
// Do something.
3.
}
plugins.js and script.js◊

Starting with H5BP we're presented with two files, plugins.js and script.js. This section outlines basic usage of these two files.

plugins.js◊
Plugins.js is meant to hold all of a sites plugin code. Instead of linking to many different files, we can improve performance by including plugin code directly in this one file. There can and should be exceptions to this usage. An extremely large plugin only used on one rarely visited page, for example, might be better off in a separate download, only accessed on the target page. Most of the time, however, it's safe to just paste in minified versions of all your plugins here for easy access.

Here's what an example file might looks like, including a small table of contents. This can serve as a handy guide for what plugins are in use, including URLs for documentation, rationale for use and the like.

01.
/* PLUGIN DIRECTORY
02.
What you can find in this file [listed in order they appear]
03.

04.
1.) Animate Background Position - http://plugins.jquery.com/project/backgroundPosition-Effect
05.
2.) jQuery Easing Plugin - http://gsgd.co.uk/sandbox/jquery/easing/
06.
3.) jQuery Ajax Form plugin - http://jquery.malsup.com/form/#download
07.
4.) jQuery validation plugin (form validation) - http://docs.jquery.com/Plugins/Validation
08.
-password strength
09.
5.) Styled Selects (lightweight) - http://code.google.com/p/lnet/wiki/jQueryStyledSelectOverview
10.
*/
11.

12.
/**
13.
* 1.) Animate Background Position - http://plugins.jquery.com/project/backgroundPosition-Effect
14.
* @author Alexander Farkas
15.
* v. 1.21
16.
*/
17.
(function($) {
18.
if(!document.defaultView || !document.defaultView.getComputedStyle){ // IE6-IE8
19.
//SNIPPED
20.
};
21.
})(jQuery);
22.

23.

24.
/**
25.
* 2.) jQuery Easing Plugin (we're not using jQuery UI as of yet) - http://gsgd.co.uk/sandbox/jquery/easing/
26.
*/
27.

28.
// t: current time, b: begInnIng value, c: change In value, d: duration
29.
jQuery.easing['jswing'] = jQuery.easing['swing'];
30.

31.
jQuery.extend( jQuery.easing,
32.
{
33.
//SNIPPED
34.

35.
});
36.
;(function($) {
37.
$.fn.ajaxSubmit = function(options) {
38.
//SNIPPED
39.
}
40.
})(jQuery);
41.

42.
/*
43.
* jQuery Styled Select Boxes
44.
* version: 1.1 (2009/03/24)
45.
* @requires jQuery v1.2.6 or later
46.
*
47.
* Examples and documentation at: http://code.google.com/p/lnet/wiki/jQueryStyledSelectOverview
48.
*
49.
* Copyright (c) 2008 Lasar Liepins, liepins.org, liepins@gmail.com
50.
*
51.
* Permission is hereby granted, free of charge, to any person obtaining a copy
52.
* of this software and associated documentation files (the "Software"), to deal
53.
* in the Software without restriction, including without limitation the rights
54.
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
55.
* copies of the Software, and to permit persons to whom the Software is
56.
* furnished to do so, subject to the following conditions:
57.
*
58.
* The above copyright notice and this permission notice shall be included in
59.
* all copies or substantial portions of the Software.
60.
*
61.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
62.
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
63.
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
64.
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
65.
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
66.
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
67.
* THE SOFTWARE.
68.
*
69.
*/
70.

71.
jQuery.fn.styledSelect = function(settings) {
72.
//SNIPPED
73.
return this;
74.
};
Script.js◊
Script.js is meant to hold your site or application code. Again, this isn't always the best solution as larger teams and or larger, more feature rich projects can really benefit from breaking out application code into module or feature specific files. For smaller sites, simpler applications, and initial prototyping, however, dropping your work into scripts.js makes sense.

A simplified example, using the Markup-based unobtrusive comprehensive DOM-ready execution pattern, might look something like the following:

01.
/* Name: Demo
02.
Author: Demo King */
03.
/*demo namespace*/
04.
demo = {
05.
common : {
06.
init : function(){
07.
//initialize
08.
},
09.
finalize : function(){
10.
//finalize
11.
},
12.
config : {
13.
prop : "my value",
14.
constant : "42"
15.
}
16.
},
17.
mapping : {
18.
init : function(){
19.
//create a map
20.
},
21.
geolocate : function(){
22.
//geolocation is cool
23.
},
24.
geocode : function(){
25.
//look up an address or landmark
26.
},
27.
drawPolylines : function(){
28.
//draw some lines on a map
29.
},
30.
placeMarker : function(){
31.
//place markers on the map
32.
}
33.
}
34.
}
Variables, ID & Class◊

All JavaScript variables shall be written in either completely lowercase letter or camelCase. The one exception to this are Constructor functions, which are capitalized by tradition. All id and class declarations in CSS shall be written in only lowercase. Neither dashes nor underscores shall be used.

Event Delegation◊

When assigning unobtrusive event listeners, it is typically acceptable to assign the event listener directly to the element(s) which will trigger some resulting action. However, occasionally there may be multiple elements which match the criteria for which you are checking, and attaching event listeners to each one might negatively impact performance. In such cases you should use event delegation instead.

jQuery's delegate() is preferred over live() for performance reasons.

Debugging◊

Even with the best of validators, inevitably browser quirks will cause issues. There are several invaluable tools which will help to refine code integrity and loading speed. It is important that you have all of these tools available to you, despite the browser you primarily use for development. We recommend developing for Firefox and Safari first, then Google Chrome and Opera, with additional tweaks via conditional comments just for Internet Explorer. The following is a list of helpful debuggers and speed analyzers...

Firefox: Firebug, Page Speed, YSlow
Safari: Web Inspector
Google Chrome: Developer Tools
Opera: Dragonfly
Internet Explorer 6-7: Developer Toolbar
Internet Explorer 8-10: Developer Tools
Patterns for better JavaScript◊

Writing Maintainable Code
Single var Pattern
Hoisting: A Problem with Scattered vars
(Not) Augmenting Built-in Prototypes
Avoiding Implied Typecasting
Avoiding eval()
Number Conversions with parseInt()
Opening Brace Location
Capitalizing Constructors
Writing Comments
Avoid void
Avoid with Statement
Avoid continue Statement
Avoid Bitwise Operators if possible
Stoyan Stefanov covers these and more in detail here.


Accessibility◊Back to Top
Section 508 Standards for intranet and internet information and applications.

— Interfaces developed by Isobar should meet Section 508 standards.
W3C checklist of checkpoints for accessibility.

— Interfaces developed by Isobar should meet Priority 1 guidelines.
— The WCAG 1.0 Guidelines.

Performance◊Back to Top
As we continue to push the limits of what the web can do, it remains just as important a web page can be used with minimal effort or wait time. The following section explains how web pages can be optimized to keep all audiences happy.

Optimize Delivery of CSS and JavaScript◊

There are many optimizations that should be done for serving CSS and javascript in Production:

Follow the Yahoo Performance Guidelines
Smush images using smush.it. Also using YSlow can autosmush all your images for you.
Set caching headers appropriately.
Consider a cookie-less subdomain for static assets
Avoid inline