Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Events
Videos
Audiobooks
Packt Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials

7019 Articles
article-image-video-editing-blender-using-video-sequence-editor-part-2
Packt
19 Feb 2010
7 min read
Save for later

Video Editing in Blender using Video Sequence Editor: Part 2

Packt
19 Feb 2010
7 min read
Video Sequence Editor (The Main Dish) Since we’ve been always using Blender’s default screen for modeling, setting up materials, or node compositing, let’s try to deviate for a moment and make use of Blender’s screen features to jump from one preset to another, which is a very useful tool in my opinion. Moving your attention over to Blender’s main menu (located at the very top of the window, below the header), you’ll notice the drop-down menu with a prefix of SR: at the beginning. This is Blender’s screen system which can come in handy anytime you want to switch to any preset view or customized view, quickly! You can click on the box itself with the text to edit the name of the screen you currently have, or you can use the dropdown button to either add a new screen or to choose between the selection. Right now we don’t have the diligence to create a new and customized screen since the presets are already of best use. Clicking the drop-down button, you’ll be presented with different screen names, of which, we will be selecting the fourth one labeled 4-Sequence. Instantaneously, after confirming your selection, your Blender screen will be warped to yet another spaceship-like interface, don’t worry though, we’ll get used to it pretty much soon. Changing Screen Layouts On the upper left hand corner, we have our IPO window which is used to add refined and custom controls over the behavior of our strips/inputs, on its right is the preview window, on the middle part is the VSE editor, below it is the Timeline, and lastly at the bottom part is the buttons window. Sequence Screen Layout For this part of the article, we’ll only be delving into some of these parts, namely the Preview, VSE Editor, Timeline, and the Buttons Window. I could’ve just said “except the IPO Window. So before we actually try and add in our videos, there are things we need to do: hover your mouse pointer over to the Timeline Window and press SHIFT+T to bring up the Time Value option and choose Seconds. This will help us later on to recognize our video lengths with seconds as the unit and not frames, which can become clearer as we go on. And next is to click the Sequencer button under the Scene(F10) menu. This will enable us to see options for our video later on. Timeline and Button Options Next thing we need to do is to add our videos (at long last) into the VSE Editor and finally to editing on them.  To do this, move your mouse pointer over to the VSE Editor and press spacebar > Movie or Movie + Audio (HD) or you can click Add > Movie or Movie + Audio (HD) on the menu header. This will then lead you into Blender’s file browser where you can locate your videos. If you want to load your videos simultaneously, you can right click, hold, and drag on the videos to select them, and click the load button. They will then be automatically concatenated, each having its own individual video strip. But right now, I only want to load them one at a time so we could focus on editing them separately and not worry about the other strips floating around and messing around with our view. Once the video/s are loaded into the VSE window and are selected, you’ll notice the Sequencer Buttons Window populated with options.  Normally, we will see four (4) tabs, namely: Edit, Input, Filter, and Proxy. Let’s leave the default settings now as they work great as they are (but you can always doodle around the buttons and settings and see how they work, try to experiment!) Basically, I will introduce you to some of Blender’s video editing capabilities such as: cutting, duplicating, transition effects, artistic glows, and speed controls. Discussing the extents and features of this editor might take me a whole new set of article or two so right now, I’ll only lead you to the basic concepts and have you and your imagination with a lot of experimentation lead you to where you want. First off, Cutting video strips. Often, you want to delete parts of your video or move a section of it on a certain time on your collection, this is where cutting comes in handy. In Blender VSE world, you can cut a video by clicking over or scrubbing on the frame where you want to start your cut and press K for hard-cut, SHIFT+K for soft-cut. Once this operation is successful, you’ll notice your strip change appearance as a result of the cut, and depending on the number of cuts you made, that’s how much sub-strips you have which can individually be moved (G) or deleted X or delete key. Cutting, Moving, and Deleting Strips Once you have made the necessary cuts, you can always arrange your strips by moving them beside each other or with gaps, depending on what you want to achieve. Additionally, you can scrub your videos by click and dragging your mouse over to the VSE window (with the green vertical line as your current frame marker) or you could also click and drag over to the Timeline Window. As you scrub your videos, you’ll notice a live preview of what’s happening on the Preview Window on the upper right hand corner of your screen. Another cool trick with the VSE is adding markers to label parts of your animation or videos. Markers are also a way of identifying events in your timeline as they happen so you won’t lose track of what has occurred on that frame in time. You can add markers to your VSE Window where your current frame marker (vertical green line) by pressing CTRL+ALT+M or by clicking Marker > Add Marker on the menu, and add a label to it by pressing CTRL+M or by clicking Marker > (Re)Name Marker. These markers would also appear on your Timeline Window. Adding and (Re)Naming Markers Next is duplicating strips. Sometimes in your video editing endeavors, you wanted to repeat parts of the video for more emphasis or even just for artistic purposes. Luckily, duplicating strips in Blender’s VSE is just as easy as selecting the strips(s) you wish to duplicate and press SHIFT+D or clicking Strip > Duplicate in the menu. Duplicating Strips Now we discuss transition effects, which are one of the nicest things video editing has ever offered. In this part, we’ll try adding some simple transition effects from within the VSE to add subtlety and variation to our strips. Like any other video editing application, it requires you to have at least two strips of video/image to create the transition. We do this in Blender by selecting two strips by first selecting the first strip with right click, then adding to it a second strip by shift right clicking. This way you’re telling Blender from what video to what will the transition occur. Say, you have selected video A first then shift selected video B next, if we’ll now try to add the transition effect, it will happen from video A to video B and not vice versa. The simplest transition that we could add now is the Gamma Cross which simply takes the first strip and fades it into the second one and so on. Do this by selecting two strips and press spacebar then click Gamma Cross or click Add > Effect > Gamma Cross.  With its default settings, when you now scrub your strips or use the timeline, you’ll notice that in between the two strips is a blend of both. Moving any of the video strips will update automatically the length of the Gamma Cross that’s present.
Read more
  • 0
  • 0
  • 6043

article-image-jquery-14-dom-manipulation-methods-replacement-copying-and-removal
Packt
19 Feb 2010
5 min read
Save for later

jQuery 1.4 DOM Manipulation Methods for Replacement, Copying and Removal

Packt
19 Feb 2010
5 min read
DOM replacement These methods are used to remove content from the DOM and replace it with new content. .html() (getter) Get the HTML contents of the first element in the set of matched elements. .html() Parameters None Return value A string containing the HTML representation of the element. Description This method is not available on XML documents. In an HTML document, we can use .html() to get the contents of any element. If our selector expression matches more than one element, only the first one's HTML content is returned. Consider the following code: $('div.demo-container').html(); In order for the content of the following <div> to be retrieved, it would have to be the first one in the document. <div class="demo-container"> <div class="demo-box">Demonstration Box</div></div> The result would look like this: <div class="demo-box">Demonstration Box</div> .html() (setter) Set the HTML contents of each element in the set of matched elements. .html(htmlString).html(function) Parameters (first version) htmlString: A string of HTML to set as the content of each matched element Parameters (second version) function: A function returning the HTML content to set Return value The jQuery object, for chaining purposes. Description The .html() method is not available in XML documents. When we use .html() to set the content of elements, any content that was in those elements is completely replaced by the new content. Consider the following HTML code: <div class="demo-container"> <div class="demo-box">Demonstration Box</div></div> We can set the HTML contents of <div class="demo-conta iner"> as follows: $('div.demo-container').html('<p>All new content. <em>You bet!</em></p>'); That line of code will replace everything inside <div class="demo-container">. <div class="demo-container"> <p>All new content. <em>You bet!</em></p></div> As of jQuery 1.4, the .html() method allows us to set the HTML content by passing in a function. $('div.demo-container').html(function() { var emph = '<em>' + $('p').length + ' paragraphs!</em>'; return '<p>All new content for ' + emph + '</p>';}); Given a document with six paragraphs, this example will set the HTML of <div class="demo-container"> to <p>All new content for <em>6 paragraphs!</em></p>. .text() (getter) Get the combined text contents of each element in the set of matched elements, including their descendants. .text() Parameters None Return value A string containing the combined text contents of the matched elements. Description Unlike the .html() method, .text() can be used in both XML and HTML documents. The result of the .text() method is a string containing the combined text of all matched elements. Consider the following HTML code: <div class="demo-container"> <div class="demo-box">Demonstration Box</div> <ul> <li>list item 1</li> <li>list <strong>item</strong> 2</li> </ul></div> The code $('div.demo-container').text() would produce the following result: Demonstration Box list item 1 list item 2 .text() (setter) Set the content of each element in the set of matched elements to the specified text. .text(textString).text(function) Parameters (first version) textString: A string of text to set as the content of each matched element Parameters (second version) function: A function returning the text to set as the content Return value The jQuery object, for chaining purposes. Description Unlike the .html() method, .text() can be used in both XML and HTML documents. We need to be aware that this method escapes the string provided as necessary so that it will render correctly in HTML. To do so, it calls the DOM method .createTextNode(), which replaces special characters with their HTML entity equivalents (such as &lt; for <). Consider the following HTML code: <div class="demo-container"> <div class="demo-box">Demonstration Box</div> <ul> <li>list item 1</li> <li>list <strong>item</strong> 2</li> </ul></div> The code $('div.demo-container').text('<p>This is a test.</p>'); will produce the following DOM output: <div class="demo-container"> &lt;p&gt;This is a test.&lt;/p&gt;</div> It will appear on a rendered page as though the tags were exposed as follows: <p>This is a test</p> As of jQuery 1.4, the .text() method allows us to set the text content by passing in a function. $('ul li').text(function() {return 'item number ' + ($(this).index() + 1);}); Given an unordered list with three <li> elements, this example will produce the following DOM output: <ul><li>item number 1</li><li>item number 2</li><li>item number 3</li></ul>
Read more
  • 0
  • 0
  • 2063

article-image-melody-other-movable-type
Packt
19 Feb 2010
5 min read
Save for later

Melody: The Other Movable Type

Packt
19 Feb 2010
5 min read
If there’s one golden rule of open source, it’s this: Major projects can and will be forked. Multiple versions of just about every open source app of repute have been spun off from the original. These splits happen for reasons that are more often political than technical. Look at the clamor building around MySQL, where people concerned about the future of the project under Oracle’s stewardship want its code copied out into another, separately managed project that won’t (as they see it) end up as a corporate lapdog. The blogging system Movable Type, now in its fifth major revision, is also undergoing a code schism of sorts. A number of Movable Type developers and contributors became frustrated with what they felt was an emphasis by MT’s corporate owners on the wrong features, as well as a lack of transparency in the development process for the product. Rather than attack Six Apart (Movable Type’s parent company) directly, they chose instead to do an end run—to take the now open-source code base for Movable Type and create a new product from it: Melody. The theme behind Melody Melody extends on Movable Type’s legacy in four basic ways. Take what already exists in Movable Type, keep what’s best about it, remove from the core product features which make things substantially more complex but which are only used by a minority of users anyway, and move Melody forward in ways that show the developers are directly attuned to the needs of the new user (and developer) base. How these things manifest in Melody can be summed up in a few key points as shown below. Backwards compatibility Since most of the initial user base for Melody will consist of Movable Type users and developers, it only makes sense for Melody to be heavily backwards-compatible with MT. This doesn’t just mean that a MT database can be imported into a Melody installation as-is. This also means things like plugins and transformation filters will still work correctly. Both are crucial, since so much of MT’s appeal is in how it can be bent and shaped to fit user’s needs—and those same needs will carry directly over into Melody. (If anything, they’ll have to be satisfied all the better in Melody, since Melody’s being written specifically from the perspective of allowing such customization to be all the easier and more powerful to implement.) The exact degree and scope of Melody’s backwards compatibility with Movable Type is still being wrangled out, but it’s likely to be as friendly as possible to existing MT developers as a way to gain their immediate support. One thing that has become clearer is that people looking to make a straight upgrade from MT to Melody will at this point be best served by an upgrade from the 4.x branch of MT than the current 5.x branch. This is probably due to Melody being more derived from the former than the latter, but there’s nothing that says in time a clean 5.x migration path can’t be created. A more developer-friendly culture "Developer" doesn’t just mean people who write Melody or Movable Type’s own code. It means people who create the above-mentioned add-ons, and—in some ways the most visible type of third-party development—people who create themes and templates for the system. A better culture for those people to thrive in means more. Another concrete way for developer-friendliness to manifest is with better use of existing CPAN (for Perl) and jQuery (for JavaScript) libraries and community-developed code. A lot of what was written for earlier versions of Movable Type duplicated functions that were available in those repositories. Not only did this mean MT’s code had to be maintained separately, but it also meant Movable Type didn’t leverage what was available in CPAN and jQuery as effectively as it could. Indirect contribution to Movable Type itself What Melody’s developers hope to create is a project that doesn’t so much steal marketshare from Movable Type as it does give Movable Type itself a chance to become a better project, too. Melody could become a model for how MT itself might evolve, and since Melody’s licensed under the same terms as MT itself (GPLv2), there’s nothing preventing significant chunks of Melody—or even the whole project—from being back-adopted into MT. Even the Melody developers themselves don’t see everyone ditching Movable Type. For one, the enterprise-level editions of Movable Type have a bevy of features (not least among which is paid support) that won’t show up in Melody any time soon. That and Melody’s developers don’t see it as being part of their project’s focus to try and eclipse MT’s high-end, paying-customers features. (Melody’s own FAQ discourages using the paid-support add-ons for MT with Melody, because of the licensing and support-contract restrictions involved.) Melody’s current interface is based on the 4.x branch of Movable Type, and so most closely resembles that program with only minimal changes.
Read more
  • 0
  • 0
  • 2864

