issue no. 20 (november 2013) - searching high and low

Upload: sofmartyrdom

Post on 04-Jun-2018

216 views

Category:

Documents


0 download

TRANSCRIPT

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    1/33

    Published by S&S Media Group

    www.webandphp.com

    ALSO IN THIS ISSUE

    November 2013Issue 20

    Compile Your Style: Smarter CSS

    by Ragnar Kurm

    Clean up WordPress shortcodes

    by Jason Lengstorf

    Talks and the power of human

    interactionby Stefan Priebsch

    Column databases overview

    by Cory Isaacson

    Open source spotlight: RainLoop

    Searching

    high and lowStretching your dataComplex queries made easy with Elasticsearch

    Equality in PHPlandWhy == and === equal trouble

    Through the looking glassCreate your own picture processor in PHP

    iStockphoto.com/ferrantraite

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    2/33

    Contents

    ContentsLetter from the Editor

    Lets get straight into it

    opening this issue, we have

    three incredible tutorials for

    the less experienced dev.First, an introduction to the

    open-source search engine

    Elasticsearch, which pow-

    ers the public search on

    both GitHub and Sound-

    Cloud, written by the prima-

    ry developer of its PHP driver, Zachary Tong.Next, a quick tip from Jason Lengstorf for those of

    you working with shortcodes in everyones favorite

    blog/CMS/kitchen sink WordPress; followed by a crash-

    course in PHPs built-in image filters from Robin Nixon.

    All three are filtering in different ways, dont you

    think? Alright, wordplay aside, stripping away the un-

    necessary cruft and drilling down to what really matters

    is an important philosophy for developers just take

    a look at the whole lean startup movement. In thewords of Sir Jony Ive: True simplicity is derived from

    so much more than just the absences of clutter or or-

    namentation. Its about bringing order to complexity.

    Sometimes reducing that complexity paradoxically

    requires increasing it. Take Ragnar Kurms MLSBS

    workflow, for example. To those working with a

    200-line CSS file, learning to use a preprocessor and

    splitting it into many small pieces might seem like

    madness, not to mention the additional overhead of

    setting up these workflows and automation scripts.

    But when youre up to your ears in inconsistent selec-

    tors and patching an already-bloated stylesheet with

    !importanthacks, suddenly a clean and modular ap-

    proach makes a whole lot of sense.

    Kurm has taken a programmers approach to writ-

    ing stylesheets, automating as much as possible and

    taming CSSs nastier properties, which he explores in

    a two-part series beginning on page 17. The first partstarts with writing smarter CSS with SASS essential

    reading for anyone doing even a small amount of work

    with CSS. I wont spoil it for you, but part two (comingsoon) gets even cooler.

    And then, there are some issues that on the surface

    look simple, but in reality must be studied in detail to

    truly understand. PHPs equality operator (== to its

    friends) seems simple enough; but its type conver-

    sion can result in some very odd outcomes that, to

    make sense of, require digging into the Zend engines

    source code. Luckily Sharon Levy has already done the

    hard work: you can read her solution on page 23.

    Enjoy the issue!

    Elliot Bentley, Editor

    Needle in a haystackCommunity Corner

    This months top events 3Open source spotlight: RainLoop 4

    Interview with Usenko Timur

    Tutorial

    Stretching your data withElasticsearch 5Zachary Tong

    Tutorial

    Quick tip: Remove crappy markupfrom WordPress shortcodes 9Jason Lengstorf

    Tutorial

    Create your own pictureprocessor in PHP 11Robin Nixon

    Tutorial

    Compile Your Style: Smarter CSS 17Ragnar Kurm

    Feature

    Equality in PHPland 23Sharon Lee Levy

    Column

    Column databases overview 28Cory Isaacson

    Column

    Talks and the powerof human interaction 32Stefan Priebsch

    www.webandphp.com Web & PHP Magazine 11.13 | 2

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    3/33

    Community CornerCalendar

    To suggest an event for our calendar,email [email protected].

    THIS MONTHS TOP EVENTS

    November 5 30 //A handpicked selection of some of the mostexciting PHP events from around the world

    November 7 // Orlando, FL, USA // Free

    The Orlando PHP MeetupGroup Monthly Meetup

    http://www.meetup.com/OrlandoPHP/events/137057312/This months meetup is a Coding Dojo, whereparticipants take it in turn to code in front of alive audience. Sounds terrifying.

    November 89 // Maastricht, Netherlands// 110

    CodeConnexxhttp://codeconnexx.com/Hosted by PHP Women, this not all techni-cal conference includes keynotes from LornaMitchell and Ross Tuck.

    November 16 // Madison, WI, USA // $ 100

    Madison PHP Conferencehttp://2013.madisonphpconference.com/Organised by the local usergroup, this conferenceincludes a Foundations Track for beginners inaddition to a Professional Track.

    November 2122 // Paris, France // 250

    Forum PHP Paris 2013http://afup.org/pages/forumphp2013/The City of Light hosts a two-day event inboth French and English, including a talk fromPHP 5.5 release manager Julien Pauli.

    November 26 // Brisbane, Australia// Free

    Brisbane Web Tech

    Nov 2013http://www.meetup.com/brisbane-webtech/events/126487932/This months speaker is Darren Mackeyon multivariate statistical theory and itsapplications to big data.

    www.webandphp.com Web & PHP Magazine 11.13 | 3

    http://www.meetup.com/OrlandoPHP/events/137057312/http://www.meetup.com/OrlandoPHP/events/137057312/http://www.meetup.com/OrlandoPHP/events/137057312/
  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    4/33

    Community CornerOSS Spotlight

    Web & PHP Magazine: Whos behind Rain-Loop?Usenko Timur: An ordinary developer from Rus-sia. Also, there are several people who helped me,and that help is really appreciated.

    WPM: Why did you decide to start it? Andwhy did you make it open source?Timur: Thats quite a long story. Initially, I havecreated MailSo, PHP library for handling mails.Its main idea was to make sure that size of mes-sages does not affect amount of memory usedby PHP. Then I thought I should develop someother tool so that development of the librarygoes in right direction. Thats when I startedmaking webmail client based on MailSo library.There were like 7 attempts to create an applica-

    tion which would satisfy me in terms of codequality and design. The 8th attempt, which in-volved KnockoutJs library released around thattime, has provided the result I was looking for.Thats how RainLoop appeared, and eventually itbecame much more complex than MailSo.

    As for the second question, RainLoop isnt exactlyopen source. Its free, yes, but I only provide the pack-age Ive built. PHP source there can be freely reviewedand modified, but JS files are minified to speed uploading, and the CSS is a result of processing less-files.

    WPM: Whats the appeal of hosting your ownemail client?Timur: I guess, this is where everyone has their ownreasons. Some people are happy with GMail while oth-er look for better control over their mails so they installtheir own mail servers and use webmail clients theyfind appropriate.

    WPM: How can people get involved in the project,and what can they do to help out?Timur: Currently, what I need the most is transla-

    tions and issue descriptions used in logs. Im tryingto examine, process and implement those as soonas possible. Later, a plugin system will be added anddocumented, and anyone will be able to extend prod-uct functionality to ones liking. And of course, Id liketo know what kind of features people want to see in

    Open source spotlight: RainLoop

    RainLoop though with any new features added,RainLoop must stay as a simple email application,easy for understanding and configuring.

    WPM: Where do you hope to see the project

    in a years time?Timur: This all depends on project users. Theirfeedback will help me perfect the current function-ality. Im staying realistic as to what I can achieve,but what can be improved will be improved.

    Meeting the people behind the most exciting homegrown OSS projects. This month,we speak to Usenko Timurabout RainLoop, a web-based email client built in PHP.

    Homepage: http://rainloop.net/

    GitHub: https://github.com/RainLoop/rainloop-webmail

    www.webandphp.com Web & PHP Magazine 11.13 | 4

    https://github.com/RainLoop/rainloop-webmailhttps://github.com/RainLoop/rainloop-webmailhttps://github.com/RainLoop/rainloop-webmailhttps://github.com/RainLoop/rainloop-webmail
  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    5/33

    TutorialElasticsearch

    by Zachary Tong

    Regardless of your domain, you have data. Perhaps itis e-commerce data and product listings. Maybe youhave a million clickstream entries from advertising.Or perhaps you have billions of log records that youneed to analyze.

    Whatever it is, you have data. And you need to accessthat data somehow, to interrogate it and reveal trends,patterns and insights that benefit your business. Stor-

    ing data is almost never a problem ... but how do youquery it? Consider the three following questions:

    Structured: Which employees are over 30? Unstructured: Which employees have namesstarting with Zac?

    Analytics: How many employees does each de-partment have?

    Traditional databases can answer the first questionwithout a problem. Dates, numbers, exact values,ranges structured search is simple for a database.Unstructured search, however, is nearly impossiblewith most databases. Their data structures simply donot allow them to answer unstructured, full text ques-tions with any kind of performance. Likewise, analyt-ics and aggregations are also very difficult. Realtimeaggregations are even harder, and as data grows, youoften resort to batch aggregations that run on a sched-

    ule. Finally, what happens if you want to ask the fol-lowing question: Show me the number of employeesin each department who are over 30 and have namesstarting with Zac?

    That will be painful in a database no matter how wellcleverly you organize your data and tweak your query.Unfortunately, these types of queries are often themost valuable to your business.

    Put a bounce in your step

    Stretching your datawith ElasticsearchComplex queries and fuzzy matches are easy with open sourcesearch and analytics tool Elasticsearch. Zachary Tong showshow to get to grips with the PHP driver.

    ImagelicensedbyIngramIm

    age

    www.webandphp.com Web & PHP Magazine 11.13 | 5

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    6/33

    TutorialElasticsearch

    Introducing Elasticsearch

    Elasticsearch was born as a full text search engine, but

    it has grown to answer all four scenarios presented

    above. Elasticsearch can handle structured search just

    as well (and just as fast!) as unstructured search and

    real-time analytics.

    At a high-level, Elasticsearch is a distributed docu-ment store where every field is indexed and search-

    able in near-real-time. It speaks HTTP over a RESTfulAPI, which means it is dead simple to interact with. It

    runs on one laptop just as well as on a 100 node cluster

    indexing literally terabytes of data.

    It may seem too good to be true, but it's simply

    the result of Elasticsearchs underlying data struc-

    ture. While most databases rely on structures like

    B-Trees, Elasticsearch uses an inverted index [1].

    The nature of inverted indices means that all fields

    are indexed, and lookups are fast regardless of how

    much data you have.But more important than technical details, Elastic-

    search is easy to get started with. You can get a clus-

    ter running in under five minutes.

    Your first cluster

    The best way to get familiar with Elasticsearch is to

    try it yourself. Lets download Elasticsearch [2], in-

    stall it and start a node (Listing 1). The only require-

    ment is that Java must be installed on your system.

    Once you start the node, youll see some startup text

    print to the terminal.

    Youll notice that Elasticsearch returned JSONoutput as the body of the HTTP response. Elastic-

    search speaks JSON as its language of choice.

    Everything is JSON, including documents, requests

    and responses. This makes it very easy to interactwith Elasticsearch from within PHP; JSON can eas-

    ily be encoded/decoded into more useful associative

    arrays.

    Indexing Documents with PHP

    While we can interact with the node using curl (and

    youll notice that the documentation online is entirely

    in curl + JSON requests), we ultimately want to use

    PHP to query Elasticsearch from within our application.

    Elasticsearch maintains an official PHP client which

    we will use for the rest of the article. The PHP clientis installed with Composer (see installation directions

    here [3]).Elasticsearch is a document-based system. Each doc-

    ument is simply a JSON object that contain the fields

    and values that you wish to store. The PHP client trans-

    parently converts associative arrays to JSON and back,

    so you never actually have to deal with raw JSON.

    In the first part of Listing 2, we create a document

    that has some data. Youll notice that $document

    contains a number of fields with different data types:

    strings, integers, arrays, and even objects. Elastic-

    search will accept all of these.Next we specify an indexwith a typeand an id. In-

    dices and types are basically logical namespaces to

    organize data. An Elasticsearch cluster can contain

    multiple indices, and a single index can contain multi-ple types. You can search across multiple indices and

    multiple types, at the same time, with no loss in per-

    formance. See this article [4] for more details about the

    nature of an index in Elasticsearch.

    Lastly, youll notice that when we index the data

    we didnt need to define a schema first. Elastic-

    search will auto detect the schema from your first

    document, which means you can prototype systems

    quickly and easily.

    Listing 2$client = new Elasticsearch\Client();

    $document = array(

    'name' => 'John Smith',

    'age' => 26,

    'hobbies' => array('biking', 'surfing'),

    'employer' => array(

    'name' => 'MegaCorp',

    'size' => 49293

    )

    );

    $params['body'] = $document;

    $params['index'] = 'company';

    $params['type'] = 'employees';

    $params['id'] = 'JohnSmith';

    $ret = $client->index($params);

    */

    Listing 1$ curl -L -O https://download.elasticsearch.org/elasticsearch/elasticsearch/

    elasticsearch-0.90.5.tar.gz

    $ tar -xzf elasticsearch-*.tar.gz

    $ cd elasticsearch-*

    $ ./bin/elasticsearch -f

    $ curl 'http://localhost:9200/?pretty'

    {

    "tagline" : "You Know, for Search",

    "ok" : true,

    "status" : 200, "name" : "Contrary",

    "version" : {

    "number" : "0.90.5",

    "snapshot_build" : false

    }

    }

    www.webandphp.com Web & PHP Magazine 11.13 | 6

    http://www.elasticsearch.org/blog/what-is-an-elasticsearch-index/http://www.elasticsearch.org/blog/what-is-an-elasticsearch-index/
  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    7/33

    TutorialElasticsearch

    Search

    Ok, so we've indexed a document. Lets do somesearching! In Listing 3, we are going to perform a sim-ple search for John. Elasticsearch has a number ofdifferent queries [5] that you can choose from, but inthis example we are using the Match Query [6].

    The Match Query is a good default choice, offeringa great search box experience with little configura-tion. In Listing 3 we are searching the companyindexand employeestype (which makes sense since that iswhere the document was indexed).

    The Match Query is defined in the body of thesearch request. It will search the namefield of everydocument for our query text. The search results comeback as a big associative array. The list of matchingdocuments (ranked by relevance score) is printed atthe end of Listing 3. You can see that our original doc-ument was matched, and the search result contains

    the entirety of the original document (plus some extrameta-data).

    Fuzzy Searching

    That example was kind of boring. Lets try somethingthat a database would struggle with: dealing with ty-pos. There are many ways to deal with typos in Elas-ticsearch depending on your requirements, but we aregoing to use the Match Query again. Youll soon learnthat the Match Query is basically the swiss-army knifeof Elasticsearch.

    The Match query can be configured to tolerate a

    certain amount of fuzziness when analyzing docu-ments. This operation allows a number of edits tobe made to the query.

    For example, if we replace the o in John with ana, that counts as a single edit. The default fuzzinessof 0.5 will allow one edit, and thus, Listing 4s querywill match the document even though Jahn is notstored in any document.

    This may seem expensive computationally: howcan you check typos without comparing every singlevalue in the index? Luckily, Elasticsearch uses somevery complicated Finite State Transducers that en-sure that the operation is performant and does not,in fact, do a simple table scan.

    Filtering Data

    The queries we have looked at so far all calculate rel-evance scores. Some results are more relevant thanother results, which is reflected with a higher score.

    In many queries, there are certain elements thatdont need relevance scoring. For example, a num-ber is either inside a range or it is not. There is noconcept of being more in the range it is just ayes/no answer.

    In these situations, you should use a filter [9]. Fil-ters perform the role of structured search in Elas-

    ticsearch, and are very efficient since they can skipthe entire scoring phase. Furthermore, Elasticsearchaggressively caches filter bitset [10] so that subse-quent filtering is even faster. Filtering documents is

    Listing 4

    $params = array();

    $params['index'] = 'company';

    $params['type'] = 'employees';

    $params['body']['query']['match']['name'] = array(

    'query' => 'Jahn',

    'fuzziness' => 0.5,

    );

    $results = $client->search($params);

    print_r($results['hits']['hits'][0]['_source']['name']);

    > John Smith

    Listing 3

    $params = array();

    $params['index'] = 'company';

    $params['type'] = 'employees';

    $params['body']['query']['match']['name'] = 'John';

    $results = $client->search($params);

    print_r($results['hits']['hits']);

    > Array

    (

    [0] => Array

    (

    [_index] => company

    [_type] => employees

    [_id] => JohnSmith

    [_score] => 0.19178301 [_source] => Array

    (

    [name] => John Smith

    [age] => 26

    [hobbies] => Array

    (

    [0] => biking

    [1] => surfing

    )

    [employer] => Array

    (

    [name] => MegaCorp [size] => 49293

    )

    )

    )

    )

    www.webandphp.com Web & PHP Magazine 11.13 | 7

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    8/33

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    9/33

    TutorialWordPress

    by Jason Lengstorf

    Shortcodes in WordPress [1] are a handy way to insertwrappers into our content for styling content withoutrequiring our clients to learn HTML. Unfortunately,WordPress has a few quirks when rendering short-codes that can introduce bugs in your layout.

    The Problem

    The easiest way to explain the issue is with an exam-ple. Lets say we want to add a wrapper around a block

    of text to highlight it. A logical solution is to add a short-code called [highlight], like so:

    [highlight]

    Content goes here...

    [/highlight]

    When this shortcode is processed, it adds a with the class highlight:

    function my_shortcode_highlight( $attr, $content )

    {

    return '' . $content . '';

    }

    add_shortcode('highlight', 'my_shortcode_highlight');

    The built-in WordPress wpautop filter will add junkmarkup to your output:

    Content goes here...

    These extra

    tags can result in extra margin andpadding, and its just generally ugly and undesirable.

    Clearing the books

    Quick tip: Remove

    crappy markup fromWordPress shortcodesClear up the messy HTML output produced by WordPress shortcodeswith Jason Lengstorfs handy function.

    Imagelicen

    sedbyIngramI

    mage

    www.webandphp.com Web & PHP Magazine 11.13 | 9

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    10/33

    TutorialWordPress

    The Fix

    Fortunately, the fix is pretty painless. All we have todo is add a quick filtering function to functions.phpandcall that filter in our shortcode function.

    Step 1: The Filtering Function: In functions.php, adda new function (Listing 1). What were doing here is

    setting up two regular expressions [2] (regex forshort) in $patternsas an array.

    The first regex, #^\s*

    #, starts at the beginning ofthe string (^), allows for zero or more whitespace char-acters (\s), then matches a closing paragraph tag ().This gets rid of the mismatched closing paragraph tagthat shows up before the shortcodes content.

    The second regex pattern, #

    \s*$#, looks for anopening paragraph tag (

    ) and zero or more whites-pace characters (\s) at the end of the string ($). Thisprevents the shortcode markup from having an emptyparagraph at the bottom, which is typically the culprit

    when formatting issues arise.

    Both patterns, when present, are replaced with anempty string thus removing them and the modi-fied markup is returned from the function. If the oneor both of the patterns are not found, no changes aremade and the markup is returned as usual.

    Step 2: Calling the Filtering Function: With the filter-

    ing function added, the next step is to include it in anyshortcodes that require filtering. As a general guide-line, any shortcode that wraps output with a tag (suchas a ) will need to be filtered.

    All we need to do to filter the output is run $contentthrough the copter_remove_crappy_markup()functionand use its return value stored in $clean instead:

    function my_shortcode_highlight( $attr, $content )

    {

    $clean = copter_remove_crappy_markup($content);

    return '' . $clean . '';

    }add_shortcode('highlight', 'my_shortcode_highlight');

    With the filter applied, our previously janky shortcodeoutput becomes a perfectly valid bit of HTML:

    Content goes here...

    TL;DR

    WordPress outputs crappy markup when using short-codes to add wrapper elements. We can correct the

    markup by adding a quick filtering function to our short-code declarations.

    Ps: If you like this tip, why not star it on Gist [3]?

    Listing 1

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    11/33

    TutorialImages in PHP

    by Robin Nixon

    Manipulating images is a tool that more and more webprogrammers are having to add to their repertoire dueto the growth of Web 2.0 and the requirement to makesites more social with thumbnails, avatars and so on.

    Websites for freelancers, for example, often needto support image uploads of photos of the freelancers

    themselves as well as of their work. Likewise auction,classifieds and other sites that sell products on behalfof the surfer need a way to accept an upload of theproducts for sale.

    But its not sufficient to simply support http fileupload, because images will be posted to you of allsizes and dimensions. Many of the latest digital cam-eras offer in excess of ten megapixels and the de-

    fault file sizes are very high resolution (thousands bythousands of pixels) and take up several megabytesof space.

    Therefore you need to be able to take uploaded im-ages and resize them to suitable dimensions for thewebsite in question, and also save them in the file for-mat of your choice. Along the way you may well needto either offer your users the opportunity to adjust the

    final image, or automatically do so yourself. This is par-ticularly necessary when you have resized an imagedown substantially to a thumbnail, as you will almostcertainly have to sharpen it.

    Before you start, though, you must ensure that yourweb (or development) server has the GD Lib [1] com-piled into PHP as that is the only way these functionswill work.

    Figure 1: PHP is much more than a simple scripting language its also an amaz-

    ingly powerful image processor

    Figure 2: With the GD Lib graphic library compiled in, PHP provides a wide sel ec-

    tion of image transformations

    Who needs Photoshop?

    Create your own picture

    processor in PHPUsing just a web server and the PHP scripting language, its easy to build a simpleimage editor with many of the features of top photo editing packages.

    www.webandphp.com Web & PHP Magazine 11.13 | 11

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    12/33

    TutorialImages in PHP

    Next the inputs are defined which include the fileto be sent (a browse button will automatically appearwhen the program is run), and the action to perform.This includes 14 items, whose actions you can tellfrom the code.

    Finally an option to also resize the uploaded file is

    given by offering the input of two fields, Wand Hforwidth and height. Then, once it's all done, the submitbutton is added and the form is closed.

    Saving the uploaded image

    The above code displays the html form required to up-load an image, perform one of 14 actions on it and/orresize the image. So you have a few things to do oncethe image arrives at the server, the first of which is topopulate the variables you will be using:

    $p = $_FILES['p']['name'];

    $a = $_POST['a'];$w = $_POST['w'];

    Figure 3: Using sophisticated resampling techniques PHP can redimension an

    image while keeping most of its integrity intact

    Figure 4: Whether you simply need to set an image to greyscale, or need more

    powerful tools, PHP has most of the graphics functions you need

    Listing 1

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    13/33

    TutorialImages in PHP

    $h = $_POST['h'];

    $t = "pic.jpg";

    $rn = rand(0, 65535);

    If a file has been uploaded, $pwill be the files con-tents. $awill be the action to perform on the file or

    No action if it is set to 0. If set, $w and $h containthe new width and height to apply to the image. $tisa simple string variable containing the name of the fileas saved to the server, while $rnis a random numberwhose use you will see later.

    But the variable that concerns you immediately is $pbecause, if it is set, an image has been uploaded andyou must deal with it as in Listing 2.

    The first thing to do after detecting that an imagewas uploaded is to save it as a file on the server usingthe value stored in $t(pic.jpg). The reason the .jpgextension is used here is because that is the format

    the image will be saved as for our internal use.To ensure this, the next few lines of code determine

    the type of image that was actually uploaded and thenconvert from that format to the PHP internal image for-mat, before then re-saving the image as a JPG file. Notethat there is no error checking here for any other mimetypes being uploaded. That is beyond the scope of thisarticle and something you will need to take into account.

    Anyway, on exit from this routine there is an elsestatement which will run if no image was uploaded.If this is the case, an attempt is made to load in a pre-viously saved image for further manipulation. This is

    because you dont want to keep re-uploading the mainimage to try different effects unless you wish to revertto the original one.

    Note the use of the @sign prefixed to the functioncall. This suppresses any error messages if no imagehas been uploaded yet. Because there is no room inthis tutorial to build in all the possible error checkingyou might need, this technique has been used in many

    places to ensure the program output is clean. If youintend other people to use any of this code you shouldfirst remove all the @signs in order to catch error mes-sages and decide how to handle them.

    Processing the image

    At this point you should now have an original imagestored on the server as pic.jpg, and loaded into PHPsimage workspace, ready to manipulate with the codein Listing 3.

    As you can see, many of the actions supported byour program are implemented using the imagefilter()function. This is built into the GD library used by PHPand offers a wide range of transforms, of which thisarticle only covers a few examples.

    The function takes the image to be manipulated, andan integer filter type and parameters which are some-times optional and sometimes mandatory, depending

    on the filter type.As a basic start point I have chosen values for these

    actions that seem reasonable and which can be appliedseveral times to achieve further changes. You maywish to experiment with the values to obtain resultsmore to your liking. Further details are in the box-outentitled Using imagefilter()and imageconvolution().

    The one exception is the use of the imageconvolution()function to obtain a sharpening effect. This has beenused as there is no sharpen filter type available for im-agefilter(). There are many other effects you can achievewith this function so it is also worth investigating further.

    Once execution of this code segment completes youshould have an image in memory ready to save backto the server. But first, theres a final test to make be-cause the user may have chosen to resize the image.

    Image resizing

    Simply dropping or adding vertical or horizontal linesto change an images dimensions is very messy to

    Listing 3switch($a)

    {

    case 1: @imageconvolution($s, array(array(-1, -1, -1),

    array(-1, 16, -1), array(-1, -1, -1)), 8, 0); break;

    case 2: @imagefilter($s, IMG_FILTER_GAUSSIAN_BLUR); break;

    case 3: @imagefilter($s, IMG_FILTER_BRIGHTNESS, 20); break;

    case 4: @imagefilter($s, IMG_FILTER_BRIGHTNESS, -20); break;

    case 5: @imagefilter($s, IMG_FILTER_CONTRAST, -20); break;

    case 6: @imagefilter($s, IMG_FILTER_CONTRAST, 20); break;

    case 7: @imagefilter($s, IMG_FILTER_GRAYSCALE); break;

    case 8: @imagefilter($s, IMG_FILTER_NEGATE); break;

    case 9: @imagefilter($s, IMG_FILTER_COLORIZE, 128, 0, 0, 50); break;

    case 10: @imagefilter($s, IMG_FILTER_COLORIZE, 0, 128, 0, 50); break;

    case 11: @imagefilter($s, IMG_FILTER_COLORIZE, 0, 0, 128, 50); break;

    case 12: @imagefilter($s, IMG_FILTER_EDGEDETECT); break;

    case 13: @imagefilter($s, IMG_FILTER_EMBOSS); break;

    case 14: @imagefilter($s, IMG_FILTER_MEAN_REMOVAL); break;

    }

    Listing 2

    if ($p)

    {

    move_uploaded_file($_FILES['p']['tmp_name'], $t);

    switch($_FILES['p']['type']) {

    case "image/gif": $s = imagecreatefromgif($t); break;

    case "image/jpeg": $s = imagecreatefromjpeg($t); break;

    case "image/png": $s = imagecreatefrompng($t); break;

    }

    @imagejpeg($s, $t);

    }

    else $s = @imagecreatefromjpeg($t);

    www.webandphp.com Web & PHP Magazine 11.13 | 13

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    14/33

    TutorialImages in PHP

    say the least. To best resize an image it needs to beresampled so that, whether you are adding or remov-ing data, it retains as much of its integrity as possible,

    as in Listing 4.To do this, the images current dimensions are

    looked up and stored in $tw and $th. Then a newworkspace is created in $s1with the width and heightspecified in the input.

    Given that data, the original image is then resam-pled to fill the new workspace and saved back to theserver using the imagejpeg()function. To return tempo-rary memory back to the server imagedestroy()is alsocalled.

    Youll notice that this code is only executed if $whas been defined. Again, this is a quick and dirty way

    to assume that a redimensioning is in order. No checkis made to see whether $wis sensible, and whether$heven exists, so garbage inputs will return garbageresults without suitable error checking being added.Finally, you are ready to display the image if it exists:

    @imagedestroy($s);

    if (file_exists($t)) echo "";

    First the temporary workspace used for the image isreturned to the server, then if the file pic.jpgexists onthe server it is displayed using the html tag.

    And now you can see the purpose of the $rnrandomvariable that was defined earlier. It is attached to the im-age URL in the form pic.jpg?rn=123to ensure that the

    web browser downloads and displays the image directlyfrom the server each time the program is run, rather thanfrom its cache which is what it would otherwise do.

    And if you string those segments together in sequenceand save them as the programpicproc.php, you will havea basic image editor in just a few lines of PHP. Using theprograms structure, you should easily be able to addplenty of additional functionality and new features.

    Listing 5

    $max = 100;

    $tw = $w;

    $th = $h;

    if ($w > $h && $max < $w)

    {

    $th = $max / $w * $h; $tw = $max;

    }

    elseif ($h > $w && $max < $h)

    {

    $tw = $max / $h * $w;

    $th = $max;

    }

    elseif ($max < $w) $tw = $th

    = $max;

    Listing 4

    if ($w)

    {

    list($tw, $th) = getimagesize($t);

    $s1 = imagecreatetruecolor($w, $h);

    imagecopyresampled($s1, $s, 0, 0, 0, 0, $w, $h, $tw, $th);

    imagejpeg($s1, $t);

    imagedestroy($s1);

    }

    else @imagejpeg($s, $t);

    @imagedestroy($s);

    Roll your own graphics features

    There are many ways you can improve thisprogram. Obviously, the first of which has

    been covered and that is to provide adequate

    error checking. When receiving uploads to a

    public web server its essential that you re-

    move any possibility of being hacked and for

    users to create strange and unwanted results.

    Features you could add include enlarging only

    parts of an image. For example you could use

    an image map of the picture as part of the in-

    put, and then the area surrounding the mouse

    click would be enlarged to fill the whole image.

    This is a technique often used to help users

    select thumbnails from larger images.

    Or you could just take parts of the project,

    many of which are handy in their own right.

    For example you could write a function to

    automatically resize an uploaded image to

    no more than either 100 pixels wide or high,

    whichever is the larger (or any amount you

    choose), and then sharpen the result (because

    the resampling usually has a blurring effect on

    thumbnails). To get you started, the piece of

    code in Listing 5 will do just that for you:

    Just set $maxto your preferred value, and

    ensure $wand $hare the current width and

    height of your image. This code will then set

    $twand $thto the correct proportional values

    required to ensure that, whether the image

    is portrait, landscape or square, the resulting

    thumbnail will be no greater than $maxpixels

    in its largest dimension. Just insert this code

    into the appropriate place in the program file.

    Or at the very least, if youve never used it be-

    fore, you could just take the file upload section

    and make use of it when CVs, databases or

    other files need to be uploaded to your server.

    www.webandphp.com Web & PHP Magazine 11.13 | 14

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    15/33

    TutorialImages in PHP

    Using imagefilter() and

    imageconvolution()

    The imagefilter()function provides a power-

    ful set of ready-made transformations you

    can use on images. The format of the func-tion call is:

    imagefilter($image, filtertype [, $arg1, ... $arg4])

    $imageshould be an image resource,

    there can be up to four arguments in $arg1

    through $arg4, and filtertypecan be any

    of the following:

    IMG_FILTER_NEGATE:

    Reverses all colours of the image IMG_FILTER_GRAYSCALE:

    Converts the image into greyscale

    IMG_FILTER_BRIGHTNESS:

    Changes the brightness of the image

    use $arg1to set the level of brightness

    IMG_FILTER_CONTRAST:

    Changes the contrast of the image

    use $arg1to set the level of contrast

    IMG_FILTER_COLORIZE:

    Like IMG_FILTER_GRAYSCALE except you

    can specify the colour use $arg1, $arg2&

    $arg3in the form of red, green & blue and

    $arg4for the alpha channel (The range for

    each colour is 0 to 255)

    IMG_FILTER_EDGEDETECT:

    Uses edge detection to highlight the

    edges in the image

    IMG_FILTER_EMBOSS:

    Embosses the image

    IMG_FILTER_GAUSSIAN_BLUR:

    Blurs the image using the Gaussian method

    IMG_FILTER_SELECTIVE_BLUR:

    Blurs the image

    IMG_FILTER_MEAN_REMOVAL:

    Uses mean removal to achieve a sketchy

    effect

    IMG_FILTER_SMOOTH:Makes the image smoother use $arg1

    to set the level of smoothness

    Sometimes imagefilter()will not have the

    exact transform you require but thats OK

    because you can create your own using im-

    ageconvolution(). For example, the follow-

    ing two function calls in turn emboss and

    sharpen an image based on a three by three

    matrix, which is applied across the whole

    image. Try changing the parameters to seewhat effects you can create there are

    examples in Listing 6.

    Everything you could want to know about the

    GD Image functions can be found online at [3].

    Listing 6

    imageconvolution($image,

    array(

    array(2, 0, 0),

    array(0, -1, 0), array(0, 0, -1)

    ), 1, 127);

    imageconvolution($image,

    array(

    array(-1, -1, -1),

    array(-1, 16, -1), array(-1, -1, -1)

    ), 8, 0);

    Robin Nixon is the author of Learning PHP, MySQL, JavaScript &CSS, the top-selling PHP web-development book since 2009. Formore information see lpmj.net or visit nixonpublishing.com to see

    some of Robins other books.

    References

    [1] http://php.net/manual/en/image.installation.php

    [2] https://gist.github.com/webandphp/6992461

    [3] http://php.net/manual/en/ref.image.php

    www.webandphp.com Web & PHP Magazine 11.13 | 15

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    16/33

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    17/33

    TutorialCSS

    by Ragnar Kurm

    Have you ever written CSS for a big website withmultiple layouts and found yourself lost in the grow-ing CSS files? Even if you have structured your files,the problem lies in how to work with multiple layouts

    side-by-side. So far I have not found any convincingproposal of how to approach the situation.

    I had a CSS project that took more than half a yearand I learned a lot during that time. Because I haveextensive background in programming, I took someprogramming tools to writing my CSS. This article cov-ers a workflow to work with multiple layouts side-by-side. On the way we learn many new approaches toworking with CSS. In all of these aspects I give only anintroduction, because complete references and tutori-als for each are already available. All of these methodsor steps can me used independently as well.

    Diagnosing an overweight stylesheet

    First, lets take a look what happens when a sitestyle grows big. There are variety of symptoms andindications:

    Some values repeat a lot. Maybe the most com-mon is the sites default color, used in back-grounds, titles, highlights, etc.

    In many places dependent values are used. These,as the name suggests, are values which dependon some other value. For example, if the content

    region is 75 % wide then the sidebar value will be25 % wide. So the sidebar value is derived from thecontent width.

    Some bits of CSS gets repeated here and there,like rounded corners.

    Browsers will take more time to render your page.Meaning that the page appears after a brief pauseonce loaded.

    Give it some SASS

    Compile Your Style:Smarter CSS

    Faced with a super-sized stylesheet, Ragnar Kurm developed a workflow forsimplifying, modifying and automating his CSS. In the first instalment of thistwo-part guide, he explores the features of preprocessor SASS and how to

    optimise your selectors.

    ImagelicensedbyIngramI

    mage

    www.webandphp.com Web & PHP Magazine 11.13 | 17

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    18/33

    TutorialCSS

    CSS files grow big which causes: Hard to orient in CSS Loss of overview Lack of structure Increasing danger that changing some value

    interferes something else

    Theming for multiple layouts (mobile, narrow, nor-mal, wide) becomes uncomfortable, because lay-outs live in separate files.

    Creating graphical elements for different layoutsrequires extra effort.

    Fortunately, there is remedy for all of that. There arefew tools and few concepts to be learned, but we willgo through it step-by-step. Any of these steps can beapplied alone or in combination to a theme of any size.

    Although it is not compulsory, I have created a smallboilerplate package [4] which I now use at every site Icreate. I find that it eases the job a lot.

    The Goal

    I found that keeping the style information for multiple

    layouts (different designs depending on screen size ormobile device) in different files is almost unmanage-able for me. So I started to look for a better way tohave good manageability and have a good overview atthe same time.

    The workflow I evolved is multiple layouts side-by-side, or MLSBS for short. It allows different layoutsto be put into one file, side-by-side, so that styling in-formation for a single element in different layouts isvisible at same time. Over time the methodology hasevolved, and nowadays if I start a new styling project Icannot imagine doing without it.

    Here is an example of how our styling informationmay appear side-by-side, in this case for logo ele-ment . Note that the syntaxwhich is used here is a preprocessor syntax, but prop-erty values are given verbatim.

    The Master Plan

    What do we need to learn in order to efficiently handlemultiple layouts? There are many steps, summarizedin Figure 1.

    In part one of the article, we will be exploring howto write smarter CSS, covering the following subjects:

    Style Preprocessor: SASS. A style preprocessor iscentral tool to achieve multiple layouts side-by-side.Preprocessors give dynamics to static CSS. In thecontext of this article, we are specifically interestedin conditionals.

    SASS plugin: Awareness of Environment. Inorder to guide the preprocessor externally, there is

    a requirement to be able to specify preprocessorvariables from the command line. Therefore wemust add a custom SASS plugin.

    Style and Evaluation: Matching and Specificity.Page rendering speed depends on many factors,and style complexity is one of them. Style complex-

    ity is determined by selectors. To write good selec-tors, one needs to know how the browser matchesselectors. Though this is not prerequisite to havemultiple layouts side-by-side, it is almost essentialto know when building big theme.

    In part two, we will explore ways to structure, compileand automate our style:

    Structuring: Splitting and Joining. To keep astyle modular there is a need to split the theme intosmaller pieces. But in order to avoid too many piec-

    es, these should be joined later on after compiling.

    Figure 1: The various elements of the MLSBS strategy

    Listing 1: The holy grail of MLSBS@if $LAYOUT == "all"

    #logo

    display: block

    background-position: center

    background-repeat: no-repeat

    @if $LAYOUT == "narrow"

    #logo

    width: 100px

    height: 100px

    background-image: url(logo-narrow.png)

    @if $LAYOUT == "normal"

    #logo

    width: 200px height: 200px

    background-image: url(logo-normal.png)

    @if $LAYOUT == "wide"

    #logo

    width: 300px

    height: 300px

    background-image: url(logo-wide.png)

    www.webandphp.com Web & PHP Magazine 11.13 | 18

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    19/33

    TutorialCSS

    I personally like to keep one selector per line, thoughthis is not a prerequisite. Having one selector per lineprovides a better overview and is easier to edit. Forexample, if there is an extra selector to be deleted, it isslightly easier to delete the entire line than a portion inthe middle. In the long run, less typing matters.

    Preprocessors have many powerful abilities: selec-tor nesting, variables, multiple data types, calculations,conditions, loops, style reuse with mixins, customfunctions, built-in functions and file inclusion. How canwe compile SASS to CSS? Easy:

    $ sass global.sass global.css

    Nestingis a way to write selectors. Child selectors areplaced under parent selectors. It avoids repeating com-mon parts of selectors and make HTML-CSS matchingmuch easier (Listing 3). It saves time, less typing, less

    errors, gives better overview and is cleaner way target-ing HTML elements.

    Listing 3: Nesting

    /* SASS source */

    #region-left,#region-right

    a:link,

    a:visited

    text-decoration: none

    color: green

    /* CSS result */

    #region-left a:link,#region-left a:visited,

    #region-right a:link,

    #region-right a:visited {

    text-decoration: none;

    color: green;

    }

    Listing 4: Variable examples

    $spacing_width: 10%

    $default_font_size: 1.5em

    $spacing: 16px

    $content: 800px

    $color_main: #aabbcc

    $color_second: rgba(255, 0, 0, 0.75)

    $path_img: '/files/images/'

    Listing 2: SASS example

    /* SASS source */

    $color_main: #3bbfce

    $content_width: 75%

    #region-content

    width: $content_width

    h1,

    a

    color: $color_main

    background-color: lighten($color_main, 50%)

    #region-sidebar

    width: 100% - $content_width

    Automated imagework with ImageMagick. Inorder to minimize manual image manipulation fordifferent screen sizes, it is convenient to use imagescaling on the fly from the command line.

    Media Queries. To be able to select between lay-outs, one needs to use media queries which then

    execute the respective style. This is not directlyrelated to the workflow, but is just a prerequisitefor choosing the layout from the client side.

    Automatics: Make/Makefile. To use all the stepsefficiently from the command line, we need to bindthem somehow. Makefile keeps track what needsto be done and carries out necessary operations.

    Style Preprocessor: SASS

    In my theming project there were many repeatedand dependent values, lots of repeated code andeven more things which were hardcoded, clum-

    sy and uncomfortable. As programmer I couldidentify many such problems and started to consid-er using things like C preprocessor or the M4 macrolanguage.

    Fortunately I found there is an excellent solution forthat CSS-specific preprocessors. There are few ofthem available and I picked SASS. The following intro-duction and examples are SASS-specific. SASS syntaxis the shortest of the different options, which I preferbecause it means less typing, fewer errors and a bet-ter overview.

    Preprocessors are built on top of CSS. Compiling

    your style results in plain CSS. It takes theming closerto programming instead of the continuous hardcodingof CSS.

    Available preprocessors are SASS [1], LESS [2] andStylus [3]. There is comprehensive documentationavailable about preprocessors so Ill give only a verybrief overview to give you an idea of how they work.You can see an example of SASS in action in Listing 2.

    /* CSS result */

    #region-content {

    width: 75%;

    }

    #region-content h1,

    #region-content a {

    color: #3bbfce;

    background- color: white;

    }

    #region-sidebar {

    width: 25%;

    }

    Variables are placeholders for values. Valuescan be of many data types like numbers, colors orstrings (Listing 4). Variables allow us to specify avalue once and use this throughout the theme. Theyare also handy for calculations. The following exam-ple gives an idea of how to define variables and what

    kind of values they can hold. Well cover their usagein a moment.

    Calculationsmeans combining one or more valuesor variables to get an altered or combined value. It ispossible to do arithmetic with dimensions, operationswith colors, combine strings to name some of the op-tions (Listing 5).

    www.webandphp.com Web & PHP Magazine 11.13 | 19

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    20/33

    TutorialCSS

    You dont need to use a calculator to getdimensions right, nor use GIMP or ColorZillato get a darker shade of your main color. Thewhole thing becomes dynamic.

    Conditional statementscheck some valueand, based on that, executes one (or another)

    piece of code selectively (Listing 6). Thoughnot used often, they are prerequisite for MLSBS.

    Loopscause a certain piece of code to be executedrepeatedly. Usually there is a variable that keeps trackhow many cycles are done. Loops are useful to gener-ate sequences (Listing 7).

    Style reuse mixins are piece of style that are in-corporated into style. It allows to reuse a common

    code optionally based on arguments generate vari-ations. It helps to get rid of non-semantic selectorsand code repetition (Listing 8).

    Custom functionsare pieces of codethat calculate some value and return it(Listing 9). They are more useful for cal-culations rather than defining styles.

    Built-in functionsare provided by thepreprocessor for data manipulation (List-ing 10). There is a load of different kindsof built-in functions, for example colormanipulation, transparency manipulation,

    arithmetic function, list functions etc.File inclusionmeans loading the con-

    tents of one file into another. The mostcommon use-case is probably to have afile with global definitions, used like this:

    @import "colors.sass"

    @import url("http://fonts.googleapis.com/

    css?family=Droid+Sans");

    SASS plugin: Awareness of Environment

    In order to achieve MLSBS, there is a

    need to be able to read the context inwhich it is being compiled specifi-cally, to access environment variablesto distinguish which layout is currentlybeing compiled.

    A custom plugin is the best way toachieve this, and it is relatively easy tocreate your own plugins. Heres an ex-

    Listing 7: Loops

    /* SASS source */

    $size: 2em

    @for $i from 1 through 6

    h#{$i}

    font-size: $size

    $size: 0.9 * $size

    /* CSS result */

    h1 { font-size: 2em; }

    h2 { font-size: 1.8em; }

    h3 { font-size: 1.62em; }

    h4 { font-size: 1.458em; }

    h5 { font-size: 1.312em; }

    h6 { font-size: 1.181em; }

    Listing 5: Calculations

    /* SASS source */

    #frame

    width: ($spacing + $content + $spacing)

    color: darken($color_main, 10%) background-image: url($path_img +

    'logo.jpg')

    /* CSS result */

    #frame {

    width: 832px;

    color: #8aa2b9; background-image: url("/files/images/

    logo.jpg");

    }

    Listing 6: Conditions

    /* SASS source */

    $page_width: 800px

    $content: 800px

    $sidebar: 220px

    @if $content + $sidebar != $page_width

    @warn "Content #{$content} + Sidebar #{$sidebar} must match page width

    #{$page_width}"

    /* Output error message: */

    WARNING: Content 800px + Sidebar 220px must match page width 800px

    on line 6 of a.sass

    Listing 8: Mixins

    /* SASS source */

    @mixin rounded($RADIUS)

    border-radius: $RADIUS

    -webkit-border-radius: $RADIUS

    -moz-border-radius: $RADIUS

    -o-border-radius: $RADIUS

    -khtml-border-radius: $RADIUS

    .block

    @include rounded(20px)

    /* CSS result */

    .block {

    border-radius: 20px;

    -webkit-border-radius: 20px;

    -moz-border-radius: 20px;

    -o-border-radius: 20px;

    -khtml-border-radius: 20px;

    }

    Listing 9: Custom functions

    /* SASS source */

    @function gallery-width($cols, $width,

    $padding)

    @return $cols * ($padding + $width +

    $padding)

    .gallery-1

    width: gallery-width(5, 100px, 10px)

    .gallery-2

    width: gallery-width(10, 400px, 5px)

    /* CSS result */

    .gallery-1 { width: 600px; }

    .gallery-2 { width: 4100px; }

    www.webandphp.com Web & PHP Magazine 11.13 | 20

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    21/33

    TutorialCSS

    ample plugin which imports and uses environmentvariables. First, create the file env.rb(this Ruby scriptis the entire plugin (Listing 11)).

    To include the plugin, SASS needs to be executedlike this:

    $ sass ... --require env.rb ...

    How could it be useful? For example, if you have a dif-ferent color scheme for the development site and forthe production site. It helps to be more aware whereyou are doing your changes and not to mix them up.Assume that you have set the environment variableSTAGE=devel(Listing 12).

    Compilation in this case would be:

    $ STAGE=devel sass --require env.rb tags.sass tags.css

    This is one way to feed an environment variable toSASS, but there are other options as well like specify-ing environment variables from the shell login profile.

    CSS evaluation by browserAs a theme or CSS file grows, it starts to require morebrowser resources for rendering,and the browser may hang for a mo-ment before the page appears. Howcan we combat that? First, thereare many sophisticated tools whichhelp you analyze CSS evaluation. Inaddition to that, there are two con-cepts which are worth understand-ing selector matching and selectorspecificity. As there is already lots

    of information available on this, I willprovide only the most essential tips.

    Selector matching

    How does a browser match selec-tors against HTML? Browsers readselectors from right to left. I repeat,right to left. This might be a bit coun-ter-intuitive at first glance, but this ismost practical way.

    Processing each element in a se-lector takes resources. Therefore the

    fewer elements, the better. Also, fail-ing rules are quicker than matchingrules (Listing 13).

    Selector specificity

    In order to write good selectors ithelps to know about selector speci-ficity. If selectors have too low

    Listing 13: Selector matching speed

    #main-navigation { } /* ID (Fastest) */

    body.home #page-wrap { } /* ID */

    .main-navigation { } /* Class */

    ul li a.current { } /* Class */

    ul { } /* Tag */

    ul li a { } /* Tag */

    * { } /* Universal (Slowest) */

    #content [title='home'] /* Universal */

    #main-nav > li { } /* Slower than it might seem */

    ul#main-navigation { } /* Don't */

    html body ul li a { } /* Worst */

    /* Credit: Chris Coyier, http://css-tricks.com/efficiently-rendering-css/ */

    Listing 10: Built-in functions

    /* SASS source */

    $color: #123456

    .element

    color: grayscale($color)

    background-color: rgba($color, 0.5)

    width: round(100px/3).element:hover

    color: $color

    /* CSS result */

    .element {

    color: #343434;

    background-color: rgba(18, 52, 86, 0.5);

    width: 33px;

    }

    .element:hover {

    color: #123456

    }

    Listing 12: Making use of the environment variable

    /* SASS source */

    $STAGE: env(STAGE)

    @if $STAGE == "devel"

    body

    background-color: blue

    @if $STAGE == "live" body

    background-color: green

    /* CSS result */

    body {

    background-color: blue;

    }

    Listing 11: SASS plugin env.rb

    module SASS::Script::Functions

    def env(var) assert_type var, :String

    SASS::Script::String.new(ENV[var.to_s()])

    end

    end

    www.webandphp.com Web & PHP Magazine 11.13 | 21

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    22/33

    TutorialCSS

    www.webandphp.com

    specificity, they will match too many elements. If aselector is too specific it will be difficult to be over-ridden later on if necessary. According to the CSS3specification: A selectors specificity is calculated asfollows:

    count the number of ID selectors in the selector(= a) count the number of class selectors, attributesselectors, and pseudo-classes in the selector (= b)

    count the number of type selectors and pseudo-elements in the selector (= c)

    ignore the universal selector

    Concatenating the three numbers a-b-c (in a numbersystem with a large base) gives the specificity.Often it is easier to understand these rules just by look-ing at examples. Listing 14 is also from the CSS3 spec.

    Application

    How can we apply these concepts to our own work?Most of the time, the selectors I use consist of oneelement which is usually an ID or a Class. Heres anexample:

    ...

    ...

    Here is a style example that matches above HTML:

    .my-grid-td { padding: 10px; }

    .my-grid-tr:hover { background-color: grey; }

    .my-grid { width: 100%; }

    #the-grid { border: 3px solid red; }

    Listing 14: Selector specificity

    * /* a=0 b=0 c=0 -> specificity = 0 */

    LI /* a=0 b=0 c=1 -> specificity = 1 */

    UL LI /* a=0 b=0 c=2 -> specificity = 2 */

    UL OL+LI /* a=0 b=0 c=3 -> specificity = 3 */

    H1 + *[REL=up] /* a=0 b=1 c=1 -> specificity = 11 */

    UL OL LI.red /* a=0 b=1 c=3 -> specificity = 13 */

    LI.red.level /* a=0 b=2 c=1 -> specificity = 21 */

    #x34y /* a=1 b=0 c=0 -> specificity = 100 */

    #s12:not(FOO) /* a=1 b=0 c=1 -> specificity = 101 */

    Next month

    In this first part, weve looked at writing smarter CSSwith the use of a preprocessor, a custom plugin andperformance-aware selectors. In the next issue, well

    consider how best to structure our SASS files, andhow to automate every aspect of our style fromSASS compilation to image formatting. Finally we seehow all these methods fit together to have multiplelayouts, side-by-side.

    Ragnar Kurm began programming in his teens and later studiedInformatics at Tallinn Technical University. He currently runs hisown company, and before that worked for 10 years at an ISP. Rag-nar has extensive programming experience in all major languages(ca 20-30) and continues to learn. In recent years, he has spent

    the majority of his time building webpages, but he loves backend program-

    ming most.

    References

    [1] http://sass-lang.com/

    [2] http://lesscss.org/

    [3] http://learnboost.github.io/stylus/

    [4] https://github.com/ragnarkurm/compile-your-style

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    23/33

    FeaturePHP equality

    by Sharon Lee Levy

    One of the questions posed during the Q&A periodof my talk PHP: Quirks, Gotchas & Wizardry [1] atthe Web and PHP Conference, September 2013 con-cerns how to apply the equality operator appropriately,in light of its potential for misuse. The question raisesanother why does PHP even bother to retain thatoperator?

    PHP has two operators to test for equality, == and

    ===, respectively equalityand identity, similar toJavaScript. Douglas Crockford in his book JavaScript:The Good Parts advocates that users avoid double-equals which he deems as evil. He claims that ==and != present issues because they attemptto coerce the values. The rules by which they do thatare complicated and unmemorable. His words mightalso describe the corresponding PHP counterparts if

    you review the equality comparison tables [2]. A note-worthy difference between equalityin PHP and thatof JavaScript involves comparing null with false whichyields true in PHP but false in JavaScript.

    Years ago, PHP developers favored equalityfar morethan identity. Since the double-equals symbol occurs in

    math as well as the C programming language, often partof the skill set of PHPs early adopters, the bias naturallyappeared. Nowadays, after misadventures in PHPland,you may hear developers advocate vigorously for replac-ing the loosely-typed equalitywith the stricter identity,suggesting that otherwise there may be hell to pay.

    The following snippet, devoid of hashing for simplic-itys sake, vividly illustrates the potential peril of codingwith ==:

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    24/33

    FeaturePHP equality

    sues. Core contributor Gustavo Lopes resolved thematter by modifying the Zend engines zendi_smart_strcmpto adhere to the following rule annunciated in asubsequent related discussion [5]:

    If both strings look like integers (no decimal sepa-rator nor exponent) but they were both converted to

    doubles because of being too large in absolute value, ifthey both compare equal in a double comparison, andif theyre both larger than 2^53-1 in absolute value,then compare them as a string.

    This description should have reassured users aboutthe reliability of equalitybut the fallout from this epi-sode may have soured some on double-equals.

    Applicability of Equality

    One should keep an open mind; sometimes equalityoffers the best choice. Suppose you were to compareobjects, as in Listing 1.

    Since $objAand $objBare instances of the sameclass rather than referring to the same object, the onlysensible basis for comparison involves equality. Bymeans of ==, PHP saves you from having to manu-ally check whether the instances share the same prop-erties and values. Changing the color of $objCaffects$objA, of course, destroying the equivalency of $objAwith $objBsince these instances now differ in theirrespective color value.

    The other scenario for == involves numeric stringswhich web applications encounter in data sent via thehttp protocol, i. e. form data which whether originally

    character-based or numeric, comes across as text. Da-tabases, too, return data regardless of type generallyas strings. Using the == simplifies the task of com-paring numbers with strings, as in Listing 2.

    If the code were to use === the first song titlewould fail to display since the expression would evalu-ate as false. The double-equals greatest utility consistsin permitting you to conveniently compare different

    data types with each another. In the following exam-ple, I have some code in Python 2.51 as follows:

    name = "Wanda"

    print "W"+"anda" # Wanda

    print name is "W"+"anda" # true

    print name == "W"+"anda" # true

    Ive moved it over to PHP for kicks with the leastamount of tampering:

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    25/33

    FeaturePHP equality

    not transitive in PHP, must you scrupulously avoid itsuse? Mercifully, PHP compensates by allowing you toalter the context to obtain the desired result. Considerthe following:

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    26/33

    FeaturePHP equality

    Then, one could modify is_numeric_string_exby de-claring the following variables:

    char space_chars[] = { WHITESPACE };

    int i, length = 0;

    The last step consists of revising the skipping whitespace code as follows:

    length = strlen(str);

    for ( i=0; i

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    27/33

    FeaturePHP equality

    the section that begins with if(!converted) {[18] andyoull see a conditional that matches what we have:

    else if (Z_TYPE_P(op2) == IS_BOOL) {

    zendi_convert_to_boolean(op1, op1_copy, result);

    ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2)));

    return SUCCESS;

    }

    Since the second operand is a Boolean value, theMACRO zendi_convert_to_boolean converts thestring. The next line performs the comparison, allow-ing for return values of 0, 1, or -1, which respective-ly correspond to $a being equivalent to $b, or elsegreater than or inferior to $b. One quick commentabout zendi_convert_to_boolean. The code for thisfunction explains why 0 fails to evaluate as truedespite containing a value. Inspecting a portion of

    the MACRO [19] in Listing 6 reveals that this choice,rather than mandated by logic, derives from a designdecision.

    Beyond the Code

    Equality in PHP is really about equivalence morethan anything else. This notion is further reflected intodays PHP Community. Predominantly male con-tributors flock to the PHP Internals List. Or, somemay prefer to congregate on the PHP-FIG forum.Separate groups, equivalent to the extent that theyare both devoted to improving PHP, but they are not

    identical in purpose.As for the women, where do they go? By in large,

    they interface vis a vis the PHPWomen IRC. Unlike theother two major groups, PHPWomen traditionally hasfocused as a support group mainly for female usersalthough male developers have joined, too.

    Imagine someday a convention with all threegroups in attendance! Who knows how the equality

    factor in the community might fare as the result ofsuch a catalytic experience? The PHP Community asa whole might gain tremendous benefit from such asynergy!

    References

    [1] http://webandphp.com/conference/

    PHP%3AQuirks%2CGotchas%26Wizardry

    [2] http://php.net/manual/en/types.comparisons.php

    [3] http://www.phpsadness.com/sad/47

    [4] https://bugs.php.net/bug.php?id=54547

    [5] https://bugs.php.net/bug.php?id=62097

    [6] http://me.veekun.com/blog/2012/04/09/php-a-fractal-of-bad-design/

    [7] http://www.phpwtf.org/its-quite-logical

    [8] http://us2.php.net/manual/en/function.sort.php

    [9] http://markmail.org/message/ymzzvyhyf32fldiu

    [10] http://lxr.php.net/xref/PHP_5_5/Zend/zend_operators.h#116

    [11] http://blog.paulbiggar.com/archive/introducing-malicious-code-reviews/

    [12] http://gcc.gnu.org/onlinedocs/cpp/Macro-Arguments.

    html#Macro-Arguments

    [13] http://us1.php.net/manual/en/function.array-values.php

    [14] http://blog.ircmaxell.com/2012/07/the-anatomy-of-equals-opcode-analysis.html

    [15] http://3v4l.org/T386t/vld#tabs

    [16] http://lxr.php.net/xref/PHP_5_5/Zend/zend_operators.h#872

    [17] http://lxr.php.net/xref/PHP_5_5/Zend/zend_operators.c#1457

    [18] http://lxr.php.net/xref/PHP_5_5/Zend/zend_operators.c#1582

    [19] http://lxr.php.net/xref/PHP_5_5/Zend/zend_operators.c#zendi_convert_

    to_boolean

    Other Links of Interest

    http://php.net/manual/en/language.oop5.object-comparison.php

    http://php.net/manual/en/language.operators.comparison.php

    http://stackoverflow.com/questions/80646/how-do-the-equality-double-

    equals-and-identity-triple-equals-comparis

    http://stackoverflow.com/questions/589549/php-vs-operator

    http://slevy1.wordpress.com/2013/09/17/web-php-conference-2013-talk-

    resources/

    Sharon Lee Levy is a Zend Certified Engineer in PHP5, equallycomfortable working with UNIX, Linux or Windows platforms. Heraccomplishments in public speaking include dynamic, multi-me-dia presentations at code camps, PHP meetups and technicalconferences, most recently at OSCON in July 2013 followed by

    the Web and PHP Co nference, Sep t 2013. php |architect ha s published s ev-eral of her articles on subjects ranging from email verification to web-basedretrieval, to PHPs support for closures. Most recently, she guest-bloggedfor Zends DevZone on PHPs Remarkable Hexadecimals. She previouslyconducted a webinar for Zend Technologies, reprising her UnCon SessionThe Truth about Lambdas and Closures in PHP (Sept 2011) in March 2012.Writing and public speaking activities compliment her primary focus, pro-viding professional web development services for companies in diverse in-dustries, from startups to the Fortune 500.

    www.webandphp.com Web & PHP Magazine 11.13 | 27

    http://lxr.php.net/xref/PHP_5_5/Zend/zend_operators.c#zendi_convert_to_booleanhttp://lxr.php.net/xref/PHP_5_5/Zend/zend_operators.c#zendi_convert_to_booleanhttp://slevy1.wordpress.com/2013/09/17/web-php-conference-2013-talk-resources/http://slevy1.wordpress.com/2013/09/17/web-php-conference-2013-talk-resources/http://slevy1.wordpress.com/2013/09/17/web-php-conference-2013-talk-resources/http://lxr.php.net/xref/PHP_5_5/Zend/zend_operators.c#zendi_convert_to_boolean
  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    28/33

    ColumnBig Data

    In an earlier column, I reviewed some of the basictypes of DBMS engines. Well, in this ever-expanding,rapidly changing field of Big Data there are more typesthat deserve to be part of the discussion. In this article,I will cover Column Databases, a great solution for datawarehouse type applications.

    What is a Column Database?

    Its easiest to understand how a Column Database

    works by comparing it to traditional RDMBS engines.As you know, traditional RDBMS engines store data ina row-based fashion, like in Table 1.

    This structure works very well for transactional appli-cations as all data for each unique row is stored togeth-er. You can see that it is very convenient for adding,updating or retrieving a single customer row at a time,like the examples in Listing 1.

    This type of thing works fine, performs well and willgo as fast as the RDBMS can process single row readsand writes.

    But what happens in the analytic case, when youneed to scan lots of rows to find specific informationor summarize data?

    Here is an example query that can be very expensivewith a row-based structure:

    SELECT type, COUNT(*)FROM customer

    WHERE start_date BETWEEN '1/1/2013' AND '3/31/2013'

    GROUP BY type;

    This type of query often causes a table scan, unlessyou add an index on the key field (start_datein thiscase). Even then it can still take a lot of processing,

    because a lot of data in the row-based structure mustbe scanned and read. To make matters worse, whathappens when you have a table with many columnsand you run complex queries across several columnvalues? Its not practical to index them all as it slowsdown writes, plus the RDBMS can only effectively

    use one or two indexes to limit the number of rowsto scan. This is all very important when it comes toBig Data scale for analytics, tables with 10s of Mil-lions to Billions of rows.

    Bio

    Cory Isaacson is CEO/CTO of CodeFutures

    Corporation. Cory has authored numerous

    articles in a variety of publications including

    SOA Magazine, Database Trends and Applica-tions, and recently authored the book Software

    Pipelines and SOA. Cory has more than twenty

    years experience with advanced software ar-

    chitectures, and has worked with many of the

    worlds brightest innovators in the field of high-

    performance computing. Cory has spoken at

    hundreds of public events and seminars, and

    assisting numerous organizations address the

    real-world challenges of application perfor-

    mance and scalability. In his prior position aspresident of Rogue Wave Software, he actively

    led the company back to a position of profitable

    growth, culminating in a successful acquisition

    by a leading private equity firm. Cory can be

    reached at: [email protected].

    Up to 100 times as fast as relational databases, column databases

    are the perfect choice for storing large, unchanging datasets.

    Column databases

    overviewby Cory Isaacson

    www.webandphp.com Web & PHP Magazine 11.13 | 28

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    29/33

    ColumnBig Data

    Introducing the Column Database

    A Column Database is designed to addressthis exact situation. As you probably haveguessed, a Column Database stores data bycolumn, instead of by row. The data is storedseparately for each column, with pointers

    back to the logical row that the value belongs too.Tables 2 6 illustrate what a column database struc-ture might look like.

    Why does this work better for analytic queries? Thereare many factors, and some depend on the specificimplementation of the column database engine itself.Here are some of the basic points that are important:

    A column database can answer a query (like theCOUNT/GROUP BY query above) very efficiently.The way it works is it can scan a single columntofind the values it needs, determine which rows

    match that query, and then further filter by othercolumn values. If you consider it this way, a Col-umn Database is really a set of indexes, one foreach column.

    Column data can be compressed using variousalgorithms, making the data much smaller. Thisis particularly true based on the cardinalityof thecolumn (i. e., the number if uniquevalues in a sin-gle column). Low-cardinality columns (those witha small number of unique values) can compressextremely well, and be searched very quickly.High-cardinality columns (those with many unique

    values) will take longer to search, but still may becompressed, and because the scan is of a singlecolumn results can be produced much faster.

    Lets look at a slightly more complex query. Note: I amusing SQL for the example queries, but not all columndatabases use the SQL language, some have otherlanguages or query syntax:

    SELECT type, zip_code, COUNT(*)

    FROM customer

    WHERE start_date BETWEEN '1/1/2013' AND '3/31/2013'

    GROUP BY type, zip_code;

    In this query, we now have two columns we are

    grouping by: type and zip_code. A Column Databasecan perform this very effectively: first scanning oneof the columns (lets say zip_code), then taking thatlist of row numbers and filtering again by the sec-ond column (type). The results then must be sorted,again an easier operation because the data valuesare evaluated independently.

    Thus, the result can be returned extremely quickly,even with a large number of rows. In practice, wehave seen Column Databases out-perform a traditionalRDBMS by up to 100:1 they can be really fast for theright types of operations.

    Things to Consider about Column Databases

    Because of the way Column Databases are struc-tured, you cannot work with them in the same wayas your traditional RDBMS. Here are some of the im-portant points:

    Data normally should be bulk-loaded in big chunksof rows (typically 1000 or more rows in a chunk). AColumn Database must do a lot of work to build thecolumn structure when new data is added, includ-ing compressing column information. You should

    not use it in a transactional manner, adding one rowat a time. Therefore, Column Databases work bestfor the analytics use case, like a data warehouse ofhistorical, non-changing data.

    Extracting your data can be slow. If you need todump data out of a column database, depending onthe particular engine implementation, the processcan be far slower than what you would expect. The

    Row zip_code

    1 11111

    2 22222

    Table 6

    Row type

    1 Premium

    2 Standard

    Table 5

    R ow s ta rt_ da te

    1 3/1/2013

    2 4/5/2011

    Table 4

    Row customer_name

    1 Acme, Inc.

    2 XYZ Corp

    Table 3

    Row customer_id

    1 1

    2 2

    Table 2

    customer_id customer_name start _dat e t ype z ip_code

    1 Acme, Inc. 3/1/2013 Premium 11111

    2 XYZ Corp 4/5/2011 Standard 22222

    Table 1: Example customer table in a row based structure

    Listing 1

    INSERT INTO customer (customer_id, customer_name, start_date, type, zip_code)

    VALUES

    (3, 'Unlimited Enterprises, Inc.', '5/1/2013', 'Economy, 33333);

    UPDATE customer

    SET zip_code = 44444

    WHERE customter_id = 2;

    SELECT *

    FROM customer

    WHERE customer_id = 3;

    www.webandphp.com Web & PHP Magazine 11.13 | 29

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    30/33

    ColumnBig Data

    www.webandphp.com

    reason is that the column database must uncompress and reassemble itscolumn structure back into a row-based format.

    Some Column Database vendors support Materialized Views, which are pre-summarized or pre-computed complex queries stored for the next use. Thesecan be very effective if you have a lot of similar or identical queries in your usecase.

    Column Databases need a lot of memory. This is due to the fact that theywork best when data for a given column can fit in RAM. Therefore, the hard-ware requirements may be different that your traditional database.

    Wrapping it up

    In this article, I have provided a basic tour and description of how Column Da-tabases work. These DBMS engines are a powerful weapon on the Big Dataarsenal, especially for heavy analytics use cases. Integrating a Column Databaseinto your overall Big Data architecture can provide a very successful strategy formeeting this type of requirement.

    In future articles I will continue to review various types of DBMS engines, and

    then begin to cover some specific vendors and their capabilities.

    1/2 dev.press

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    31/33

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    32/33

    ColumnCommunity

    The room was already filled with people, even if not allof the seats were taken yet. The conference speakerwas setting up his laptop to work with the projector.The topic of the talk was promising, and the speakersreputation impeccable. We were all looking for a talkthat might have been the highlight of the day. Then,

    all of a sudden, a few union workers showed up andstarted to remove the PA.

    The speaker started his session. Talking to a roomfilled with around 100 people without amplificationsoon began to take its toll on the speakers voice. Sincemy eyesight is pretty bad, and I usually want to be ableto read the slides, I was sitting in one of the front rows,so I could still understand the speaker. Maybe I was

    not even paying too much attention, because I wasfollowing the conferences Twitter stream.

    At the time, using Twitter during a conference wasstill fancy, if only because wireless internet connectiv-ity is notoriously bad at so many IT conferences. In oneof the tweets, another attendee of the very session I

    was sitting in, complained that the speaker was hardlyaudible in the back rows.

    This is actually a true story, one I have frequentlyused to amuse myself and others. Why would some-body tell this to the whole world, that, not unsurpris-ingly, is rather remotely interested in such information,instead of raising their hand and politely asking the pre-senter to speak up (which in fact, I did, acting as a

    Twitter proxy). Two people in the same room shouldprefer direct human-to-human communication over so-cial media, after all. Or should they?

    This year, when I was (once again) speaking atan IT conference, the conference organizer had an-nounced that they would make use of a great new

    service that some new startup company had created.This service would allow attendees to ask questionson a session they listen to. And they would be ableto use their smartphone to do this. As an additionalbenefit, other attendees can vote on questions theyalso think are worth while. At the end of the session,the speaker was to visit a web page (or use an app)to retrieve the questions asked.

    I was really curious. Would people use the sys-tem? Had the time of we do not need to speak toeach other while staying in the same room finallycome? Turns out not. To my knowledge, none of the

    attendees had used the system in any of the othersessions as well. To be very frank with you, I am notreally sad about this.

    Social media has its place and all that, but when westop talking to each other in person, even when weare gathered together in one location, things start go-ing really, really wrong. There is a good reason why Iprefer to speak to a live audience (well, multiple rea-

    Bio

    Stefan Priebsch unites expert knowledge with

    an extraordinary sense of when to use which

    tool. His specialities are object-oriented de-

    velopment and software architecture. As an

    internationally-acclaimed author and speaker

    he thrills auditoriums and likes to share his

    tremendous practical experience.

    For all the wonders of digital media, lets not forget the importance ofspeaking in person, writes frequent conference-goer Stefan Priebsch.

    Talks and the power

    of human interactionby Stefan Priebsch

    www.webandphp.com Web & PHP Magazine 11.13 | 32

  • 8/13/2019 Issue No. 20 (November 2013) - Searching High and Low

    33/33

    ColumnCommunity

    sons, actually). I have done a few webinars, and wasnever really happy with them. You miss out on theinteraction with attendees. You lack the non-verbalfeedback, which is so important in helping you to ei-ther slow down or pace up based on the reactions ofthe listeners. Let me tell you: talking to your monitor

    is very different from talking to live persons.

    Dear technology geeks: please do not let us forget

    that one of the last reasons why we still travel fromtime to time is so that we are able meet with otherpeople. We want (and need) to interact with them, ata personal level. Once attendees can ask their ques-tions online, why should they even attend the liveevent in the first place? Will the next big thing be pre-senters who answer the questions online instead ofverbally? Will we answer to nobody in particular byjust typing back? This means that we would missout on the non-verbal feedback that is so crucial forfiguring out whether somebody is satisfied with theanswer, or maybe has trouble understand is, requiring

    further clarification.I have seen online discussions go completely awry.

    Browse through the PHP internals mailing list archiveif you want good examples. I know people who areincredibly nice in person, but are extremely difficultto communicate with online. And as a consultant, Ihave seen teams discussing features and implemen-tations through commit messages and the comment

    functionality of a collaboration plat form even thoughthey all sat in the same room all day.

    Human communication comprises of a verbal anda non-verbal part. Researchers have stated differentratios between verbal and non-verbal communica-tion, but all of them seem to agree that the latter hasa share of more than 50 %. This is why communicat-ing online is far easier to misread or misinterpret thendirect human interaction. In online communication, welose most of our means of expressing ourselves, andthe means to understand the other party. We shouldnever do this without a very good reason.

    About

    Publisher

    Software & Support Media Ltd

    Editorial Office Address

    86 Great Suffolk StLondon SE1 0BE

    www.sandsmedia.com

    Editor: Elliot Bentley ([email protected])

    Authors:Cory Isaacson, Ragnar Kurm, Jason Lengstorf,

    Sharon Levy, Robin Nixon, Stefan Priebsch, Zachary Tong

    Creative Director: Jens Mainz

    Layout: Tobias Dorn, Petra Rth

    Sales:

    Ellen May

    +44 207 199 6234

    [email protected]

    Contents copyright 2013 Software & Support Media Ltd.All rights reserved. No part of this publication may be repro-

    duced, redistributed, posted online or reused by any means in

    any form, including print, electronic, photocopy, internal network,

    Web or any other method, without prior written permission of

    Software & Support Media Ltd.

    The views expressed are solely those of the authors and do

    not reflect the views or position of their firm, any of their

    clients, or Publisher. Regarding the information, Publisher dis-

    claims all warranties as to the accuracy, completeness, or ade-

    quacy of any information, and is not responsible for any errors,

    omissions, inadequacies, misuse, or the consequences of us-

    ing any information provided by Publisher. Rights of disposal of

    rewarded articles belong to Publisher. All mentioned trademarks

    and service marks are copyrighted by their respective owners.

    Will the next big thingbe presenters who answerthe questions onlineinstead of verbally?