article-image-php-web-20-mashup-projects-your-own-video-jukebox-part-1
Packt
19 Feb 2010
11 min read
Save for later

PHP Web 2.0 Mashup Projects: Your Own Video Jukebox: Part 1

Packt
19 Feb 2010
11 min read
Project Overview What Mashup the web APIs from Last.fm and YouTube to create a video jukebox of songs Protocols Used REST (XML-RPC available) Data Formats XML, XPSF, RSS Tools Featured PEAR APIs Used Last.fm and YouTube   Now that we've had some experience using web services, it's time to fine tune their use. XML-RPC, REST, and SOAP will be frequent companions when you use web services and create mashups. You will encounter a lot of different data formats, and interesting ways in which the PHP community has dealt with these formats. This is especially true because REST has become so popular. In REST, with no formalized response format, you will encounter return formats that vary from plain text to ad-hoc XML to XML-based standards. The rest of our projects will focus on exposing us to some new formats, and we will look at how to handle them through PHP. We will begin with a project to create our own personalized video jukebox. This mashup will pull music lists feeds from the social music site, Last.fm. We will parse out artist names and song titles from these feeds and use that information to search videos on YouTube, a user-contributed video site, using the YouTube web service. By basing the song selections on ever-changing feeds, our jukebox selection will not be static, and will change as our music taste evolves. As YouTube is a user-contributed site, we will see many interesting interpretations of our music, too. This jukebox will be personalized, dynamic, and quite interesting. Both Last.fm and YouTube's APIs offer their web services through REST, and YouTube additionally offers an XML-RPC interface. Like with previous APIs, XML is returned with each service call. Last.fm returns either plain text, an XML playlist format called XSPF (XML Shareable Playlist Format), or RSS (Really Simple Syndication). In the case of YouTube, the service returns a proprietary format. Previously, we wrote our own SAX-based XML parser to extract XML data. In this article, we will take a look at how PEAR, the PHP Extension and Application Repository, can do the XSPF parsing work for us on this project and might help in other projects. Let's take a look at the various data formats we will be using, and then the web services themselves. XSPF One of XML's original goals was to allow industries to create their own markup languages to exchange data. Because anyone can create their own elements and schemas, as long as people agreed on a format, XML can be used as the universal data transmission language for that industry. One of the earliest XML-based languages was ChemXML, a language used to transmit data within the chemical industry. Since then, many others have popped up. XSPF was a complete grassroots project to create an open, non-proprietary music playlist format based on XML. Historically, playlists for software media players and music devices were designed to be used only on the machine or device, and schemas were designed by the vendor themselves. XSPF's goal was to create a format that could be used in software, devices, and across networks. XSPF is a very simple format, and is easy to understand. The project home page is at http://www.xspf.org. There, you will find a quick start guide which outlines a simple playlist as well as the official specifications at http://www.xspf.org/specs. Basically, a typical playlist has the following structure: <?xml version="1.0" encoding="UTF-8"?><playlist version="1" > <title>Shu Chow's Playlist</title> <date>2006-11-24T12:01:21Z</data> <trackList> <track> <title>Pure</title> <creator>Lightning Seeds</creator> <location> file:///Users/schow/Music/Pure.mp3 </location> </track> <track> <title>Roadrunner</title> <creator>The Modern Lovers</creator> <location> file:///Users/schow/Music/Roadrunner.mp3 </location> </track> <track> <title>The Bells</title> <creator>April Smith</creator> <location> file:///Users/schow/Music/The_Bells.mp3 </location> </track> </trackList></playlist> playlist is the parent element for the whole document. It requires one child element, trackList, but there can be several child elements that are the metadata for the playlist itself. In this example, the playlist has a title specified in the title element, and the creation date is specified in the date element. Underneath trackList are the individual tracks that make up the playlist. Each track is encapsulated by the track element. Information about the track, including the location of its file, is encapsulated in elements underneath track. In our example, each track has a title, an artist name, and a local file location. The official specifications allow for more track information elements such as track length and album information. Here are the playlist child elements summarized: Playlist Child Element Required? Description trackList Yes The parent of individual track elements. This is the only required child element of a playlist. Can be empty if the playlist has no songs. title No A human readable title of the XSPF playlist. creator No The name of the playlist creator. annotation No Comments on the playlist. info No A URL to a page containing more information about the playlist. location No The URL to the playlist itself. identifier No The unique ID for the playlist. Must be a legal Uniform Resource Name (URN). image No A URL to an image representing the playlist. date No The creation (not the last modified!) date of the playlist. Must be in XML schema dateTime format. For example, "2004-02-27T03:30:00". license No If the playlist is under a license, the license is specified with this element. attribution No If the playlist is modified from another source, the attribution element gives credit back to the original source, if necessary. link No Allows non-XSPF resources to be included in the playlist. meta No Allows non-XSPF metadata to be included in the playlist. extension No Allows non-XSPF XML extensions to be included in the playlist. A trackList element has an unlimited number of track elements to represent each track. track is the only allowed child of trackList. track's child elements give us information about each track. The following table summarizes the children of track: Track Child Element Required? Description location No The URL to the audio file of the track. identifier No The canonical ID for the playlist. Must be a legal URN. title No A human readable title of the track. Usually, the song's name. creator No The name of the track creator. Usually, the song's artist. annotation No Comments on the track. info No A URL to a page containing more information about the track. image No A URL to an image representing the track. album No The name of the album that the track belongs to. trackNum No The ordinal number position of the track in the album. duration No The time to play the track in milliseconds. link No Allows non-XSPF resources to be included in the track. meta No Allows non-XSPF metadata to be included in the track. extension No Allows non-XSPF XML extensions to be included in the track. Note that XSPF is very simple and track oriented. It was not designed to be a repository or database for songs. There are not a lot of options to manipulate the list. XSPF is merely a shareable playlist format, and nothing more. RSS The simplest answer to, "What is RSS?", is that it's an XML file used to publish frequently updated information, like news items, blogs entries, or links to podcast episodes. News sites like Slashdot.org and the New York Times provide their news items in RSS format. As new news items are published, they are added to the RSS feed. Being XML-based, third-party aggregator software makes reading news items easy. With one piece of software, I can tell it to grab feeds from various sources and read the news items in one location. Web applications can also read and parse RSS files. By offering an RSS feed for my blog, another site can grab the feed and keep track of my daily life. This is one way by which a small site can provide rudimentary web services with minimal investment. The more honest answer is that it is a group of XML standards (used to publish frequently updated information like news items or blogs) that may have little compatibility with each other. Each version release also has a tale of conflict and strife behind it. We won't dwell on the politicking of RSS. We'll just look at the outcomes. The RSS world now has three main flavors: The RSS 1.0 branch includes versions 0.90, 1.0, and 1.1. It's goal is to be extensible and flexible. The downside to the goals is that it is a complex standard. The RSS 2.0 branch includes versions 0.91, 0.92, and 2.0.x. Its goal is to be simple and easy to use. The drawback to this branch is that it may not be powerful enough for complex sites and feeds. There are some basic skeletal similarities between the two formats. After the XML root element, metadata about the feed itself is provided in a top section. After the metadata, one or more items follow. These items can be news stories, blog entries, or podcasts episodes. These items are the meat of an RSS feed. The following is an example RSS 1.1 file from XML.com: <Channel rdf_about="http://www.xml.com/xml/news.rss"> <title>XML.com</title> <link>http://xml.com/pub</link> <description> XML.com features a rich mix of information and services for the XML community. </description> <image rdf_parseType="Resource"> <title>XML.com</title> <url>http://xml.com/universal/images/xml_tiny.gif</url> </image> <items rdf_parseType="Collection"> <item rdf_about= "http://www.xml.com/pub/a/2005/01/05/restful.html"> <title> The Restful Web: Amazon's Simple Queue Service </title> <link> http://www.xml.com/pub/a/2005/01/05/restful.html </link> <description> In Joe Gregorio's latest Restful Web column, he explains that Amazon's Simple Queue Service, a web service offering a queue for reliable storage of transient messages, isn't as RESTful as it claims. </description> </item> <item rdf_about= "http://www.xml.com/pub/a/2005/01/05/tr-xml.html"> <title> Transforming XML: Extending XSLT with EXSLT </title> <link> http://www.xml.com/pub/a/2005/01/05/tr-xml.html </link> <description> In this month's Transforming XML column, Bob DuCharme reports happily that the promise of XSLT extensibility via EXSLT has become a reality. </description> </item> </items></Channel> The root element of an RSS file is an element named Channel. Immediately, after the root element are elements that describe the publisher and the feed. The title, link, description, and image elements give us more information about the feed. The actual content is nested in the items element. Even if there are no items in the feed, the items element is required, but will be empty. Usage of these elements can be summarized as follows: Channel Child Element Required? Description title Yes A human readable title of the channel. link Yes A URL to the feed. description Yes A human readable description of the feed. items Yes A parent element to wrap around item elements. image No A section to house information about an official image for the feed. others No Any other elements not in the RSS namespace can be optionally included here. The namespace must have been declared earlier, and the child elements must be prefixed. If used, the image element needs its own child elements to hold information about the feed image. A title element is required and while optional, a link element to the actual URL of the image would be extremely useful. Each news blog, or podcast entry is represented by an item element. In this RSS file, each item has a title, link, and a description, each, represented by the respective element. This file has two items in it before the items and Channel elements are closed off.
Read more
  • 0
  • 0
  • 2471

article-image-jquery-14-dom-insertion-methods
Packt
19 Feb 2010
8 min read
Save for later

jQuery 1.4 DOM Insertion Methods

Packt
19 Feb 2010
8 min read
DOM insertion, inside These methods allow us to insert new content inside an existing element. .prepend() Insert content specified by the parameter at the beginning of each element in the set of matched elements. .prepend(content).prepend(function) Parameters (first version) content: An element, an HTML string, or a jQuery object to insert at the beginning of each element in the set of matched elements Parameters (second version) function: A function that returns an HTML string to insert at the beginning of each element in the set of matched elements Return value The jQuery object, for chaining purposes. Description The .prepend() and .prependTo() methods perform the same task. The major difference is in the syntax, specifically in the placement of the content and target. With .prepend(), the selector expression preceding the method is the container into which the content is inserted. With .prependTo(), on the other hand, the content precedes the method either as a selector expression or as markup created on the fly. It is then inserted into the target container. Consider the following HTML code: <h2>Greetings</h2> <div class="container"> <div class="inner">Hello</div> <div class="inner">Goodbye</div></div> We can create content and insert it into several elements at once. $('.inner').prepend('<p>Test</p>'); Each <div class="inner"> element gets the following new content: <h2>Greetings</h2> <div class="container"> <div class="inner"> <p>Test</p> Hello </div> <div class="inner"> <p>Test</p> Goodbye </div></div> We can also select an element on the page and insert it into another: $('.container').prepend($('h2')); If an element selected this way is inserted elsewhere, it will be moved into the target (not cloned). <div class="container"> <h2>Greetings</h2> <div class="inner">Hello</div> <div class="inner">Goodbye</div></div> However, if there are more than one target elements, cloned copies of the inserted elements will be created for each target after the first. .prependTo() Insert every element in the set of matched elements at the beginning of the target. .prependTo(target) Parameters target: A selector, element, HTML string, or jQuery object; the matched set of elements will be inserted at the beginning of the element(s) specified by this parameter Return value The jQuery object, for chaining purposes. Description The .prepend() and .prependTo() methods perform the same task. The major difference is in the syntax, specifically in the placement of the content and target. With .prepend(), the selector expression preceding the method is the container into which the content is inserted. With .prependTo(), on the other hand, the content precedes the method either as a selector expression or as markup created on the fly, and is inserted into the target container. Consider the following HTML code: <h2>Greetings</h2> <div class="container"> <div class="inner">Hello</div> <div class="inner">Goodbye</div></div> We can create content and insert it into several elements at once. $('<p>Test</p>').prependTo('.inner'); Each inner <div> element gets the following new content: <h2>Greetings</h2><div class="container"> <div class="inner"> <p>Test</p> Hello </div> <div class="inner"> <p>Test</p> Goodbye </div></div> We can also select an element on the page and insert it into another. $('h2').prependTo($('.container')); If an element selected this way is inserted elsewhere, it will be moved into the target (not cloned). <div class="container"> <h2>Greetings</h2> <div class="inner">Hello</div> <div class="inner">Goodbye</div></div> However, if there are more than one target elements, cloned copies of the inserted elements will be created for each target after the first. .append() Insert content specified by the parameter at the end of each element in the set of matched elements. .append(content).append(function) Parameters (first version) content: An element, an HTML string, or a jQuery object to insert at the end of each element in the set of matched elements Parameters (second version) function: A function that returns an HTML string to insert at the end of each element in the set of matched elements Return value The jQuery object, for chaining purposes. Description The .append() and .appendTo() methods perform the same task. The major difference is in the syntax, specifically in the placement of the content and target. With .append(), the selector expression preceding the method is the container into which the content is inserted. With .appendTo(), on the other hand, the content precedes the method either as a selector expression or as markup created on the fly, and is inserted into the target container. Consider the following HTML code: <h2>Greetings</h2><div class="container"> <div class="inner">Hello</div> <div class="inner">Goodbye</div></div> We can create content and insert it into several elements at once. $('.inner').append('<p>Test</p>'); Each inner <div> element gets the following new content: <h2>Greetings</h2><div class="container"> <div class="inner"> Hello <p>Test</p> </div> <div class="inner"> Goodbye <p>Test</p> </div></div> We can also select an element on the page and insert it into another. $('.container').append($('h2')); If an element selected this way is inserted elsewhere, it will be moved into the target (not cloned). <div class="container"> <div class="inner">Hello</div> <div class="inner">Goodbye</div> <h2>Greetings</h2></div> However, if there is more than one target element, cloned copies of the inserted elements will be created for each target after the first. .appendTo() Insert every element in the set of matched elements at the end of the target. .appendTo(target) Parameters target: A selector, element, HTML string, or jQuery object; the matched set of elements will be inserted at the end of the element(s) specified by this parameter Return value The jQuery object, for chaining purposes. Description The .append() and .appendTo() methods perform the same task. The major difference is in the syntax, specifically in the placement of the content and target. With .append(), the selector expression preceding the method is the container into which the content is inserted. With .appendTo(), on the other hand, the content precedes the method either as a selector expression or as markup created on the fly, and is inserted into the target container. Consider the following HTML code: <h2>Greetings</h2><div class="container"> <div class="inner">Hello</div> <div class="inner">Goodbye</div></div> We can create content and insert it into several elements at once. $('<p>Test</p>').appendTo('.inner'); Each inner <div> element gets the following new content: <h2>Greetings</h2> <div class="container"> <div class="inner"> Hello <p>Test</p> </div> <div class="inner"> Goodbye <p>Test</p> </div></div> We can also select an element on the page and insert it into another. $('h2').append($('.container')); If an element selected this way is inserted elsewhere, it will be moved into the target (not cloned). <div class="container"> <div class="inner">Hello</div> <div class="inner">Goodbye</div> <h2>Greetings</h2></div> However, if there are more than one target elements, cloned copies of the inserted elements will be created for each target after the first.
Read more
  • 0
  • 0
  • 1911

article-image-building-simple-address-book-application-jquery-and-php
Packt
19 Feb 2010
14 min read
Save for later

Building a Simple Address Book Application with jQuery and PHP

Packt
19 Feb 2010
14 min read
Let's get along. The application folder will be made up of five files: addressbook.css addressbook.html addressbook.php addressbook.js jquery.js Addressbook.css will contain the css for the interface styling, addressbook.html will contain the html source, addressbook.js contains  javascript codes, addressbook.php will mostly contain the server side code that will store the contacts to database, delete the contacts, provide updates and fetch the list of the contacts. Let's look through the HTML We include the scripts and the css file in the head tag in addressbook.html file. <title>sample address book</title> <link rel="stylesheet" type="text/css" href="addressbook.css"> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript" src="addressbook.js"></script> The code above includes the css for styling the application, jquery library for cross browser javascript and easy DOM access, and the addressbook.js contains functions that help user actions translated via javascript and ajax calls. The Body tag should contain this: <div id="Layer1"> <h1>Simple Address Book</h1> <div id="addContact">               <a href="#add-contact" id="add-contact-btn">Add Contact</a>               <table id="add-contact-form">               <tr>               <td>Names:</td><td><input type="text" name="names" id="names"  /></td>               </tr>               <tr>               <td>Phone Number:</td><td><input type="text" name="phone" id="phone"  /></td>               </tr>               <tr>               <td>&nbsp;</td><td>               <a href="#save-contact" id="save-contact-btn">Save Contact</a>               <a href="#cancel" id="cancel-btn">Cancel</a>               </td>               </tr>               </table> </div> <div id="notice">               notice box </div> <div id="list-title">My Contact List</div> <ul id="contacts-lists">         <li>mambe nanje [+23777545907] - <a href="#delete-id" class="deletebtn" contactid='1'> delete contact </a></li>         <li>mambe nanje [+23777545907] - <a href="#delete-id" class="deletebtn" contactid='2'> delete contact</a></li>         <li>mambe nanje [+23777545907] - <a  href="#delete-id" class="deletebtn" contactid='3'> delete contact</a></li> </ul> </div> The above code creates an html form that provides input fields to insert new address book entries. It also displays a button to make it appear via javascript functions. It also creates a notification div and goes to display the contact list with delete button on each entry. With the above code, the application will now look like this:   /* CSS Document */   body {               background-color: #000000; } #Layer1 {               margin:auto;               width:484px;               height:308px;               z-index:1; } #add-contact-form{               color:#FF9900;               font-weight:bold;               font-family:Verdana, Arial, Helvetica, sans-serif;               background-color:#333333;               margin-top:5px;               padding:10px; } #add-contact-btn{               background-color:#FF9900;               font-weight:bold;               font-family:Verdana, Arial, Helvetica, sans-serif;               border:1px solid #666666;               color:#000;               text-decoration:none;               padding:2px;               font-weight:bold; } #save-contact-btn{               background-color:#FF9900;               font-weight:bold;               font-family:Verdana, Arial, Helvetica, sans-serif;               border:1px solid #666666;               color:#000;               text-decoration:none;               padding:2px;               font-weight:bold; } #cancel-btn{               background-color:#FF9900;               font-weight:bold;               font-family:Verdana, Arial, Helvetica, sans-serif;               border:1px solid #666666;               color:#000;               text-decoration:none;               padding:2px;               font-weight:bold; } h1{               color:#FFFFFF;               font-family:Arial, Helvetica, sans-serif; } #list-title{               color:#FFFFFF;               font-weight:bold;               font-size:14px;               font-family:Arial, Helvetica, sans-serif;               margin-top:10px; } #contacts-lists{               color:#FF6600;               font-weight:bold;               font-family:Verdana, Arial, Helvetica, sans-serif;               font-size:12px; } #contacts-lists a{               background-color:#FF9900;               text-decoration:none;                            padding:2px;               color:#000;               margin-bottom:2px; } #contacts-lists li{               list-style:none;               border-bottom:1px dashed #666666;               margin-bottom:10px;               padding-bottom:5px; } #notice{               width:400px;               margin:auto;               background-color:#FFFF99;               border:1px solid #FFCC99;               font-weight:bold;               font-family:verdana;               margin-top:10px;               padding:4px; } The CSS code styles the HTML above and it ends up looking like this: Now that we have our html and css perfectly working, we need to setup the database and the PHP server codes that will handle the AJAX requests from the jquery functions. Create a MySQL database and executing the following SQL code will create the contacts table. This is the only table this application needs. CREATE TABLE `contacts` ( `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , `names` VARCHAR( 200 ) NOT NULL , `phone` VARCHAR( 100 ) NOT NULL ); Let's analyse the php codes. Remember, this code will be located in addressbook.php. The database connection code # FileName="Connection_php_mysql.htm" # Type="MYSQL" # HTTP="true" //configure the database paramaters $hostname_packpub_addressbook = "YOUR-DATABASE-HOST"; $database_packpub_addressbook = "YOUR-DATABASE-NAME"; $username_packpub_addressbook = "YOUR-DATABASE-USERNAME"; $password_packpub_addressbook = "YOUR-DATABASE-PASSWORD"; //connect to the database server $packpub_addressbook = mysql_pconnect($hostname_packpub_addressbook, $username_packpub_addressbook,  $password_packpub_addressbook) or trigger_error(mysql_error(),E_USER_ERROR); //selete the database mysql_select_db($database_packpub_addressbook); the above code sets the parameters required for the database connection, then establishes a connection to the server and selects your database. The PHP codes will then contain functions SAVECONTACTS, DELETECONTACTS, GETCONTACTS. These functions will do exactly as their name implies. Save the contact from AJAX call to the database, delete contact via AJAX request or get the contacts. The functions are as show below: //function to save new contact /** * @param <string> $name //name of the contact * @param <string> $phone //the telephone number of the contact */ function saveContact($name,$phone){               $sql="INSERT INTO contacts (names , phone ) VALUES ('".$name."','".$phone."');";               $result=mysql_query($sql)or die(mysql_error()); } //lets write a function to delete contact /** * @param <int> id //the contact id in database we wish to delete */ function deleteContact($id){               $sql="DELETE FROM contacts where id=".$id;               $result=mysql_query($sql); }   //lets get all the contacts function getContacts(){               //execute the sql to get all the contacts in db               $sql="SELECT * FROM contacts";               $result=mysql_query($sql);               //store the contacts in an array of objects               $contacts=array();               while($record=mysql_fetch_object($result)){                             array_push($contacts,$record);               }               //return the contacts               return $contacts; } The codes above creates the functions but the functions are not called till the following code executes: //lets handle the Ajax calls now $action=$_POST['action']; //the action for now is either add or delete if($action=="add"){               //get the post variables for the new contact               $name=$_POST['name'];               $phone=$_POST['phone'];               //save the new contact               saveContact($name,$phone);               $output['msg']=$name." has been saved successfully";               //reload the contacts               $output['contacts']=getContacts();               echo json_encode($output); }else if($action=="delete"){               //collect the id we wish to delete               $id=$_POST['id'];               //delete the contact with that id               deleteContact($id);               $output['msg']="one entry has been deleted successfully";               //reload the contacts               $output['contacts']=getContacts();               echo json_encode($output); }else{               $output['contacts']=getContacts();               $output['msg']="list of all contacts";               echo json_encode($output); } The above code is the heart of the addressbook.php codes. It gets the action from post variables sent via AJAX call in addressbook.js file, interprets the action and executes the appropriate function for either add, delete or nothing which will just get the list of contacts. json_encode() function is used to encode the data in to Javascript Object Notation format; it will be easily interpreted by the javascript codes.
Read more
  • 0
  • 0
  • 12718
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime
article-image-drupal-6-performance-optimization-using-throttle-and-devel-module
Packt
19 Feb 2010
6 min read
Save for later

Drupal 6 Performance Optimization Using Throttle and Devel Module

Packt
19 Feb 2010
6 min read
Enabling and configuring the Throttle module Drupal allows you to control when your modules and blocks get enabled and shown to your site visitors. This helps you to prevent bottlenecks in your server's web traffic and to optimize your server load to prevent any congestion that it might experience with its bandwidth and traffic. Throttling blocks and modules becomes increasingly important on larger scale websites where you have many blocks and modules active. You may have a site that contains a large number of blocks, for example, that have been built with the Views module. You can throttle these blocks, so they only get enabled when the site visitor calls a page that is supposed to show that block. The throttle module allows you to configure it, so it automatically gets enabled when the usage of your site goes above a certain threshold. For example, this can be the number of anonymous users visiting your site. When a certain amount of visitors are on your site, you can have Drupal enable throttling. Using the Throttle module is essential on shared servers where you may not have all of the resources on the server made available to you at any given time or on a server that gives you limited CPU resources and bandwidth. You may not need to use Throttle on higher performance-dedicated servers because they will most likely be providing you with good performance. But on shared servers it does become important to use Throttle. If you did not enable the Throttle module after we upgraded our site to Drupal 6.13, we need to enable it first. Once enabled, we can then configure the module. Follow these steps: Under your Core-optional module list, check the box next to Throttle and then save your module configuration. There are two methods of accessing the Throttle module configuration. You can visit the main Throttle configuration page to set auto throttling settings for your site. Also, you can enable throttling for each module and block on your site. We'll look at both methods now. Note that your modules admin page explains how to access and enable both types of throttling (module and auto) at the top of the page in its introductory help text. You will only see your module throttle checkboxes available if you have enabled the Throttle module first. Configuring the Throttle module for auto throttling features Go to Site configuration | Throttle to load your Throttle module settings form or click on the throttle configuration page link through your main modules admin page. The Throttle configuration page explains what the Throttle module does and gives you a link to more information through the more help link. If you click on that link and have the Advanced Help module active, you will launch a detailed Throttle module help and explanation page. On this page you can configure three throttle elements that fall under the default Throttle module congestion control feature: Auto-throttle on anonymous users Auto-throttle on authenticated users Auto-throttle probability limiter Auto-throttle on anonymous users allows you to set a threshold for enabling your congestion control throttle dependent on anonymous user activity. So, for example, you will want to choose a threshold number of anonymous users to enter into this field. When this number of anonymous users is reached, the auto-throttle feature will be enabled. If you want the auto-throttle to be enabled after 250 anonymous users are on your site at the same time, you can type 250 into this field. Set this field to 0 if you do not want to use the auto-throttle feature. Drupal also tells you here that you can determine how many users are on your site at any given time by enabling the Who's Online block—this will show you all of the anonymous users who are browsing your site and authenticated users who are logged into your site. The Auto-throttle on authenticated users works using the same method. Add the threshold number of authenticated users that you want logged into your site before the point your throttle gets enabled. We'll set this to 50 authenticated users. The Auto-throttle probability limiter helps to reduce the overhead of the auto-throttle module. It's a built-in performance check just for this Throttle module. You can set a pe rcentage of page views for your site. For example, if you set the page view percentage to 10%, then the module will only perform extra database queries to update the Throttle module status once for every 10 page views. Drupal tells you that the busier your website, the lower you want to set this value. Leave it set to the default of 10%. Save your auto-throttle configuration. Throttling your modules You can also throttle each of your core and contributed modules as long as they have a Throttle checkbox next to their line item on the modules admin page. Load your modules admin page and look for the Throttle checkboxes. This allows you to tell Drupal to throttle a specific module during high traffic periods on your site. This means that when your site reaches a high traffic threshold (based on the auto throttling settings you determined above) your site will temporarily disable the module in question. This will throttle the module until your site returns to a stable status. You do need to be careful here. You should throttle those modules that are of lesser importance when your site reaches its threshold of user activity. When you throttle, you are temporarily disabling the module, so it will also temporarily disable that module's functionality during high server loads. So, you may want to disable some modules, such as Views, but leave your CCK module enabled so that your users can still see the content that is being filtered into the View. We'll go ahead and throttle the following modules: Administration menu (because this module is only being used by our logged in admins) Chaos tool suite (all submodules here) Comment Contact Database logging Help PHP filter Search Statistics Advanced Help FCKEditor IMCE Lightbox2 Poormanscron You can select more modules to throttle based on your preferences and the usage of your site. Use the above as an example and model to follow. Check the throttle boxes and save your configuration. During the next high server load period, these modules will be disabled temporarily to increase the performance of your site during its high server load period. Throttling blocks You can also throttle your blocks. To do this, go to the Blocks admin page here: Administer | Site building | Blocks. You'll notice that there is a new checkbox selection for Throttle. You can choose which blocks to throttle by checking the Throttle checkbox next to each of your enabled blocks. We'll go ahead and throttle all of our blocks except for the User login, as we still want to allow users to login to the site during high traffic periods. The throttle functionality works the same here as it does with modules. These blocks will be temporarily disabled during high site traffic. Once you check your throttle boxes, save your blocks configuration. The next time you have high site traffic, these blocks will be temporarily disabled.
Read more
  • 0
  • 0
  • 2869

article-image-php-web-20-mashup-projects-your-own-video-jukebox-part-2
Packt
19 Feb 2010
19 min read
Save for later

PHP Web 2.0 Mashup Projects: Your Own Video Jukebox: Part 2

Packt
19 Feb 2010
19 min read
Parsing With PEAR If we were to start mashing up right now, between XSPF, YouTube's XML response, and RSS, we would have to create three different parsers to handle all three response formats. We would have to comb through the documentation and create flexible parsers for all three formats. If the XML response for any of these formats changes, we would also be responsible for changing our parser code. This isn't a difficult task, but we should be aware that someone else has already done the work for us. Someone else has already dissected the XML code. To save time, we can leverage this work for our mashup. We used PEAR, earlier in Chapter 1 to help with XML-RPC parsing. For this project, we will once again use PEAR to save us the trouble of writing parsers for the three XML formats we will encounter. For this project, we will take a look at three packages for our mashup. File_XSPF is a package for extracting and setting up XSPF playlists. Services_YouTube is a Web Services package that was created specifically for handling the YouTube API for us. Finally, XML_RSS is a package for working with RSS feeds. For this project, it works out well that there are three specific packages that fits our XML and RSS formats. If you need to work with an XML format that does not have a specific PEAR package, you can use the XML_Unserializer package. This package will take a XML and return it as a string. Is PEAR Right For You?Before we start installing PEAR packages, we should take a look if it is even feasible to use them for a project. PEAR packages are installed with a command line package manager that is included with every core installation of PHP. In order for you to install PEAR packages, you need to have administrative access to the server. If you are in a shared hosting environment and your hosting company is stingy, or if you are in a strict corporate environment where getting a server change is more hassle than it is worth, PEAR installation may not be allowed. You could get around this by downloading the PEAR files and installing them in your web documents directory. However, you will then have to manage package dependencies and package updates by yourself. This hassle may be more trouble than it's worth, and you may be better off writing your own code to handle the functionality.On the other hand, PEAR packages are often a great time saver. The purpose of the packages is to either simplify tedious tasks, or interface with complex systems. The PEAR developer has done the difficult work for you already. Moreover, as they are written in PHP and not C, like a PHP extension would be, a competent PHP developer should be able to read the code for documentation if it is lacking. Finally, one key benefit of many packages, including the ones we will be looking at, is that they are object-oriented representations of whatever they are interfacing. Values can be extracted by simply calling an object's properties, and complex connections can be ignited by a simple function call. This helps keep our code cleaner and modular. Whether the benefits of PEAR outweigh the potential obstacles depends on your specific situation. Package Installation and Usage Just like when we installed the XML-RPC package, we will use the install binary to install our three packages. If you recall, installing a package, simply type install into the command line followed by the name of the package. In this case, though, we need to set a few more flags to force the installer to grab dependencies and code in beta status. To install File_XSPF, switch to the root user of the machine and use this command: [Blossom:~] shuchow# /usr/local/php5/bin/pear install -f --alldeps File_XSPF This command will download the package. The -alldeps flag tells PEAR to also check for required dependencies and install them if necessary. The progress and outcome of the downloads will be reported. Do a similar command for Services_YouTube: [Blossom:~] shuchow# /usr/local/php5/bin/pear install -f --alldeps Services_YouTube Usually, you will not need the –f flag. By default, PEAR downloads the latest stable release of a package. The –f flag, force, forces PEAR to download the most current version, regardless of its release state. As of this writing, File_XSPF and Services_YouTube do not have stable releases, only beta and alpha respectively. Therefore, we must use –f to grab and install this package. Otherwise, PEAR will complain that the latest version is not available. If the package you want to download is in release state, you will not need the –f flag. This is the case of XML_RSS, which has a stable version available. [Blossom:~] shuchow# /usr/local/php5/bin/pear install --alldeps XML_RSS After this, sending a list-all command to PEAR will show the three new packages along with the packages you had before. PEAR packages are basically self-contained PHP files that PEAR installs into your PHP includes directory. The includes directory is a directive in your php.ini file. Navigate to this directory to see the PEAR packages' source files. To use a PEAR package, you will need to include the package's source file in the top of your code. Consult the package's documentation on how to include the main package file. For example, File_XSPF is activated by including a file named XSPF.php. PEAR places XSPF.php in a directory named File, and that directory is inside your includes directory. <?php require_once 'File/XSPF.php'; //File_XSPF is now available. File_XSPF The documentation to the latest version of XSPF is located at http://pear.php.net/package/File_XSPF/docs/latest/File_XSPF/File_XSPF.html. The package is simple to use. The heart of the package is an object called XSPF. You instantiate and use this object to interact with a playlist. It has methods to retrieve and modify values from a playlist, as well as utility methods to load a playlist into memory, write a playlist from memory to a file, and convert an XSPF file to other formats. Getting information from a playlist consists of two straightforward steps. First, the location of the XSPF file is passed to the XSPF object's parse method. This loads the file into memory. After the file is loaded, you can use the object's various getter methods to extract values from the list. Most of the XSPF getter methods are related to getting metadata about the playlist itself. To get information about the tracks in the playlist, use the getTracks method. This method will return an array of XSPF_Track objects. Each track in the playlist is represented as an XSPF_Track object in this array. You can then use the XSPF_Track object's methods to grab information about the individual tracks. We can grab a playlist from Last.fm to illustrate how this works. The web service has a playlist of a member's most played songs. Named Top Tracks, the playlist is located at http://ws.audioscrobbler.com/1.0/user/USERNAME/toptracks.xspf, where USERNAME is the name of the Last.fm user that you want to query. This page is named XSPFPEARTest.php in the examples. It uses File_XSPF to display my top tracks playlist from Last.fm. <?php require_once 'File/XSPF.php'; $xspfObj =& new File_XSPF(); //Load the playlist into the XSPF object. $xspfObj->parseFile('http://ws.audioscrobbler.com/1.0/user/ ShuTheMoody/toptracks.xspf'); //Get all tracks in the playlist. $tracks = $xspfObj->getTracks();?> This first section creates the XSPF object and loads the playlist. First, we bring in the File_XSPF package into the script. Then, we instantiate the object. The parseFile method is used to load an XSPF file list across a network. This ties the playlist to the XSPF object. We then use the getTracks method to transform the songs on the playlist into XSPF_Track objects. <html><head> <title>Shu Chow's Last.fm Top Tracks</title></head><body> Title: <?= $xspfObj->getTitle() ?><br /> Created By: <?= $xspfObj->getCreator() ?> Next, we prepare to display the playlist. Before we do that, we extract some information about the playlist. The XSPF object's getTitle method returns the XSPF file's title element. getCreator returns the creator element of the file. <?php foreach ($tracks as $track) { ?> <p> Title: <?= $track->getTitle() ?><br /> Artist: <?= $track->getCreator() ?><br /> </p><?php } ?></body></html> Finally, we loop through the tracks array. We assign the array's elements, which are XSPF_Track objects, into the $track variable. XSPF_Track also has getTitle and getCreator methods. Unlike XSPF's methods of the same names, getTitle returns the title of the track, and getCreator returns the track's artist. Running this file in your web browser will return a list populated with data from Last.fm. Services_YouTube Services_YouTube works in a manner very similar to File_XSPF. Like File_XSPF, it is an object-oriented abstraction layer on top of a more complicated system. In this case, the system is the YouTube API. Using Services_YouTube is a lot like using File_XSPF. Include the package in your code, instantiate a Services_YouTube object, and use this object's methods to interact with the service. The official documentation for the latest release of Services_YouTube is located at http://pear.php.net/package/Services_YouTube/docs/latest/. The package also contains online working examples at http://pear.php.net/manual/en/package.webservices.services-youtube.php. Many of the methods deal with getting members' information like their profile and videos they've uploaded. A smaller, but very important subset is used to query YouTube for videos. We will use this subset in our mashup. To get a list of videos that have been tagged with a specific tag, use the object's listByTag method. listByTag will query the YouTube service and store the XML response in memory. It is does not return an array of video objects we can directly manage, but with one additional function call, we can achieve this. From there, we can loop through an array of videos similar to what we did for XSPF tracks. The example file YouTubePearTest.php illustrates this process. <?php require_once 'Services/YouTube.php'; $dev_id = 'Your YouTube DeveloperID'; $tag = 'Social Distortion'; $youtube = new Services_YouTube($dev_id, array('usesCache' => true)); $videos = $youtube->listByTag($tag);?> First, we load the Services_YouTube file into our script. As YouTube's web service requires a Developer ID, we store that information into a local variable. After that, we place the tag we want to search for in another local variable named $tag. In this example, we are going to check out which videos YouTube has for the one of the greatest bands of all time, Social Distortion. Service_YouTube's constructor takes this Developer ID and uses it whenever it queries the YouTube web service. The constructor can take an array of options as a parameter. One of the options is to use a local cache of the queries. It is considered good practice to use a cache, as to not slam the YouTube server and run up your requests quota. Another option is to specify either REST or XML-RPC as the protocol via the driver key in the options array. By default, Services_YouTube uses REST. Unless you have a burning requirement to use XML-RPC, you can leave it as is. Once instantiated, you can call listByTag to get the response from YouTube. listByTag takes only one parameter—the tag of our desire. Services_YouTube now has the results from YouTube. We can begin the display of the results. <html><head> <title>Social Distortion Videos</title></head><body> <h1>YouTube Query Results for Social Distortion</h1> Next, we will loop through the videos. In order to get an array of video objects, we first need to parse the XML response. We do that using Services_YouTube's xpath method, which will use the powerful XPATH query language to go through the XML and convert it into PHP objects. We pass the XPATH query into the method, which will give us an array of useful objects. We will take a closer look at XPATH and XPATH queries later in another project. For now, trust that the query //video will return an array of video objects that we can examine. Within the loop, we display each video's title, a thumbnail image of the video, and a hyperlink to the video itself. <?php foreach ($videos->xpath('//video') as $i => $video) { ?><p> Title: <?= $video->title ?><br /> <img src='<?= $video->thumbnail_url ?>' alt='<?= $video->title ?>' /><br /> <a href='<?= $video->url ?>'>URL</a></p><?php } ?></body></html> Running this query in our web browser will give us a results page of videos that match the search term we submitted. XML_RSS Like the other PEAR extensions, XML_RSS changes something very complex, RSS, into something very simple and easy to use, PHP objects. The complete documentation for this package is at http://pear.php.net/package/XML_RSS/docs/XML_RSS. There is a small difference to the basic philosophy of XML_RSS compared to Services_YouTube and File_XSPF. The latter two packages take information from whatever we're interested in, and place them into PHP object properties. For example, File_XSPF takes track names into a Track object, and you use a getTitle() getter method to get the title of the track. In Services_YouTube, it's the same principle, but the properties are public, and so there are no getter methods. You access the video's properties directly in the video object. In XML_RSS, the values we're interested in are stored in associative arrays. The available methods in this package get the arrays, then you manipulate them directly. It's a small difference, but you should be aware of it in case you want to look at the code. It also means that you will have to check the documentation of the package to see which array keys are available to you. Let's take a look at how this works in an example. The file is named RSSPEARTest.php in the example code. One of Audioscrobbler's feeds gives us an RSS file of songs that a user recently played. The feed isn't always populated because after a few hours, songs that are played aren't considered recent. In other words, songs will eventually drop off the feed simply because they are too old. Therefore, it's best to use this feed on a heavy user of Last.fm. RJ is a good example to use. He seems to always be listening to something. We'll grab his feed from Audioscrobbler: <?php include ("XML/RSS.php"); $rss =& new XML_RSS("http://ws.audioscrobbler.com/1.0/user/RJ/ recenttracks.rss"); $rss->parse(); We start off by including the module and creating an XML_RSS object. XML_RSS is where all of the array get methods reside, and is the heart of this package. It's constructor method takes one variable—the path to the RSS file. At instantiation, the package loads the RSS file into memory. parse() is the method that actually does the RSS parsing. After this, the get methods will return data about the feed. Needless to say, parse() must be called before you do anything constructive with the file. $channelInfo = $rss->getChannelInfo();?> The package's getChannelInfo() method returns an array that holds information about the metadata, the channel, of the file. This array holds the title, description, and link elements of the RSS file. Each of these elements is stored in the array with the same key name as the element. <?= "<?xml version="1.0" encoding="UTF-8" ?>" ?> The data that comes back will be UTF-8 encoded. Therefore, we need to force the page into UTF-8 encoding mode. This line outputs the XML declaration into the top of the web page in order to insure proper rendering. Putting a regular <?xml declaration will trigger the PHP engine to parse the declaration. However, PHP will not recognize the code and halt the page with an error. <html> <head> <title><?= $channelInfo['title'] ?></title> </head> <body> <h1><?= $channelInfo['description'] ?></h1> Here we begin the actual output of the page. We start by using the array returned from getChannelInfo() to output the title and description elements of the feed. <ol> <?php foreach ($rss->getItems() as $item { ?> <li> <?= $item['title'] ?>: <a href="<?= $item ['link'] ?>"><?= $item ['link'] ?></a> </li> <?php } ?></ol> Next, we start outputting the items in the RSS file. We use getItems() to grab information about the items in the RSS. The return is an array that we loop through with a foreach statement. Here, we are extracting the item's title and link elements. We show the title, and then create a hyperlink to the song's page on Last.fm. The description and pubDate elements in the RSS are also available to us in getItems's returned array. Link to User: <a href="<?= $channelInfo['link'] ?>"><?= $channelInfo['link'] ?></a> </body></html> Finally, we use the channel's link property to create a hyperlink to the user's Last.fm page before we close off the page's body and html tags. Using More ElementsIn this example, the available elements in the channel and item arrays are a bit limited. getChannelInfo() returns an array that only has the title, description, and link properties. The array from getItems() only has title, description, link, and pubDate properties. This is because we are using the latest release version of XML_RSS. At the time of writing this book, it is version 0.9.2. The later versions of XML_RSS, currently in beta, handle many more elements. Elements in RSS 2.0 like category and authors are available. To upgrade to a beta version of XML_RSS, use the command PEAR upgrade –f XML_RSS in the command line. The –f flag is the same flag we used to force the beta and alpha installations of Service_YouTube and File_XSPF. Alternatively, you can install the beta version of XML_RSS at the beginning using the same –f flag. If we run this page on our web browser, we can see the successful results of our hit. At this point, we know how to use the Audioscrobbler feeds to get information. The majority of the feeds are either XSPF or RSS format. We know generally how the YouTube API works. Most importantly, we know how to use the respective PEAR packages to extract information from each web service. It's time to start coding our application. Mashing Up If you haven't already, you should, at the very least, create a YouTube account and sign up for a developer key. You should also create a Last.fm account, install the client software, and start listening to some music on your computer. This will personalize the video jukebox to your music tastes. All examples here will assume that you are using your own YouTube key. I will use my own Last.fm account for the examples. As the feeds are open and free, you can use the same feeds if you choose not to create a Last.fm account. Mashup Architecture There are obviously many ways in which we can set up our application. However, we're going to keep functionality fairly simple. The interface will be a framed web page. The top pane is the navigation pane. It will be for the song selection. The bottom section is the content pane and will display and play the video. In the navigation pane, we will create a select menu with all of our songs. The value, and label, for each option will be the artist name followed by a dash, followed by the name of the song (For example, "April Smith—Bright White Jackets"). Providing both pieces of information will help YouTube narrow down the selection. When the user selects a song and pushes a "Go" button, the application will load the content page into the content pane. This form will pass the artist and song information to the content page via a GET parameter. The content page will use this GET parameter to query YouTube. The page will pull up the first, most relevant result from its list of videos and display it. Main Page The main page is named jukebox.html in the example code. This is our frameset page. It will be quite simple. All it will do is define the frameset that we will use. <html><head><title>My Video Jukebox</title></head> <frameset rows="10%,90%"> <frame src="navigation.php" name="Navigation" /> <frame src="" name="Content" /> </frameset></html> This code defines our page. It is two frame rows. The navigation section, named Navigation, is 10% of the height, and the content, named Content, is the remaining 90%. When first loaded, the mashup will load the list of songs in the navigation page and nothing else.
Read more
  • 0
  • 0
  • 2167

article-image-ajax-form-validation-part-1
Packt
18 Feb 2010
4 min read
Save for later

AJAX Form Validation: Part 1

Packt
18 Feb 2010
4 min read
The server is the last line of defense against invalid data, so even if you implement client-side validation, server-side validation is mandatory. The JavaScript code that runs on the client can be disabled permanently from the browser's settings and/or it can be easily modified or bypassed. Implementing AJAX form validation The form validation application we will build in this article validates the form at the server side on the classic form submit, implementing AJAX validation while the user navigates through the form. The final validation is performed at the server, as shown in Figure 5-1: Doing a final server-side validation when the form is submitted should never be considered optional. If someone disables JavaScript in the browser settings, AJAX validation on the client side clearly won't work, exposing sensitive data, and thereby allowing an evil-intentioned visitor to harm important data on the server (for example, through SQL injection). Always validate user input on the server. As shown in the preceding figure, the application you are about to build validates a registration form using both AJAX validation (client side) and typical server-side validation: AJAX-style (client side): It happens when each form field loses focus (onblur). The field's value is immediately sent to and evaluated by the server, which then returns a result (0 for failure, 1 for success). If validation fails, an error message will appear and notify the user about the failed validation, as shown in Figure 5-3. PHP-style (server side): This is the usual validation you would do on the server—checking user input against certain rules after the entire form is submitted. If no errors are found and the input data is valid, the browser is redirected to a success page, as shown in Figure 5-4. If validation fails, however, the user is sent back to the form page with the invalid fields highlighted, as shown in Figure 5-3. Both AJAX validation and PHP validation check the entered data against our application's rules: Username must not already exist in the database Name field cannot be empty A gender must be selected Month of birth must be selected Birthday must be a valid date (between 1-31) Year of birth must be a valid year (between 1900-2000) The date must exist in the number of days for each month (that is, there's no February 31) E-mail address must be written in a valid email format Phone number must be written in standard US form: xxx-xxx-xxxx The I've read the Terms of Use checkbox must be selected Watch the application in action in the following screenshots: XMLHttpRequest, version 2 We do our best to combine theory and practice, before moving on to implementing the AJAX form validation script, we'll have another quick look at our favorite AJAX object—XMLHttpRequest. On this occasion, we will step up the complexity (and functionality) a bit and use everything we have learned until now. We will continue to build on what has come before as we move on; so again, it's important that you take the time to be sure you've understood what we are doing here. Time spent on digging into the materials really pays off when you begin to build your own application in the real world. Our OOP JavaScript skills will be put to work improving the existing script that used to make AJAX requests. In addition to the design that we've already discussed, we're creating the following features as well: Flexible design so that the object can be easily extended for future needs and purposes The ability to set all the required properties via a JSON object We'll package this improved XMLHttpRequest functionality in a class named XmlHttp that we'll be able to use in other exercises as well. You can see the class diagram in the following screenshot, along with the diagrams of two helper classes: settings is the class we use to create the call settings; we supply an instance of this class as a parameter to the constructor of XmlHttp complete is a callback delegate, pointing to the function we want executed when the call completes The final purpose of this exercise is to create a class named XmlHttp that we can easily use in other projects to perform AJAX calls. With our goals in mind, let's get to it! Time for action – the XmlHttp object In the ajax folder, create a folder named validate, which will host the exercises in this article.
Read more
  • 0
  • 0
  • 6943

article-image-author-podcast-aleksander-seovic-talks-about-oracle-coherence-35
Packt
17 Feb 2010
1 min read
Save for later

Author Podcast - Aleksander Seovic Talks About Oracle Coherence 3.5

Packt
17 Feb 2010
1 min read
Aleksander Seovic is the author of Oracle Coherence 3.5, which will help you to design and build scalable, reliable, high-performance applications using software of the same name. The book is due out in March, but you can get a flavour of it in his interview with Cameron Purdy, below. For more information on Aleksander's book, visit: http://www.packtpub.com/oracle-coherence-3-5/book. Listen Here      
Read more
  • 0
  • 0
  • 3361
article-image-web-scraping-python
Packt
17 Feb 2010
5 min read
Save for later

Web Scraping with Python

Packt
17 Feb 2010
5 min read
To perform this task, usually three basic steps are followed: Explore the website to find out where the desired information is located in the HTML DOM tree Download as many web pages as needed Parse downloaded web pages and extract the information from the places found in the exploration step The exploration step is performed manually with the aid of some tools that make it easier to locate the information and reduce the development time in next steps. The download and parsing steps are usually performed in an iterative cycle since they are interrelated. This is because the next page to download may depend on a link or similar in the current page, so not every web page can be downloaded without previously looking into the earlier one. This article will show an example covering the three steps mentioned and how this could be done using python with some development. The code that will be displayed is guaranteed to work at the time of writing, however it should be taken into account that it may stop working in future if the presentation format changes. The reason is that web scraping depends on the DOM tree to be stable enough, that is to say, as happens with regular expressions, it will work fine for slight changes in the information being parsed. However, when the presentation format is completely changed, the web scraping scripts have to be modified to match the new DOM tree. Explore Let's say you are a fan of Pack Publishing article network and that you want to keep a list of the titles of all the articles that have been published until now and the link to them. First of all, you will need to connect to the main article network page (http://www.packtpub.com/article-network) and start exploring the web page to have an idea about where the information that you want to extract is located. Many ways are available to perform this task such as view the source code directly in your browser or download it and inspect it with your favorite editor. However, HTML pages often contain auto-generated code and are not as readable as they should be, so using a specialized tool might be quite helpful. In my opinion, the best one for this task is the Firebug add-on for the Firefox browser. With this add-on, instead of looking carefully in the code looking for some string, all you have to do is press the Inspect button, move the pointer to the area in which you are interested and click. After that, the HTML code for the area marked and the location of the tag in the DOM tree will be clearly displayed. For example, the links to the different pages containing all the articles are located inside a right tag, and, in every page, the links to the articles are contained as list items in an unnumbered list. In addition to this, the links URLs, as you probably have noticed while reading other articles, start with http://www.packtpub.com/article/ So, our scraping strategy will be Get the list of links to all pages containing articles Follow all links so as to extract the article information in all pages One small optimization here is that main article network page is the same as the one pointed by the first page link, so we will take this into account to avoid loading the same page twice when we develop the code. Download Before parsing any web page, the contents of that page must be downloaded. As usual, there are many ways to do this: Creating your own HTTP requests using urllib2 standard python library Using a more advanced library that provides the capability to navigate through a website simulating a browser such as  mechanize. In this article mechanize will be covered as it is the easiest choice. mechanize is a library that provides a Browser class that lets the developer to interact with a website in a similar way a real browser would. In particular it provides methods to open pages, follow links, change form data and submit forms. Recalling the scraping strategy in our previous version, the first thing we would like to do is to download the main article network web page. To do that we will create a Browser class instance and then open the main article network page: >>> import mechanize>>> BASE_URL = "http://www.packtpub.com/article-network">>> br = mechanize.Browser()>>> data = br.open(BASE_URL).get_data()>>> links = scrape_links(BASE_URL, data) Where the result of the open method is an HTTP response object, the get_data method returns the contents of the web page. The scrape_links function will be explained later. For now, as pointed out in the introduction section, bear in mind that the downloading and parsing steps are usually performed iteratively since some contents to be downloaded depends on the parsing done in some kind of initial contents such as in this case.
Read more
  • 0
  • 0
  • 9367

article-image-forms-grok-10
Packt
12 Feb 2010
13 min read
Save for later

Forms in Grok 1.0

Packt
12 Feb 2010
13 min read
A quick demonstration of automatic forms Let's start by showing how this works, before getting into the details. To do that, we'll add a project model to our application. A project can have any number of lists associated with it, so that related to-do lists can be grouped together. For now, let's consider the project model by itself. Add the following lines to the app.py file, just after the Todo application class definition. We'll worry later about how this fits into the application as a whole. class IProject(interface.Interface): name = schema.TextLine(title=u'Name',required=True) kind = schema.Choice(title=u'Kind of project', values=['personal','business']) description = schema.Text(title=u'Description')class AddProject(grok.Form): grok.context(Todo) form_fields = grok.AutoFields(IProject) We'll also need to add a couple of imports at the top of the file: from zope import interfacefrom zope import schema Save the file, restart the server, and go to the URL http://localhost:8080/todo/addproject. The result should be similar to the following screenshot: OK, where did the HTML for the form come from? We know that AddProject is some sort of a view, because we used the grok.context class annotation to set its context and name. Also, the name of the class, but in lowercase, was used in the URL, like in previous view examples. The important new thing is how the form fields were created and used. First, a class named IProject was defined. The interface defines the fields on the form, and the grok.AutoFields method assigns them to the Form view class. That's how the view knows which HTML form controls to generate when the form is rendered. We have three fields: name, description, and kind. Later in the code, the grok.AutoFields line takes this IProject class and turns these fields into form fields. That's it. There's no need for a template or a render method. The grok.Form view takes care of generating the HTML required to present the form, taking the information from the value of the form_fields attribute that the grok.AutoFields call generated. Interfaces The I in the class name stands for Interface. We imported the zope.interface package at the top of the file, and the Interface class that we have used as a base class for IProject comes from this package. Example of an interface An interface is an object that is used to specify and describe the external behavior of objects. In a sense, the interface is like a contract. A class is said to implement an interface when it includes all of the methods and attributes defined in an interface class. Let's see a simple example: from zope import interfaceclass ICaveman(interface.Interface): weapon = interface.Attribute('weapon') def hunt(animal): """Hunt an animal to get food""" def eat(animal): """Eat hunted animal""" def sleep() """Rest before getting up to hunt again""" Here, we are describing how cavemen behave. A caveman will have a weapon, and he can hunt, eat, and sleep. Notice that the weapon is an attribute—something that belongs to the object, whereas hunt, eat, and sleep are methods. Once the interface is defined, we can create classes that implement it. These classes are committed to include all of the attributes and methods of their interface class. Thus, if we say: class Caveman(object): interface.implements(ICaveman) Then we are promising that the Caveman class will implement the methods and attributes described in the ICaveman interface: weapon = 'ax'def hunt(animal): find(animal) hit(animal,self.weapon)def eat(animal): cut(animal) bite()def sleep(): snore() rest() Note that though our example class implements all of the interface methods, there is no enforcement of any kind made by the Python interpreter. We could define a class that does not include any of the methods or attributes defined, and it would still work. Interfaces in Grok In Grok, a model can implement an interface by using the grok.implements method. For example, if we decided to add a project model, it could implement the IProject interface as follows: class Project(grok.Container): grok.implements(IProject) Due to their descriptive nature, interfaces can be used for documentation. They can also be used for enabling component architectures, but we'll see about that later on. What is of more interest to us right now is that they can be used for generating forms automatically. Schemas The way to define the form fields is to use the zope.schema package. This package includes many kinds of field definitions that can be used to populate a form. Basically, a schema permits detailed descriptions of class attributes that are using fields. In terms of a form—which is what is of interest to us here—a schema represents the data that will be passed to the server when the user submits the form. Each field in the form corresponds to a field in the schema. Let's take a closer look at the schema we defined in the last section: class IProject(interface.Interface): name = schema.TextLine(title=u'Name',required=True) kind = schema.Choice(title=u'Kind of project', required=False, values=['personal','business']) description = schema.Text(title=u'Description', required=False) The schema that we are defining for IProject has three fields. There are several kinds of fields, which are listed in the following table. In our example, we have defined a name field, which will be a required field, and will have the label Name beside it. We also have a kind field, which is a list of options from which the user must pick one. Note that the default value for required is True, but it's usually best to specify it explicitly, to avoid confusion. You can see how the list of possible values is passed statically by using the values parameter. Finally, description is a text field, which means it will have multiple lines of text. Available schema attributes and field types In addition to title, values, and required, each schema field can have a number of properties, as detailed in the following table: Attribute Description title A short summary or label. description A description of the field. required Indicates whether a field requires a value to exist. readonly If True, the field's value cannot be changed. default The field's default value may be None, or a valid field value. missing_value If input for this field is missing, and that's OK, then this is the value to use. order The order attribute can be used to determine the order in which fields in a schema are defined. If one field is created after another (in the same thread), its order will be greater. In addition to the field attributes described in the preceding table, some field types provide additional attributes. In the previous example, we saw that there are various field types, such as Text, TextLine, and Choice. There are several other field types available, as shown in the following table. We can create very sophisticated forms just by defining a schema in this way, and letting Grok generate them. Field type Description Parameters Bool Boolean field.   Bytes Field containing a byte string (such as the python str). The value might be constrained to be within length limits.   ASCII Field containing a 7-bit ASCII string. No characters > DEL (chr(127)) are allowed. The value might be constrained to be within length limits.   BytesLine Field containing a byte string without new lines.   ASCIILine Field containing a 7-bit ASCII string without new lines.   Text Field containing a Unicode string.   SourceText Field for the source text of an object.   TextLine Field containing a Unicode string without new lines.   Password Field containing a Unicode string without new lines, which is set as the password.   Int Field containing an Integer value.   Float Field containing a Float.   Decimal Field containing a Decimal.   DateTime Field containing a DateTime.   Date Field containing a date.   Timedelta Field containing a timedelta.   Time Field containing time.   URI A field containing an absolute URI.   Id A field containing a unique identifier. A unique identifier is either an absolute URI or a dotted name. If it's a dotted name, it should have a module or package name as a prefix.   Choice Field whose value is contained in a predefined set. values: A list of text choices for the field. vocabulary: A Vocabulary object that will dynamically produce the choices. source: A different, newer way to produce dynamic choices. Note: only one of the three should be provided. More information about sources and vocabularies is provided later in this book. Tuple Field containing a value that implements the API of a conventional Python tuple. value_type: Field value items must conform to the given type, expressed via a field. Unique. Specifies whether the members of the collection must be unique. List Field containing a value that implements the API of a conventional Python list. value_type: Field value items must conform to the given type, expressed via a field. Unique. Specifies whether the members of the collection must be unique. Set Field containing a value that implements the API of a conventional Python standard library sets.Set or a Python 2.4+ set. value_type: Field value items must conform to the given type, expressed via a field. FrozenSet Field containing a value that implements the API of a conventional Python2.4+ frozenset. value_type: Field value items must conform to the given type, expressed via a field. Object Field containing an object value. Schema: The interface that defines the fields comprising the object. Dict Field containing a conventional dictionary. The key_type and value_type fields allow specification of restrictions for keys and values contained in the dictionary. key_type: Field keys must conform to the given type, expressed via a field. value_type: Field value items must conform to the given type, expressed via a field. Form fields and widgets Schema fields are perfect for defining data structures, but when dealing with forms sometimes they are not enough. In fact, once you generate a form using a schema as a base, Grok turns the schema fields into form fields. A form field is like a schema field but has an extended set of methods and attributes. It also has a default associated widget that is responsible for the appearance of the field inside the form. Rendering forms requires more than the fields and their types. A form field needs to have a user interface, and that is what a widget provides. A Choice field, for example, could be rendered as a <select> box on the form, but it could also use a collection of checkboxes, or perhaps radio buttons. Sometimes, a field may not need to be displayed on a form, or a writable field may need to be displayed as text instead of allowing users to set the field's value. Form components Grok offers four different components that automatically generate forms. We have already worked with the first one of these, grok.Form. The other three are specializations of this one: grok.AddForm is used to add new model instances. grok.EditForm is used for editing an already existing instance. grok.DisplayForm simply displays the values of the fields. A Grok form is itself a specialization of a grok.View, which means that it gets the same methods as those that are available to a view. It also means that a model does not actually need a view assignment if it already has a form. In fact, simple applications can get away by using a form as a view for their objects. Of course, there are times when a more complex view template is needed, or even when fields from multiple forms need to be shown in the same view. Grok can handle these cases as well, which we will see later on. Adding a project container at the root of the site To get to know Grok's form components, let's properly integrate our project model into our to-do list application. We'll have to restructure the code a little bit, as currently the to-do list container is the root object of the application. We need to have a project container as the root object, and then add a to-do list container to it. To begin, let's modify the top of app.py, immediately before the TodoList class definition, to look like this: import grokfrom zope import interface, schemaclass Todo(grok.Application, grok.Container): def __init__(self): super(Todo, self).__init__() self.title = 'To-Do list manager' self.next_id = 0 def deleteProject(self,project): del self[project] First, we import zope.interface and zope.schema. Notice how we keep the Todo class as the root application class, but now it can contain projects instead of lists. We also omitted the addProject method, because the grok.AddForm instance is going to take care of that. Other than that, the Todo class is almost the same. class IProject(interface.Interface): title = schema.TextLine(title=u'Title',required=True) kind = schema.Choice(title=u'Kind of project',values=['personal', 'business']) description = schema.Text(title=u'Description',required=False) next_id = schema.Int(title=u'Next id',default=0) We then have the interface definition for IProject, where we add the title, kind, description, and next_id fields. These were the fields that we previously added during the call to the __init__ method at the time of product initialization. class Project(grok.Container): grok.implements(IProject) def addList(self,title,description): id = str(self.next_id) self.next_id = self.next_id+1 self[id] = TodoList(title,description) def deleteList(self,list): del self[list] The key thing to notice in the Project class definition is that we use the grok.implements class declaration to see that this class will implement the schema that we have just defined. class AddProjectForm(grok.AddForm): grok.context(Todo) grok.name('index') form_fields = grok.AutoFields(Project) label = "To begin, add a new project" @grok.action('Add project') def add(self,**data): project = Project() self.applyData(project,**data) id = str(self.context.next_id) self.context.next_id = self.context.next_id+1 self.context[id] = project return self.redirect(self.url(self.context[id])) The actual form view is defined after that, by using grok.AddForm as a base class. We assign this view to the main Todo container by using the grok.context annotation. The name index is used for now, so that the default page for the application will be the 'add form' itself. Next, we create the form fields by calling the grok.AutoFields method. Notice that this time the argument to this method call is the Project class directly, rather than the interface. This is possible because the Project class was associated with the correct interface when we previously used grok.implements. After we have assigned the fields, we set the label attribute of the form to the text: To begin, add a new project. This is the title that will be shown on the form. In addition to this new code, all occurrences of grok.context(Todo) in the rest of the file need to be changed to grok.context(Project), as the to-do lists and their views will now belong to a project and not to the main Todo application. For details, take a look at the source code of this article for Grok 1.0 Web Development>>Chapter 5.
Read more
  • 0
  • 0
  • 1881

article-image-trunks-using-3cx-part-1
Packt
12 Feb 2010
11 min read
Save for later

Trunks using 3CX: Part 1

Packt
12 Feb 2010
11 min read
PSTN trunks A Public Switch Telephone Network (PSTN) trunk is an old fashioned analog Basic Rate Interface (BRI) ISDN or Primary Rate Interface (PRI) phone line. 3CX can use any of these with the correct analog to SIP gateway. Usually these come into your home or business through a pair of copper lines. Depending on where you live, this may be the only means of connecting 3CX and communicating outside of your network. One of the advantages of a PSTN line is reliability and great call quality. Unless the wires break, you will almost always have phone service. However, what about call quality? After all, many people would like to have a comparison between VoIP and PSTN. Analog hardware for BRI ISDN and PRI's will be discussed in greater detail in Chapter 9. For using an analog PSTN line, you will need an FXO gateway. There are many external ones available. Until Sangoma introduced a new line at the end of 2008, there had not been any gateway which worked inside a Windows PC with 3CX. There are many manufacturers of analog gateways such as Linksys, Audio-Codes, Patton Electronics, GrandStream, and Sangoma. What these FXO gateways do is convert the analog phone line into IP signaling. Then the IP signaling gets passed over your network to the 3CX server and your phones. My personal preference is Patton Electronics. They are probably the most expensive FXOs' out there, but in this case, you get what you pay for. I have tried all of them and they all work. Some have issues with echo which can be hard to get rid of without support, or lots of trial and error, whereas some cannot support high demands (40 calls/hour) without needing to be reset every day, so if you are just testing, get a low-end one. For a high demand business, my preference is Patton. Not only do they make great products, but their support is top notch too. We will configure a Patton SmartNode SN4114 later in this article. SIP trunks What is a SIP trunk? A SIP trunk is a call that is routed by IP over the Internet through an Internet Telephony Service Provider (ITSP). For enterprises wanting to make full use of their installed IP PBXs' and communicate over IP not only within the enterprise, but also outside the enterprise—a SIP trunk provided by an ITSP that connects to the traditional PSTN network is the solution. Unlike traditional telephony, where bundles of physical wires were once delivered from the service provider to a business, a SIP trunk allows a company to replace traditional fixed PSTN lines with PSTN connectivity via a SIP trunking service provider on the Internet. SIP trunks can offer significant cost savings for enterprises, eliminating the need for local PSTN gateways, costly ISDN BRI's or PRI's. The following figure is an example of how our phone system operates: You can see that we have a local area network containing our desktops, servers, phones, and our 3CX Phone System. To reach the outside world using a SIP trunk, we have to go through our firewall or router. Depending on your network, you could be using a private IP address (10.x.x.x, 172.16.x.x, or 192.168.x.x) which is not allowed on the public Internet, so it has to get translated to the public IP address. This translation process is called Network Address Translation (NAT). Once we get outside the local network, we are in the public realm. Our ITSP uses the internet to get our phone call to/from the various carriers PSTN (analog) lines where our phone call is connected/terminated. There are three components necessary to successfully deploy SIP trunks: A PBX with a SIP-enabled trunk side An enterprise edge device understanding SIP An Internet Telephony or SIP trunking service provider The PBX In most cases, the PBX is an IP-based PBX, communicating with all endpoints over IP. However, it may just as well be a traditional digital or analog PBX. The sole requirement that has to be available is an interface for SIP trunking connectivity. The enterprise border element The PBX on the LAN connects to the ITSP via the enterprise border element. The enterprise edge component can either be a firewall with complete support for SIP, or an edge device connected to the firewall handling the traversal of the SIP traffic. The ITSP On the Internet, the ITSP provides connectivity to the PSTN for communication with mobile and fixed phones. Choosing a VoIP carrier—more than just price I feel two of the most important features to look for when choosing a VoIP carrier is support and call quality. Usually once you setup and everything is working, you won't need support. I always tell clients that there is no "boxed" solution that I can sell, every installation is a little different. Internet connections are all different even with the same provider. If you have a rock-solid T1 or something better, then this shouldn't be a problem. DSL seems different from building to building, even in the same area. So how do you test support before giving them your credit card? Call them! Try calling support at the worst times such as Monday afternoons when everyone is back to work and online, also try calling after business hours. See how long does it take to connect to a live person and if you can understand them once you speak to them? Find where is their support located? Try talking to them and tell them you are thinking about signing up with their service and ask them for help. If they go out of their way before they have your money, chances are they will be good to work with later on. Some carriers only offer chat or email support in favor of lower prices. While this may work fine for your business, it certainly won't work for the ones who need answers right away. I know I seem to be stressing a lot on support but it's for good reason. If your business depends on phone service and it goes down then you need answers! I pay more for a product if the support is worth it. Part of this is your Return On Investment (ROI). For example, if you have 3 lawyers billing at $200/hour and they need phones to work, that's $600/hour of lost time. Does the extra $50 or $100 upfront cover that? Now back to the topic at hand. Once you have connected 3CX to the carrier, how is the call quality? If it sounds like a bad cell phone, you probably don't want it, unless the price is so cheap that you can live with the low quality. Certain carriers even change the way your call gets routed through the Internet, based on the lowest cost for the particular call. They don't care about quality as long as you get that connection and they make money on it. Concurrent calls with an ITSP are a feature that you may want to look for when choosing an ITSP. Some accounts are a one-to-one ratio of lines per call. If you want to have 5 people on the phone at the same time (inbound or outbound), you would need to pay for 5 lines, this is similar to a PSTN line. You may get some savings here over a PSTN but that depends on what is available in your area. Some ITSP's have concurrent calls where you can use more than one line per call. Not many carriers have this feature but for a small business, this can be a great cost saving feature to look for. I use a couple of different carriers that have this feature. One carrier that I use lets you have 3 concurrent calls simultaneously on the same line. If you need more than 3 calls, you're a higher use customer and they want you to buy several lines. VoIP IP signaling uses special algorithms to compress your voice into IP packets. This compression uses a codec. There are several available, but the most common one is G.711u-law or A-law. This uses about 80kpbs of upload and download bandwidth. Another popular codec is G.729, it uses about 36kpbs. So for the same bandwidth you can have twice the number of calls using G.729 than G.711. You will need to check with your ITSP and see what codec they support. Another carrier I use is based purely on how much internet bandwidth you have. If you have 1Mbps of upload speed (usually the slowest part of your internet connection), you can support about 10 simultaneous or concurrent calls using G.711. You then pay for the minutes you use. This works very well for a small office as your monthly bill is very low and you don't have to maintain a bunch of lines that don't get used. Cable internet providers are also offering VoIP service to your home or business. These are usually single-use lines but they terminate at your office with an FXS plug. To integrate this with 3CX, you will need an FXO just like it's a PSTN line, same setup but you get the advantage of a VoIP line. Another great benefit of a SIP trunk is expandability. You can easily start out with one line which can usually be completed in one day. As you grow you can add more, usually in minutes as you already have the plan setup. Time to consolidate lines? You can even drop them later on without having contracts (most of the time). Try doing that with the local phone company! Call for a new business and it can take 1-2 weeks to get set up, plus contracts to worry about. No wonder they are jumping on the VoIP band wagon. Disaster recovery What do you do when your internet goes down? Some of you might be saying, "Ha! It never goes down". In my experience, it will eventually, and at the worst time. So what do you do? Go home for the day or plan for a backup? Most VoIP carriers provide some kind of disaster recovery option. They try to send you a call and when they don't get a connection to your 3CX box; then then re-route the call to another phone number. This could be a PSTN line or even a cell phone. It can be a free feature or there can be a small monthly fee on the account. It's worth having, especially if you rely on phones. Okay, so that covers inbound disaster recovery. What about outbound? Yes just about everyone has a cell phone these days, if that isn't enough, I'd suggest you invest in a pay-per-use PSTN line. This keeps the monthly cost very low but it's there when you need it. Whether it's an emergency pizza order for that Friday afternoon party or a true emergency when someone panics and dials 911—you want that call to go out. Speaking of emergency numbers, make sure you have your carrier register that phone number to your local address. Let's say you are in New York and you have a Californian phone number to give you some local presence in that part of the country. Your co-worker grabs his chest and falls down and someone dials 911 from the closest phone they see. Emergency services see your Californian number and contacts California for help for your New York office, that's not what you want when someone is clutching their chest, even though it was just heartburn from that pepperoni pizza. Mixing VoIP and PSTN Some of my clients even mix VoIP and PSTN together. Why would you mix? Local calls and inbound calls use the PSTN lines for the best call quality (and do not use any VoIP minutes if they have to pay for those). Long distance calls use the cheaper rate VoIP line. Another scenario is using PSTN lines for all your incoming and outgoing calls and use VoIP to talk to your other offices. Your own office can deal with a lower call quality, and management will appreciate the lower cost. These types of setups can be controlled using a dial plan.
Read more
  • 0
  • 0
  • 3982
article-image-trunks-using-3cx-part-2
Packt
12 Feb 2010
7 min read
Save for later

Trunks using 3CX: Part 2

Packt
12 Feb 2010
7 min read
The next wizard screen is for Outbound Call Rules. Let's go over it enough so that you can setup a simple rule. We start off with a name. This can be anything you like but I prefer something meaningful. For our example I want to dial 9 to use the analog line, and only allow extensions 100-102 to use this line. I also only want to be able to dial certain phone numbers. Then I have to delete the 9 before it goes out to the phone carrier. Let's have a look at each section of this screen: Calls to numbers starting with (Prefix) This is where you specify what you want someone to dial before the line is used. You could enter a string of numbers here to use as a "password" to dial out. You don't just let anyone call an international phone number, so set this to a string of numbers to use as your international password. Give the password only to those who need it. Just make sure you change it occasionally in case it slips out. Calls from extension(s) Now, you can specify who (by extension number) can use this gateway. Just enter the extension number(s) you want to allow either in a range (100-110), individually (100, 101, 104), or as a mix (100-103, 110). Usually, you will leave this open for everyone to use; otherwise, you will restrict extensions that were allowed to use the gateway, which will have repercussions of forwarding rules to external numbers. Calls to numbers with a length of This setting can be left blank if you want all calls to be able to go out on this gateway. In the next screenshot, I specified 3, 7, 10, and 11. This covers calls to 911, 411, 555-1234, 800-555-1234, and 1-800-555-1234, respectively. You can control what phone numbers go out based on the number of digits that are dialed. Route and strip options Since this is our only gateway right now, we will have it route the calls to the Patton gateway. The Strip Digits option needs to be set to 1. This will strip out the "9" that we specified above to dial out with. We can leave the Prepend section blank for now. Now, go ahead and click Finish: Once you click Finish, you will see a gateway wizard summary, as shown in the next screenshot. This shows you that the gateway is created, and it also gives an overview of the settings. Your next step is to get those settings configured on your gateway. There is a list of links for various supported gateways on the bottom of the summary page with up-to-date instructions. Feel free to visit those links. These links will take you to the 3CX website and explain how to configure that particular gateway. With Patton this is easy; click the Generate config file button. The only other information you need for the configuration file is the Subnet mask for the Patton gateway. Enter your network subnet mask in the box. Here, I entered a standard Class C subnet mask. This matches my 192.168.X.X network. Click OK when you are done: Once you click OK, your browser will prompt you to save the file, as shown in the following screenshot. Click Save: The following screenshot shows a familiar Save As Windows screen. I like to put this file in an easy-to-remember location on my hard drive. As I already have a 3CX folder created, I'm going to save the file there. You can change the name of the file if you wish. Click Save: Now that your file is saved, let's take a look at modifying those settings. Open the administration web interface and, on the left-hand side, click PSTN Devices. Go ahead and expand this by clicking the + sign next to it. Now, you will see our newly created Patton SN4114A gateway listed. Click the + sign again and expand that gateway. Next, click the Patton SN4114A name, and you will see the right-hand side window pane fill up with five separate tabs. The first tab is General. This is where you can change the gateway IP address, SIP port, and all the account details. If you change anything, you will need a new configuration file. So click the Generate config file button at the bottom of the screen. If you forgot to save the file previously, here's your chance to generate and save it again: On the Advanced tab, we have some Provider Capabilities. Leave these settings alone for now: We will leave the rest of the tabs for now. Go ahead and click the 10000 line information in the navigation pane on the left. These are the settings for that particular phone port (10000). The first group of settings that we can change is the authentication username and password. Remember, this is to register the line with 3CX and not to use the phone line. The next two sections are about what to do with an inbound call during Office Hours and Outside Office Hours. I didn't change anything from the gateway wizard but, on this screen, you can see that we selected Ring group 800 MainRingGroup. This is the Ring group that we configured previously. We also see similar drop-down boxes for Outside Office Hours. As no one will be in the office to answer the phone, I've selected a Digital Receptionist 801 DR1. In the section Other Options, the Outbound Caller ID box is used to enter what you would like to have presented to the outside world as caller ID information. If your phone carrier supports this, you can enter a phone number or a name. If the carrier does not support this, just leave it blank and talk to your carrier as to what you would require to have it assigned as your caller ID. The Allow outbound calls on this line and Allow incoming calls on this line checkboxes are used to limit calls in or out. Depending on your environment, you might want to leave one line selected as no outbound calls. This will always leave an incoming line for customers to call. Otherwise, unless you have other lines that they can call on, they will get a busy signal. Maximum simultaneous calls cannot be changed here as analog lines only support one call at a time. If you changed anything, click Apply and then go back and generate a new configuration file: For the most up-to-date information on configuring your gateway, visit the 3CX site: http://www.3cx.com/voip-gateways/index.html We will go over a summary of it here: Since nothing was changed, it is now time to configure the Patton device with the config file that we generated from the 3CX template. If you know the IP address of the device, go ahead and open a browser and navigate to that IP address. Mine would be http://192.168.2.10. If you do not know the IP address of your device, you will need the SmartNode discovery tool. The easiest place to get this tool is the CD that came with the device. You can also download it from http://www.3cx.com/downloads/misc/sndiscovery.zip, or search the Patton website for it. Go ahead and install the SmartNode discovery tool and run it. You will get a screen that tells you all the SmartNodes on your network with their IP address, MAC address, and firmware version. Double-click on the SmartNode to open the web interface in a browser. The default username is administrator, and the password field is left blank. Click Import/Export on the left and Import Configuration on the right. Click Browse to find the configuration file that we generated. Click Import and then Reload to restart the gateway with the new configuration. That's it . We can now get incoming calls and make an outbound call.
Read more
  • 0
  • 0
  • 2986

article-image-testing-and-debugging-grok-10-part-1
Packt
11 Feb 2010
12 min read
Save for later

Testing and Debugging in Grok 1.0: Part 1

Packt
11 Feb 2010
12 min read
Grok offers some tools for testing, and in fact, a project created by grokproject (as the one we have been extending) includes a functional test suite. In this article, we are going to discuss testing a bit and then write some tests for the functionality that our application has so far. Testing helps us avoid bugs, but it does not eliminate them completely, of course. There are times when we will have to dive into the code to find out what's going wrong. A good set of debugging aids becomes very valuable in this situation. We'll see that there are several ways of debugging a Grok application and also try out a couple of them. Testing It's important to understand that testing should not be treated as an afterthought. As mentioned earlier, agile methodologies place a lot of emphasis on testing. In fact, there's even a methodology called Test Driven Development (TDD), which not only encourages writing tests for our code, but also writing tests before any other line of code. There are various kinds of testing, but here we'll briefly describe only two: Unit testing Integration or functional tests Unit testing The idea of unit testing is to break a program into its constituent parts and test each one of them in isolation. Every method or function call can be tested separately to make sure that it returns the expected results and handles all of the possible inputs correctly. An application which has unit tests that cover the majority of its lines of code, allows its developers to constantly run the tests after a change, and makes sure that modifications to the code do not break the existing functionality. Functional tests Functional tests are concerned with how the application behaves as a whole. In a web application, this means how it responds to a browser request and whether it returns the expected HTML for a given call. Ideally, the customer himself has a hand in defining these tests, usually through explicit functionality requirements or acceptance criteria. The more formal the requirements from the customer are, the easier it is to define appropriate functional tests. Testing in Grok Grok highly encourages the use of both kinds of tests, and in fact, includes a powerful testing tool that is automatically configured with every project. In the Zope world—from where Grok originated—a lot of value is placed in a kind of tests known as "doctests", so Grok comes with a sample test suite of this kind. Doctests A doctest is a test that's written as a text file, with lines of code mixed with explanations of what the code is doing. The code is written in a way that simulates a Python interpreter session. As tests exercise large portions of the code (ideally 100%), they usually offer a good way of finding out of what an application does and how. So, if an application has no written documentation, its tests would be the next obvious way of finding out what it does. Doctests take this idea further by allowing the developer to explain in the text file exactly what each test is doing. Doctests are especially useful for functional testing, because it makes more sense to document the high-level operations of a program. Unit tests, on the other hand, are expected to evaluate the program bit by bit and it can be cumbersome to write a text explanation for every little piece of code. A possible drawback of doctests is that they can make the developer think that he needs no other documentation for his project. In almost all of the cases, this is not true. Documenting an application or package makes it immediately more accessible and useful, so it is strongly recommended that doctests should not be used as a replacement for good documentation. We'll show an example of using doctests in the Looking at the test code section of this article. Default test setup for Grok projects As mentioned above, Grok projects that are started with the grokproject tool already include a simple functional test suite by default. Let's examine it in detail. Test configuration The default test configuration looks for packages or modules that have the word 'tests' in their name and tries to run the tests inside. For functional tests, any files ending with .txt or .rst are considered. For functional tests that need to simulate a browser, a special configuration is needed to tell Grok which packages to initialize in addition to the Grok infrastructure (usually the ones that are being worked on). The ftesting.zcml file in the package directory has this configuration. This also includes a couple of user definitions that are used by certain tests to examine functionality specific to a certain role, such as manager. Test files Besides the already mentioned ftesting.zcml file, in the same directory, there is a tests.py file added by grokproject, which basically loads the ZCML declarations and registers all of the tests in the package. The actual tests that are included with the default project files are contained in the app.txt file. These are doctests that do a functional test run by loading the entire Grok environment and imitating a browser. We'll take a look at the contents of the file soon, but first let's run the tests. Running the tests As part of the project's build process, a script named test is included in the bin directory when you create a new project. This is the test runner and calling it without arguments, finds and executes all of the tests in the packages that are included in the configuration. We haven't added a single test so far, so if we type bin/test in our project directory, we'll see more or less the same thing that doing that on a new project would show: $ bin/testRunning tests at level 1 Running todo.FunctionalLayer tests: Set up in 12.319 seconds. Running: ...2009-09-30 15:00:47,490 INFO sqlalchemy.engine.base.Engine.0x...782c PRAGMA table_info("users") 2009-09-30 15:00:47,490 INFO sqlalchemy.engine.base.Engine.0x...782c () Ran 3 tests with 0 failures and 0 errors in 0.465 seconds. Tearing down left over layers: Tear down todo.FunctionalLayer ... not supported The only difference between our output to that of a newly created Grok package is in the sqlalchemy lines. Of course, the most important part of the output is the "penultimate" line, which shows the number of tests that were run and whether there were any failures or errors. A failure means that some test didn't pass, which means that the code is not doing what it's supposed to do and needs to be checked. An error signifies that the code crashed unexpectedly at some point, and the test couldn't even be executed, so it's necessary to find the error and correct it before worrying about the tests. The test runner The test runner program looks for modules that contain tests. The test can be of three different types: Python tests, simple doctests, and full functionality doctests. To let the test runner know, which test file includes which kind of tests, a comment similar to the following is placed at the top of the file: Do a Python test on the app. :unittest: In this case, the Python unit test layer will be used to run the tests. The other value that we are going to use is "doctest" when we learn how to write doctests. The test runner then finds all of the test modules and runs them in the corresponding layer. Although unit tests are considered very important in regular development, we may find functional tests more necessary for a Grok web application, as we will usually be testing views and forms, which require the full Zope/Grok stack to be loaded to work. That's the reason why we find only functional doctests in the default setup. Test layers A test layer is a specific test setup which is used to differentiate the tests that are executed. By default, there is a test layer for each of the three types of tests handled by the test runner. It's possible to run a test layer without running the others and also to name new test layers to be able to cluster together tests that require a specific setup. Invoking the test runner As shown above, running bin/test will start the test runner with the default options. It's also possible to specify a number of options, and the most important ones are summarized below. In the following table, command-line options are shown to the left. Most options can be expressed with a short form (one dash) or a long form (two dashes). Arguments for the option in question are shown in uppercase. -s PACKAGE, --package=PACKAGE, --dir=PACKAGE Search the given package's directories for tests. This can be specified more than once, to run tests in multiple parts of the source tree. For example, when refactoring interfaces, you don't want to see the way you have broken setups for tests in other packages. You just want to run the interface tests. Packages are supplied as dotted names. For compatibility with the old test runner, forward and backward slashes in package names are converted to dots. (In the special case of packages, which are spread over multiple directories, only directories within the test search path are searched.) -m MODULE, --module=MODULE Specify a test-module filter as a regular expression. This is a case sensitive regular expression, which is used in search (not match) mode, to limit which test modules are searched for tests. The regular expressions are checked against dotted module names. In an extension of Python regexp notation, a leading "!" is stripped and causes the sense of the remaining regexp to be negated (so "!bc" matches any string that does not match "bc", and vice versa). The option can specy multiple test-module filters. Test modules matching any of the test filters are searched. If no test-module filter is specified, then all of the test modules are used. -t TEST, --test=TEST Specify a test filter as a regular expression. This is a case sensitive regular expression, which is used in search (not match) mode, to limit which tests are run. In an extension of Python regexp notation, a leading "!" is stripped and causes the sense of the remaining regexp to be negated (so "!bc" matches any string that does not match "bc", and vice versa). The option can specify multiple test filters. Tests matching any of the test filters are included. If no test filter is specified, then all of the tests are executed. --layer=LAYER Specify a test layer to run. The option can be given multiple times to specify more than one layer. If not specified, all of the layers are executed. It is common for the running script to provide default values for this option. Layers are specified regular expressions that are used in search mode, for dotted names of objects that define a layer. In an extension of Python regexp notation, a leading "!" is stripped and causes the sense of the remaining regexp to be negated (so "!bc" matches any string that does not match "bc", and vice versa). The layer named 'unit' is reserved for unit tests, however, take note of the -unit and non-unit options. -u, --unit Executes only unit tests, ignoring any layer options. -f, --non-unit Executes tests other than unit tests. -v, --verbose Makes output more verbose. Increment the verbosity level. -q, --quiet Makes the output minimal by overriding any verbosity options. Looking at the test code Let's take a look at the three default test files of a Grok project, to see what each one does. ftesting.zcml As we explained earlier, ftesting.zcml is a configuration file for the test runner. Its main objective is to help us set up the test instance with users, so that we can test different roles according to our needs. <configure i18n_domain="todo" package="todo" > <include package="todo" /> <include package="todo_plus" /> <!-- Typical functional testing security setup --> <securityPolicy component="zope.securitypolicy.zopepolicy.ZopeSecurityPolicy" /> <unauthenticatedPrincipal id="zope.anybody" title="Unauthenticated User" /> <grant permission="zope.View" principal="zope.anybody" /> <principal id="zope.mgr" title="Manager" login="mgr" password="mgrpw" /> <role id="zope.Manager" title="Site Manager" /> <grantAll role="zope.Manager" /> <grant role="zope.Manager" principal="zope.mgr" /> As shown in the preceding code, the configuration simply includes a security policy, complete with users and roles and the packages that should be loaded by the instance, in addition to the regular Grok infrastructure. If we run any tests that require an authenticated user to work, we'll use these special users. The includes at the top of the file just make sure that all of the Zope Component Architecture setup needed by our application is performed prior to running the tests. tests.py The default test module is very simple. It defines the functional layer and registers the tests for our package: import os.path import z3c.testsetup import todo from zope.app.testing.functional import ZCMLLayer ftesting_zcml = os.path.join( os.path.dirname(todo.__file__), 'ftesting.zcml') FunctionalLayer = ZCMLLayer(ftesting_zcml, __name__, 'FunctionalLayer', allow_teardown=True) test_suite = z3c.testsetup.register_all_tests('todo') After the imports, the first line gets the path for the ftesting.zcml file, which then is passed to the layer definition method ZCMLLayer. The final line in the module tells the test runner to find and register all of the tests in the package. This will be enough for our testing needs in this article, but if we needed to create another non-Grok package for our application, we would need to add a line like the last one to it, so that all of its tests are found by the test runner. This is pretty much boilerplate code, as only the package name has to be changed.
Read more
  • 0
  • 0
  • 2386
Modal Close icon
Modal Close icon