Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
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

7018 Articles
article-image-django-12-e-commerce-generating-pdf-reports-python-using-reportlab
Packt
19 May 2010
6 min read
Save for later

Django 1.2 E-commerce: Generating PDF Reports from Python using ReportLab

Packt
19 May 2010
6 min read
(Read more interesting articles on Django 1.2 e-commerce here.) ReportLab is an open source project available at http://www.reportlab.org. It is a very mature tool and includes binaries for several platforms as well as source code. It also contains extension code written in C, so it's relatively fast. It is possible for ReportLab to insert PNG and GIF image files into PDF output, but in order to do so we must have the Python Imaging Library (PIL) installed. We will not require this functionality in this article, but if you need it for a future project, see the PIL documentation for setup instructions. The starting point in the ReportLab API is drawing to canvas objects. Canvas objects are exactly what they sound like: blank slates that are accessible using various drawing commands that paint graphics, images, and words. This is sometimes referred to as a low-level drawing interface because generating output is often tedious. If we were creating anything beyond basic reporting output, we would likely want to build our own framework or set of routines on top of these low-level drawing functions. Drawing to a canvas object is a lot like working with the old LOGO programming language. It has a cursor that we can move around and draw points from one position to another. Mostly, these drawing functions work with two-dimensional (x, y) coordinates to specify starting and ending positions. This two-dimensional coordinate system in ReportLab is different from the typical system used in many graphics applications. It is the standard Cartesian plane, whose origin (x and y coordinates both equal to 0) begins in the lower-left hand corner instead of the typical upper-right hand corner. This coordinate system is used in most mathematics courses, but computer graphics tools, including HTML and CSS layouts, typically use a different coordinate system, where the origin is in the upper-left. ReportLab's low-level interface also includes functions to render text to a canvas. This includes support for different fonts and colors. The text routines we will see, however, may surprise you with their relative crudeness. For example, word-wrapping and other typesetting operations are not automatically implemented. ReportLab includes a more advanced set of routines called PLATYPUS, which can handle page layout and typography. Most low-level drawing tools do not include this functionality by default (hence the name "low-level"). This low-level drawing interface is called pdfgen and is located in the reportlab.pdfgen module. The ReportLab User's Guide includes extensive information about its use and a separate API reference is also available. The ReportLab canvas object is designed to work directly on files. We can create a new canvas from an existing open file object or by simply passing in a file name. The canvas constructor takes as its first argument the filename or an open file object. For example: from reportlab.pdfgen import canvasc = canvas.Canvas("myreport.pdf") Once we obtained a canvas object, we can access the drawing routines as methods on the instance. To draw some text, we can call the drawString method: c.drawString(250, 250, "Ecommerce in Django") This command moves the cursor to coordinates (250, 250) and draws the string "Ecommerce in Django". In addition to drawing strings, the canvas object includes methods to create rectangles, lines, circles, and other shapes. Because PDF was originally designed for printed output, consideration needs to be made for page size. Page size refers to the size of the PDF document if it were to be output to paper. By default, ReportLab uses the A4 standard, but it supports most popular page sizes, including letter, the typical size used in the US. Various page sizes are defined in reportlab.lib.pagesizes. To change this setting for our canvas object, we pass in the pagesize keyword argument to the canvas constructor. from reportlab.lib.pagesizes import letterc = canvas.Canvas('myreport.pdf', pagesize=letter) Because the units passed to our drawing functions, like rect, will vary according to what page size we're using, we can use ReportLab's units module to precisely control the output of our drawing methods. Units are stored in reportlab.lib.units. We can use the inch unit to draw shapes of a specific size: from reportlab.lib.units import inchc.rect(1*inch, 1*inch, 0.5*inch, 1*inch) The above code fragment draws a rectangle, starting one inch from the bottom and one inch from the left of the page, with sides that are length 0.5 inches and one inch, as shown in the following screenshot: Not particularly impressive is it? As you can see, using the low-level library routines require a lot of work to generate very little results. Using these routines directly is tedious. They are certainly useful and required for some tasks. They can also act as building blocks for your own, more sophisticated routines. Building our own library of routines would still be a lot of work. Fortunately ReportLab includes a built-in high-level interface for creating sophisticated report documents quickly. These routines are called PLATYPUS; we mentioned them earlier when talking about typesetting text, but they can do much more. PLATYPUS is an acronym for "Page Layout and Typography Using Scripts". The PLATYPUS code is located in the reportlab.platypus module. It allows us to create some very sophisticated documents suitable for reporting systems in an e-commerce application. Using PLATYPUS means we don't have to worry about things such as page margins, font sizes, and word-wrapping. The bulk of this heavy lifting is taken care of by the high-level routines. We can, if we wish, access the low-level canvas routines. Instead we can build a document from a template object, defining and adding the elements (such as paragraphs, tables, spacers, and images) to the document container. The following example generates a PDF report listing all the products in our Product inventory: from reportlab.platypus.doctemplate import SimpleDocTemplatefrom reportlab.platypus import Paragraph, Spacerfrom reportlab.lib import sytlesdoc = SimpleDocTemplate("products.pdf")Catalog = []header = Paragraph("Product Inventory", styles['Heading1']) Catalog.append(header)style = styles['Normal']for product in Product.objects.all(): for product in Product.objects.all(): p = Paragraph("%s" % product.name, style) Catalog.append(p) s = Spacer(1, 0.25*inch) Catalog.append(s)doc.build(Catalog) The previous code generates a PDF file called products.pdf that contains a header and a list of our product inventory. The output is displayed in the accompanying screenshot.
Read more
  • 0
  • 0
  • 26836

article-image-different-types-mapping-nhibernate-2
Packt
19 May 2010
8 min read
Save for later

Different types of Mapping in Nhibernate 2

Packt
19 May 2010
8 min read
(Read more interesting articles on Nhibernate 2 Beginner's Guide here.) What is mapping? Simply put, we need to tell NHibernate about the database that we created and how the fields and tables match up to the properties and classes we created. We need to tell NHibernate how we will be assigning Primary Keys, the data types that we will be using to represent data, what variables we will store them in, and so on. You could say this is one of the most important exercises we will perform in our pursuit of NHibernate. Don't worry though, it's pretty easy. Types of mapping There are two basic ways to map data for NHibernate: the traditional XML mapping in an hbm.xml file, or the newer "Fluent NHibernate" style, which is similar to the interface pattern introduced with the .NET 3.5 framework (see http://www.martinfowler.com/bliki/FluentInterface.html). In both cases, we will create a document for each of our tables. We will map each field from our database to the property we created to display it in our class. XML mapping XML mapping is undoubtedly the most common method of mapping entities with NHibernate. Basically, we create an XML document that contains all of the information about our classes and how it maps to our database tables. These documents have several advantages: They are text files, so they are small They are very readable They use a very small number of tags to describe the data The two biggest complaints about XML mapping is the verbosity of the text and that it is not compiled. We can handle some of the verbosity by limiting the amount of data we put into the document. There are a number of optional parameters that do not absolutely need to be mapped, but that provide additional information about the database that can be included. We'll discuss more about that in the Properties section. You should copy the nhibernate-mapping.xsd and nhibernate-configuration.xsd files from the NHibernate ZIP file into your Visual Studio schemas directory (that is C:Program FilesMicrosoft Visual Studio 9.0Common7Packagesschemasxml). This will give you IntelliSense and validation in the .NET XML editor when editing NHibernate mapping and configuration files. Without compilation, when the database changes or the classes change, it's difficult to detect mismatches until the application is actually executed and NHibernate tries to reconcile the database structure with the mapping classes. While this can be an issue there are a number of ways to mitigate it, such as careful monitoring of changes, writing tests for our persistence layer, using a Visual Studio plugin, or using a code generation tool. Getting started The XML mapping document begins like any XML document, with an XML declaration. No magic here, just a simple xml tag, and two attributes, version and encoding. <?xml version="1.0" encoding="utf-8" ?> The next tag we are going to see in our document is the hibernate-mapping tag. This tag has an attribute named ><hibernate-mapping namespace="BasicWebApplication.Common.DataObjects" assembly="BasicWebApplication"> </hibernate-mapping> These three properties within the hibernate-mapping tag make up the basic XML mapping document. Classes The next tag we need to define in our document is the class tag. This is a KEY tag, because it tells NHibernate two things—the class this mapping document is meant to represent and which table in the database that class should map to. The class tag has two attributes we need to be concerned with—name and table <class name="" table=""> </class> The name attribute contains the fully-qualified POCO (or VB.NET) class that we want to map to, including the assembly name. While this can be specified in the standard fully-qualified dotted class name, a comma, and then the assembly name, the preferred method is to define the namespace and assembly in the <hibernate-mapping> tag, as shown in the previous code. The table attribute specifies the table in the database that this mapping file represents. It can be as simple as the name of the table Address or as complex as needed to adequately describe the table. If you need to include the owner of the table, such as dbo.Address, then you can add the schema attribute as follows: schema="dbo" If we were going to map the Address class in our application to the Address table in the database, then we would use a tag as follows: <class name="Address" table="Address"> </class> Technically, as the table name is the same as our class name, we could leave out the table attribute. Properties We can map properties from our class to fields in the database using the id tag and the property tag. These tags are for the standard fields in the database, not the Foreign Key fields. We'll get to those in a minute. The id and property tags follow a standard pattern and have a number of optional parameters. They follow the basic format of defining the property on the class that they are mapping to and the data type that is used to represent that data. This will generally look as follows: <property name="Address1" type="String"> <column name="Address1" length="255" sql-type="varchar" not-null="true"/> </property> This is the fully-verbose method of mapping the properties, and the one I personally use. If something happens to your database, you can re-generate the database from this information. It's also very helpful when you are troubleshooting because all of the information about the data is right there. Alternately, you can map the property as follows: <property name="Address1" /> Both methods will provide the same mapping to NHibernate, but as I stated earlier, the more verbose method gives you a lot more flexibility. One of the optional attributes that I generally use on the id and property tags is the type attribute. With this attribute I can tell NHibernate that I am using a particular type of data to store that information in my class. Adding this data type, our property tag would look as follows: <property name="Address1" type="String" /> I also like to use the column tag, just to explicitly link the field with the property in the class, but that again is just preference. The previous code is completely adequate. ID columns The first property from our class that we want to map is the Id property. This tag has a number of attributes we can optionally set, but the simplest way we can map the Id property is as follows: <id name="Id"> <generator class="hilo"/> </id> This tells NHibernate that we have a property in our class named Id which maps to a field in the database called Id and also that we use the hilo method to automatically generate a value for this field. Simple enough! An optional attribute that I generally use on the id tag is the unsaved-value attribute. This attribute specifies what value should be returned in a new object before it is persisted (saved) to the database. Adding this attribute, as well as the type attribute we talked about, the code would look as follows: <id name="Id" type="Int32" unsaved-value="null"> <generator class="hilo"/> </id> As long as our field is named Id in the database, we are good to go. But what if it was named id or address_id? This simply wouldn't handle it. In that case, we would have to add the optional column tag to identify it: <id name="Id"> <column name="address_id"/> <generator class="hilo"/> </id> Now we have mapped our address_id field from the database into a more standard Id property on our class. Some of the additional attributes that are commonly used on the column tag are as follows: name: Define the name of the column in the database length: The length of the field, as defined in the database sql-type: The database definition of the column type not-null: Whether or not the database column allows nulls. not-null="true" specifies a required field Again, these optional attributes simply allow you to further define how your database is created. Some people don't even define the database. They just define the hbm.xml files and use the NHibernate.Tool.hbm2ddl to create a SQL script to do this work!
Read more
  • 0
  • 0
  • 5109

article-image-using-flowplayer-plone-3
Packt
19 May 2010
5 min read
Save for later

Using Flowplayer in Plone 3

Packt
19 May 2010
5 min read
This article is the third and the final section of this article series. The following articles are the initial parts of the series. Managing Audio Content in Plone 3.3 Audio Enhancements with p4a.ploneaudio in Plone 3.3 (For more resources on Plone, see here.) Including audio into HTML Generally, we have two options to include a sound file on a HTML page: Streaming Non streaming Another option is to simply include a link to the file like this: <a href="example.mp3" type="audio/x-mpeg" title="MP3 audiofile , ... kB">example.mp3 </a> This is the standard way Plone includes files into the visual editor. The advantage of this approach is that virtually everyone is able to access the file in some way. What happens with the file after it has been downloaded depends on the client browser and how it is configured. The shortcoming of this method is that we depend on an external player to listen to the audio. Probably one needs to download the file and start the player manually. Including audio with plugin elements Another option to spread an audio file is to use the embed element or the object element. The former looks like this: <embed src="example.mp3"> The embed element was introduced by Netscape in browser version 2.0. However, it has not yet made it into the HTML standard, and probably will never do so. An alternative element to the Netscape variant is the object element that was introduced by Microsoft. Including an example.mp3 file located in the data folder looks like this: <object type="audio/x-mpeg" data="data/example.mp3" width="200" height="20"> <param name="src" value="data/example.mp3"> <param name="autoplay" value="false"> <param name="autoStart" value="0"> alt : <a href="data/example.mp3">example.mp3</a> </object> Including audio with the embed or the object element assumes that there is a plugin installed on the client side that can play the multimedia format. In most cases, we can't tell what the client is equipped with and want a more robust solution. The third way to include audio into your site is Flash. We still need a plugin on the client side, but Flash is more widespread than audio player plugins. There are a couple of free audio players written in Flash. An older but easy-to-use Flash player is EMFF. A custom view with an embedded audio player What we do now is to write a custom view for the audio-enhanced File content type of Plone. We reuse the mm.enhance product we created in the previous article and add the additional code there. We utilize the p4a.audio.interfaces.IAudioEnhanced interface to register our view on. Let's do so: <browser:page for="p4a.audio.interfaces.IAudioEnhanced" name="my-audioplayer-view" class=".browser.AudioPlayerView" permission="zope2.View" template="player.pt" /> <browser:resourceDirectory directory="thirdparty/emff" name="emff" /> The page is named my-audioplayer-view and has the AudioPlayerView view class in the browser module. Further, we register a thirdparty/emff directory where we can put the Flash resources of the Flash player. Next, we need to create this view class and add the player.pt template. We fill the template with the HTML code we get from the EMFF code generator: Using the EMFF code generator Choose the first option URL to MP3, though it doesn't really matter what you write into the text field. The value is overridden with the name we retrieve from our context object. For the HTML version, you can either choose HTML or XHTML as Plone 3 doesn't output valid XHTML itself. Nevertheless, XHTML might still be the better option, as it is future proof. Selecting XHTML closes the param elements inside of the object element. We can copy this literally into our Zope page template. <object type="application/x-shockwave-flash" data="emff_lila_info.swf" width="200" height="55"> <param name="movie" value="emff_lila_info.swf" /> <param name="bgcolor" value="#00ff00" /> <param name="FlashVars" value="src=example.mp3&amp;autostart=yes" /> </object> The Plone template is a standard one using the main_template. We copy the generated code from the bottom of the codegenerator window and put into the main slot of the template. There are just two changes we make. One is the location of the Flash file, which is registered as a resource, and the other is the audio file itself, which is our context. <html xml_lang="en" lang="en" i18n:domain="p4a.audio" metal:use-macro="context/main_template/macros/master"> <body> <div metal:fill-slot="main"> <object type="application/x-shockwave-flash" data=" ++resource++emff/emff_lila_info.swf" width="200" height="55"> <param name="movie" value="emff_lila_info.swf" /> <param name="bgcolor" value="#ffffff" /> <param name="FlashVars" value="src=example.mp3&amp;autostart=yes" tal:attributes="value string_src=${context/getId}&amp; autostart=yes" /> </object> </div> </body> </html> Next, we download the necessary Flash code from its website. The player is provided as a ZIP package with all sources and stuff included. We need to copy the chosen skin file to the thirdparty/emff directory of our mm.enhance product. In our example we used the emff_lila_info skin.
Read more
  • 0
  • 0
  • 1818

article-image-liferay-portal6-build-wap-sites-and-integrate-crm-and-netvibes-widgets
Packt
18 May 2010
8 min read
Save for later

Liferay Portal6: Build WAP sites and Integrate with CRM and Netvibes widgets

Packt
18 May 2010
8 min read
(Read more interesting articles on Liferay Portal 6 here.) WAP Liferay goes mobile! As smart-phones continue to impede the space between dialing a number, taking a picture, or discovering new music, mobile browsers offer us the next frontier in the previously desktop-exclusive market of web design. A mobile browser is a web browser designed for use on a mobile device such as a mobile phone, PDA, iPhone, which is optimized to display web content most effectively for small screens on portable devices. A WAP browser provides all of the basic services of a web browser, but is simplified to operate within the restrictions of a mobile phone, such as its smaller view screen. The websites generated by the portal go with mobile browsers, or any WAP browsers. Thus you can browse portal websites, called WAP sites, through mobile devices. Themes (look and feel of websites or WAP sites) in the portal will detect mobile devices dynamically. As mentioned earlier, each site may have its own look and feel and each page could have its own look and feel. Under the tab Look and Feel, you would see Regular Browsers and Mobile Devices, where available themes will appear. Of course, you can develop your mobile themes or WAP themes depending on your own requirements. Here we're going to discuss several existing mobile themes or WAP themes, and going further, see what themes are and how they work. Jedi Mobile theme The theme Jedi Mobile has been applied on the home page of the community Guest. As you can see, the theme Jedi Mobile takes the original Jedi theme and packs it int a bite-sized, smart-phone punch. Structure The theme Jedi Mobile has the following folder structure at $AS_WEB_APP_HOME/jedi-mobile-theme. CSS: CSS files images: Image files javascripts: JavaScript files templates: Velocity template files WEB-INF: Web info specification includes sub-folders classes, lib, and tld As you can see, web-info specification covers liferay-look-and-feel.xml,liferay-plugin-package.properties, liferay-plugin-package.xml, and web.xml. Knowing the structure of the theme would be helpful to customize that theme. How does it work? You could bring the theme Jedi Mobile Theme into the portal by following these steps: Download the WAR file ${jedi.mobile.theme.war} from http://liferay.cignex.com/palm_tree/book/0387/chapter12/jedi-mobiletheme-6.0.0.1.war Drop the WAR file ${jedi.mobile.theme.war} to the folder $LIFERAY_HOME/deploys when the portal is running Then apply the theme as the current look and feel of pages. What's happening? The theme Jedi Mobile has specified the following script at $AS_WEB_APP_HOME/jedi-mobile-theme/templates/portal_normal.vm. <script type="text/javascript">iPhone = function() {setTimeout("window.scrollTo(0,1) ", 100)}if (navigator.userAgent.indexOf('iPhone') != -1) {addEventListener("load", iPhone, false)addEventListener("onorientationchange", iPhone, false)}</script> As shown in the preceding code, it detects the navigator, whether it is an iPhone or not. iPhone theme The theme iPhone takes a much more direct approach to web applications. With its indigenous appearance and feel, the WAP site starts to feel like a playlist, user experience appears native, and navigation comes naturally. How does it work? You can bring the iPhone Theme into the portal by following these steps: Download the WAR file ${iphone.theme.war} from http://liferay.cignex.com/palm_tree/book/0387/chapter12/iphone-theme-6.0.0.1.war Drop the WAR file ${iphone.theme.war} to the folder $LIFERAY_HOME/deploy swhen the portal is running. Then apply the theme as the current look and feel of pages. What's happening? The theme iPhone introduces a new browser detection mechanism for specialized mobile functionality. If you visit the site on an iPhone, you get the bare minimum—JavaScript, HTML, and CSS. If you visit the site on a regular browser, you get all the more advanced UI features. The theme iPhone has specified the following script at $AS_WEB_APP_HOME/iphonetheme/templates/portal_normal.vm. #set ($isIphone = $request.getHeader("User-Agent").toLowerCase().indexOf("iphone") != -1)<!-- ignore details -->#if ($isIphone)<!-- ignore details -->#else$theme.include($top_head_include)#end</head><!-- ignore details --> iPhone Redirect theme The theme iPhone Redirect takes the browser detection mechanism and takes intelligent redirection. The theme iPhone Redirect is an unstyled theme, coming with a custom initialization feature—that is, it can detect an iPhone browser visiting the page, check for a Mobile community, and automatically redirect the iPhone user to that community if found. Moreover, it will work with a virtual host. How does it work? You could bring the theme iPhone Redirect Theme into the portal by following these steps: Download the WAR file ${iphone.redirect.theme.war} fromhttp://liferay.cignex.com/palm_tree/book/0387/chapter12/so-theme-6.0.0.1.war Drop the WAR file ${iphone. redirect.theme.war} to the folder$LIFERAY_HOME/deploy when the portal is running.   Then apply the theme as the current look and feel of pages. What's happening? The theme iPhone Redirect has the following code specified at $AS_WEB_APP_HOME/iphone-detect-theme/templates/init_custom.vm. //ignore details#set ($isIphone = $request.getHeader("User-Agent").toLowerCase().indexOf("iphone") != -1)#if ($isIphone && $mobileGroup && $group_id != $mobileGroup.groupId)<script type="text/javascript">window.location.href = '${layoutSet.virtualHost}' ? 'http://' +'${layoutSet.virtualHost}' + ((window.location.port) ? ':' + window.location.port : '') : '/web${mobileGroup.friendlyURL}'</script>#end Of course, you could customize the preceding themes according to your own requirements. Reporting JasperReports is an open source Java reporting tool that can write to screen, a printer, or to PDF, HTML, Microsoft Excel, RTF, ODT, CSV (Comma Separated Value) formats, and XML files. It can be used in Java-enabled applications, including Java EE or Web applications to generate dynamic content. It reads its instructions from an XML or .jasper file. Refer to http://www.jasperforge.org/jasperreports for more information. The portal provides full integration of JasperReports with the reporting framework—a web called reporting-jasper-web and a portlet called reports-console-portlet. The portal provides the ability to schedule reports and deliver them via Document Library and e-mail. In addition, the portal has added support for Jasper XLS data source to a reporting framework. JasperReports Engine The Liferay JasperReports Report Engine provides implementation of Liferay BI using Jasper. You can bring the web Reporting Jasper into the portal by following these steps: Download the WAR file ${reporting.jasper.web.war} from http://liferay.cignex.com/palm_tree/book/0387/chapter12/reporting-jasper-web-6.0.0.1.war Drop the WAR file ${reporting.jasper.web.war} to the folder $LIFERAY_HOME/deploy when the portal is running. Note that the current integration of JasperReports version is 3.6.2. You will be able to upgrade it to the latest version of JasperReports anytime. The Reports portlets The plugin Reports Console defines two portlets: Reports Console at Control Panel and Reports Display. The portlet Reports Display is instanceable—that is, you can add more than one instance of the portlet on a page. You could bring the plugin Reports Console into the portal by following these steps: Download the WAR file ${reports.console.portlet.war} from http://liferay.cignex.com/palm_tree/book/0387/chapter12/reports-console-portlet-6.0.0.1.warr Drop the WAR file ${reports.console.portlet.war} to the folder$LIFERAY_HOME/deploy when the portal is running. As shown in the following screenshot, the portlet Reports Display provides the ability to search for reports and display search results with pagination. Search results will be displayed with a set of columns: Report Definition Name, Report Format, Requested Date, and Reporting Date. As you can see, you can search for reports via basic search or advanced search. The advanced search would cover the following items: Match All of the following fields: All or Any Definition Name: User's input Datasource Name: Jasper Empty, Portal Format: csv, excel, HTML, pdf, rtf, Text, and XML Requesting User Name:User's input Start date:A date End date:A date Active: Yes or No The portlet Reports Console provides the abilities to manage reports in the Control Panel. By going to Content | Reports Console under the Control Panel, you can search for generated reports under the tab Generated Reports. You can also create report definitions under the tab Report Definitions. Under the tab Report Definition, you would be able to search report definitions via basic search or advanced search. The advanced search would cover the following items: Match All of the following fields: All or Any Definition Name: User's input Description: User's input Datasource Name: Multiple checkboxes, Jasper Empty or Portal Of course, you could add definitions with the following items: Definition Name: Input required Description: User's input Datasource Name: Empty or Portal Template: Uploading template file (required) Report Parameters: Multiple pair (key, value) Key: User's input; optionally, it is bound to Report parameters Value: User's input Permissions: A checkbox—Public permissions configuration.
Read more
  • 0
  • 0
  • 4225

article-image-managing-audio-content-plone-33
Packt
17 May 2010
10 min read
Save for later

Managing Audio Content in Plone 3.3

Packt
17 May 2010
10 min read
(For more resources on Plone, see here.) There are at least four use cases when we think of integrating audio in a web application: We want to provide an audio database with static files for download. We have audio that we want to have streamed to the Internet (for example, as a podcast). We want a audio file/live show streamed to the Internet as an Internet radio service. We want some sound to be played when the site is loaded or shown. In this article series, we will discuss three of the four cases. The streaming support is limited to use case 2. We can stream to one client like a podcast does, but not to many clients at once like an Internet Radio does. We need special software such as Icecast or SHOUTcast for this purpose. Further, we will investigate how we solve use cases 1, 2, and 3 with the Plone CMS and extensions. Technically, these are the topics covered in this article series: Manipulation of audio content stored as File content in Plone The different formats used for the binary storage of audio data Storing and accessing MP3 audio metadata with the ID3 tag format Managing metadata, formats, and playlists with p4a.ploneaudio in Plone Including a custom embedded audio player in Plone Using the Flowplayer product to include an audio player standalone in rich text and as a portlet Previewing the audio element of HTML5 Extracting metadata from a FLAC file using mutagen   Uploading audio files with an unmodified Plone installation The out of the box support of Plone for audio content is limited. What is possible to do is to upload an audio file utilizing the File content type of Plone to the ZODB. A File is nothing more and nothing less than a simple binary file. Plone does not make any difference between a MP3 file and a ZIP, an EXE, or an RPM binary file. When adding File content to Plone, we need to upload a file (of course!). We don't necessarily need to specify a title, as the filename is used if the title is omitted. The filename is always taken for the short name (ID) of the object. This limits the number of files with any specific name to one in a container While uploading a file, Plone tries to recognize the MIME type and the size of the file. This is the smallest subset of information shared by all binary files the content type File was intended for. Normally, detecting the MIME type for standard audio is not a problem if the file extension is correctly set. Clicking on the link in the default view either downloads the file or opens it with the favorite player of your operating system. This behavior depends on the settings made on the target browser and corresponds with the method 1 of our audio use cases. It goes without saying that we can add the default metadata to files and organize them in folders. Like Images, File objects do not have a workflow associated in a default Plone setup. They inherit the read and write permissions from the container they are placed into. Still, we can add an existing workflow to this content type or create a new one via the portal_workflow tool if we want. That's pretty much it. Fortunately, we can utilize some extensions to enhance the Plone audio story greatly. What we will see in this article is as follows: First, we will go over some theoretical ground. We will see what formats are available for storing audio content and which is best for which purpose. Later we will investigate the Plone4Artists extension for Plone's File content type—p4a.ploneaudio. We will talk about metadata especially used for audio content and how to manipulate it. As a concrete example, we will use mutagen to extract metadata from a FLAC file to add FLAC support to p4a.ploneaudio. Finally, we will have a word on streaming audio data through the Web and see how to embed a Flash player into our Plone site. We will see how we can do this programmatically and also with the help of a third-party product called collective.flowplayer. At the very end of the article, we have a small technical preview on HTML5 where a dedicated audio element is available. This element allows us to embed audio directly into our HTML page without the detour with Flash. Accessing audio content in Plone Once we upload a file we want to work with to Plone, we will link it with other content and display it in one way or another. There are several ways of accessing audio data in Plone. It can be accessed in the visual editor by editors, in templates by integrators and in Python code by developers. Kupu access Unlike for images, there is no special option in the visual editor to embed file/audio content into a page. The only way to access an audio file with Kupu is to use an internal link. The file displays as a normal link and is executed when clicked. Executed means (as for the standalone file) saved or opened with the music player of your operating system as is done in the standard view of the File content type. Of course, it is possible to reference external audio files as well. Page template access As there is no special access method in Kupu, there is none in page templates. If we need to access a file there, we can use the absolute_url method of the audio content object. This computes a link we can refer to. So the only way to access a file from another context is to refer to its URL. <a tal_attributes="href audiocontext/absolute_url"tal:content="audiocontext/Title">audio</a> Python script access If we need to access the content of an (audio) file in a Python script, we can get the binary data with the Archetype accessor getFile. >>> binary = context.getFile() This method returns the data wrapped into a Zope OFS.File object. To access the raw data as a string, we need to do the following: >>> rawdata = str(binary.data) Accessing the raw data of an audio file might be useful if we want to do format transformations on the fly or other direct manipulation of the data. Field access If we write our own content type and want to save audio data with an object, we need a file field. This field stores the binary data and takes care of communicating with the browser with adequate view and edit widgets. The file field is defined in the Field module of the Archetype product. Additional to the properties, it exclusively defines that it inherits from the ObjectField base class. The following properties are important. Key Default value type 'file' default ' ' primary False widget FileWidget content_class File default_content_type 'application/octet-stream'   The type property provides a unique name for the field. We usually don't need to change this. The default property defines the default value for this field. It is normally empty. If we want to change it, we need to specify an instance of the content_class property. One field of the schema can be marked as primary. This field can be retrieved by the getPrimaryField accessor. When accessing the content object with FTP, the content of the primary field is transmitted to the client. Like every other field, the file field needs a widget. The standard FileWidget is defined in the Widget module of the Archetypes product. The content_class property declares the instance, where the actual binary data is stored. As standard, the File class from Zope's OFS.Image module is used. This class supports chunk-wise transmission of the data with the publisher. Field can be accessed like any other field by its accessor method. This method is either defined as a property of the field or constructed from its name. If the name were "audio", the accessor would be getAudio. The accessor is generated from the "get" prefix with the capitalized name of the field. Audio formats Before we go on with Plone and see how we can enhance the story of audio processing and manipulate audio data, we will glance at audio formats. We will see how raw audio data is compressed to enable effective audio storage and streaming. We need to have some basic audio know-how about some of the terminology to understand how we can effectively process audio for our own purposes. As with images, there are several formats in which audio content can be stored. We want to learn a bit of theoretical background. This eases the decision of choosing the right format for our use case. An analog acoustic signal can be displayed as a wave: If digitalized, the wave gets approximated by small rectangles below the curve. The more rectangles are used the better is the sound (fidelity) of the digital variant. The width of the rectangles is called the sampling rate. Usual sampling rates include: 44.1 kHz (44,100 samples per second): CD quality 32 kHz: Speech 14.5 kHz: FM radio bandwidth 10 kHz: AM radio Each sample is stored with a fixed number of bits. This value is called the audio bit depth or bit resolution. Finally, there is a third value that we already know from the analog side. It is the channel. We have one channel for mono and two channels for stereo. For the digital variant, this means a doubling of data if stereo is used. So let's do a calculation. Let's assume we have an audio podcast with a length of eight minutes, which we want to stream in stereo CD quality. The sampling rate corresponds with the highest frequency of sound that is stored. For accurate reproduction of the original sound, the sample rate has to be at least twice that ofthe highest frequency sound. Most humans cannot hear frequencies higher than 20 kHz. The corresponding sampling rate to 20 kHz is a sampling rate of 44100 samples. We want to use a bit resolution of 16. This is the standard bit depth for audio CDs. Lastly, we have two channels for stereo: 44100 x 16 x 2 x 60 x 8= 677376000 bits = 84672000 bytes ˜ 80.7 MB This is quite a lot of data for eight minutes of CD-quality sound. We do not want to store so much data and more importantly, we do not want to send so much data over the Internet. So what we do is compress the data. Zipping the data would not give us a big effect because of the binary structure of digital audio data. There are different types of compressions for different types of data. ZIPs are good for text, JPEG is good for images, and MP3 is good for music—but why? Each of these algorithms takes the nature of the data into account. ZIP looks for redundant characters, JPEG unifies similar color areas, and MP3 strips the frequencies humans do not hear from the raw data.
Read more
  • 0
  • 0
  • 1701

article-image-liferay-portal-6pluggable-enterprise-search-and-plugin-management
Packt
17 May 2010
13 min read
Save for later

Liferay Portal 6:Pluggable Enterprise Search and Plugin Management

Packt
17 May 2010
13 min read
(Read more interesting articles on Liferay Portal 6 here.) Pluggable Enterprise Search As an alternative to using Lucene, the portal supports pluggable search engines. The first implementation of this uses the open source search engine Solr, but in the future, there will be many such plugins for search engine of your choice, such as FAST, GSA, Coveo, and so on. In this section, we're going to discuss caching, indexing, and using Solr for search Caching settings EHCache is a widely-used cache implemented in Java, which the portal uses to provide distributed caching in a clustered environment. EHCache is also used in a non-clustered environment to speed up repeated data retrievals. The portal uses EHCache caching by default. At the same time, the portal uses Hibernate caching as well. The portal provides the capability to confi gure EHCache caching and Hibernate caching. The portal has specified Hibernate as default ORM (Object-Relational Mapping) persistence in portal.properties. persistence.provider=hibernate The preceding code sets the provider hibernate used for ORM persistence. Of course, you can set this property to jpa (Java Persistence API), thus the properties with the prefi x jpa.* will be read. Similarly, if this property is set to hibernate, then the properties with the prefix hibernate.* will be read. Note that this property affects the loading of hibernate-spring.xml or jpa-spring.xml in the property spring.configs. For example, the portal has the following JPA configuration specified in portal.properties: jpa.configs=META-INF/mail-orm.xml,META-INF/portal-orm.xmljpa.provider=eclipselinkjpa.provider.property.eclipselink.allow-zero-id=truejpa.load.time.weaver=org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver As shown in the preceding code, the property jpa.configs sets a list of commadelimited JPA configurations. The default JPA provider is set as eclipselink via the property jpa.provider. You can set it to other values such as hibernate, openjpa, and toplink. The property jpa.provider.property.eclipselink. allow-zero-id specifies provider-specific properties prefixed with jpa.provider. property.*.On the other hand, LoadTimeWeaver interface specified via the property jpa.load.time.weaver is a Spring class that allows JPA ClassTransformer instances to be plugged in a specific manner depending on the environment. Note that not all JPA providers require a JVM agent. If your provider doesn't require an agent or you have other alternatives, the loadtime weaver shouldn't be used. Configure Hibernate caching First of all, let's consider Hibernate caching settings. The portal will automatically detect the Hibernate dialect. However, you can set the property in portal-ext.properties to manually override the automatically detected dialect. hibernate.dialect= The portal also specified the following properties related to Hibernate caching in portal.properties. hibernate.configs=//ignore detailsMETA-INF/ext-hbm.xmlhibernate.cache.provider_class=com.liferay.portal.dao.orm.hibernate.EhCacheProvidernet.sf.ehcache.configurationResourceName=/ehcache/hibernate.xmlhibernate.cache.use_query_cache=truehibernate.cache.use_second_level_cache=truehibernate.cache.use_minimal_puts=truehibernate.cache.use_structured_entries=falsehibernate.jdbc.batch_size=20hibernate.jdbc.use_scrollable_resultset=truehibernate.bytecode.use_reflection_optimizer=truehibernate.query.factory_class=org.hibernate.hql.classic.ClassicQueryTranslatorFactoryhibernate.generate_statistics=false As shown in the preceding code, the property hibernate.configs sets Hibernate configurations. You may input a list of comma-delimited Hibernate configurations in portal-ext.properties. The property hibernate.cache.provider_class sets the Hibernate cache provider. On the other hand, the property net.sf.ehcache.configurationResourceName is used if Hibernate is confi gured to use Ehcache's cache provider, where Ehcache is recommended in a clustered environment. In a clustered environment, you need to set the property in portal-ext.properties as follows: net.sf.ehcache.configurationResourceName=/ehcache/hibernate-clustered.xml The portal has specified other Hibernate cache settings with properties starting with hibernate.cache.use_*. The property hibernate.jdbc.batch_size sets the JDBC batch size to improve performance. Note that if you're using Hypersonic databases or Oracle 9i, you should set the batch size to 0 as a workaround for a logging bug in the Hypersonic database driver or Oracle 9i driver. In addition, the property hibernate.query.factory_class sets the classic query factory, whereas the portal sets the property hibernate.generate_statistics to false. Of course, you could set the property hibernate.generate_statistics to true to enable Hibernate cache monitoring in portal-ext.properties. Setting up EHCache caching The portal has specified the following EHCache caching settings in portal.properties ehcache.single.vm.config.location=/ehcache/liferay-single-vm.xmlehcache.multi.vm.config.location=/ehcache/liferay-multi-vm.xmlehcache.portal.cache.manager.jmx.enabled=trueehcache.blocking.cache.allowed=true As shown in the preceding code, the property ehcache.single.vm.config.location sets the classpath to the location of the Ehcache configuration file / ehcache/liferay-single-vm.xml for internal caches of a single VM, whereas the property ehcache.multi.vm.config.location sets the classpath to the location of the Ehcache configuration file /ehcache/liferay-multi-vm.xml for internal caches of multiple VMs. In a clustered environment, you need to set the following in ehcache.multi.vm.config.location=/ehcache/liferay-multi-vm-clustered.xml In addition, the portal sets the property ehcache.portal.cache.manager.jmx.enabled to true to enable JMX integration in com.liferay.portal.cache.EhcachePortalCacheManager. Moreover, the portal sets the property ehcache.blocking.cache.allowed to, true to allow Ehcache to use blocking caches. This improves performance signifi cantly by locking on keys instead of the entire cache. The drawback is that threads can hang if the cache isn't used properly. Therefore, make sure that all queries that return a miss also immediately populate the cache, or else other threads that are blocked on a query of that same key will continue to hang. Of course, you can override the preceding properties in portal-ext.properties. Customization As you can see, the property net.sf.ehcache.configurationResourceName can have the value /ehcache/hibernate.xml for a non-clustered environment and /ehcache/hibernate-clustered.xml for a clustered environment. The propertynet.sf.ehcache.configurationResourceName can have the value /ehcache/hibernate.xml for a non-clustered environment and /ehcache/hibernateclustered.xml for a clustered environment. In the same pattern, the property ehcache.single.vm.config.location can havethe value /ehcache/liferay-single-vm.xml and the property ehcache.multi.vm.config.location can have the value /ehcache/liferay-multi-vm.xml for a non-clustered environment. ehcache.multi.vm.config.location has a value /ehcache/liferay-multi-vmclustered.xml for a clustered environment. In real cases, you may need to update both Hibernate caching settings and Ehcache caching settings, either in a non-clustered environment or in a clustered environment. The following is an example of how to do this: Create a folder named ext-ehcache under the folder $PORTAL_ROOT_HOME/WEB-INF/classes/. Obviously, you can have different names for the folder ${ehcache.folder.name}. Here we use the folder ext-ehcache of ${ehcache.folder.name} as an example Locate the JAR file portal-impl.jarunder the folder $PORTAL_ROOT_HOME/WEB-INF/lib and unzip all the fi les under the folder ehcache into the folder $PORTAL_ROOT_HOME/WEB-INF/classes/ext-ehcache. Update following fi les according to your requirements for both a non-clustered environment and a clustered environment. hibernate.xmlhibernate-clustered.xmlliferay-single-vm.xmlliferay-multi-vm.xmlliferay-multi-vm-clustered.xml Set the following for a non-clustered environment in portal-ext.properties:net.sf.ehcache.configurationResourceName=/ext-ehcache/hibernate.xmlehcache.single.vm.config.location=/ext-ehcache/liferay-single-vm.xmlehcache.multi.vm.config.location=/ext-ehcache/liferay-multi-vm.xml Otherwise, set the following for a clustered environment in portal-ext.properties:net.sf.ehcache.configurationResourceName=/ext-ehcache/hibernateclustered.xmlehcache.multi.vm.config.location=/ext-ehcache/liferay-multi-vmclustered.xml That's it! You have customized both the both Hibernate caching settings and Ehcache caching settings   Indexing settings Search engine indexing collects, parses, and stores data to facilitate fast and accurate information retrieval. Apache Lucene is a high-performance, full-featured text search engine library written entirely in Java-based indexing. It is a technology suitable for nearly any application that requires full-text search, especially cross-platform. Refer to http://lucene.apache.org for more information. By default, the portal uses Lucene search and indexing. Lucene search The portal sets the default Lucene index on start-up to false for faster performance, as follows,in portal.properties: index.read.only=falseindex.on.startup=falseindex.on.startup.delay=60index.with.thread=true As you can see, the portal sets the property index.read.only to false to allow any writes to the index. You should set it to true if you want to avoid any writes to the index. This is useful in some clustering environments where there is a shared index, and only one node of the cluster updates it. The portal sets the property index.on.startup to false in order to avoid indexing on every startup. You could set this property to true if you want to index your entire library of files on startup. This property is available so that automated test environments index the files on startup. Don't set this to true on production systems, or else your index data will be indexed on every startup. The property index.on.startup.delay adds a delay before indexing on startup. A delay may be necessary if a lot of plugins need to be loaded and re-indexed. Note that this property is only valid if the property index.on.startup is set to true. In addition, the portal sets the property index.with.thread to true to allow indexing on startup to be executed on a separate thread to speed up execution. Of course, you could re-index either all resources or an individual resource through web UI. For example, for re-indexing all search indexing, you can go to Control Panel | Server | Server Administration | Resources | Actions, and click on the button Execute next to the "Reindex all search indexes" option. Suppose that you're going to re-index individual resource like Users, you can use the Plugin Installation portlet in the Control Panel. Go to Control Panel | Server | Plugin Installation | Portlet Plugins, and click on the button Reindex next to the portlet Users. Index storage Lucene stores could be in the filesystem, the database, or in RAM. Anyway, the portal provides a set of properties to configure index storage as follows in portal.properties. lucene.store.type=filelucene.store.jdbc.auto.clean.up=falselucene.store.jdbc.dialect.*lucene.dir=${liferay.home}/data/lucene/lucene.file.extractor=com.liferay.portal.search.lucene.LuceneFileExtractorlucene.file.extractor.regexp.strip=lucene.analyzer=org.apache.lucene.analysis.standard.StandardAnalyzerlucene.commit.batch.size=0lucene.commit.time.interval=0lucene.buffer.size=16lucene.merge.factor=10lucene.optimize.interval=100 As shown in the preceding code, the property lucene.store.type designates whether Lucene stores indexes in a database via JDBC, filesystem, or in RAM. The default setting is filesystem. When using Lucene's storage of indexes via JDBC, temporary files don't get removed properly. This can eat up disk space over time. Thus set the property lucene.store.jdbc.auto.clean.up to true to automatically clean up the temporary files once a day. The property lucene.store.jdbc.dialect.* sets the JDBC dialect so that Lucene can use it to store indexes in the database. This property is referenced only when Lucene stores indexes in the database. The portal will attempt to load the proper dialect based on the URL of the JDBC connection. The property lucene.dir sets the directory where Lucene indexes are stored. This is referenced only when Lucene stores indexes in the filesystem. In a clustered environment, you could point the property lucene.dir to a shared folder, which is accessible for all nodes. More interestingly, you could set one node to allow any writes to the indexes via the property index.read.only and set the rest of nodes to allow read only. The property lucene.file.extractor specifies a class, called by Lucene to extract text from complex fi les so that they can be properly indexed. The file extractor can sometimes return text that isn't valid for Lucene. The property lucene.file. extractor.regexp.strip expects a regular expression. Any character that doesn't match the regular expression will be replaced with a blank space. You can set an empty regular expression to disable this feature. The property lucene.analyzer sets the default analyzer used for indexing and retrieval. In addition, the property lucene.commit.batch.size sets how often index updates will be committed. Set the batch size to confi gure how many consecutive updates will trigger a commit. If the value is 0, then the index will be committed on every update. The property lucene.commit.time.interval sets the time interval in milliseconds to confi gure how often to commit the index. The time interval isn't read unless the batch size is greater than 0 because the time interval works in conjunction with the batch size to guarantee that the index is committed after a specifi ed time interval. The portal sets the time interval to 0 to disable committing the index by a time interval. The property lucene.buffer.size sets Lucene's buffer size in megabytes and the property lucene.merge.factor sets Lucene's merge factor. For both of these properties, higher numbers mean that indexing goes faster but uses more memory. The default value from Lucene is 10. Note that this should never be set to a number less than 2. The property lucene.optimize.interval sets how often to run Lucene's optimize method. Optimization speeds up searching but slows down writing. You can set this property to 0 to always optimize. Indexer framework As mentioned earlier, you could re-index either all resources or an individual resource through web UI. For example, you could re-index out-of-the-box portlets like Users (Portlet ID 125) and plugins like the Mail portlet. This is because, in $PORTAL_ROOT_HOME/WEB-INF/liferay-portlet.xml, the portlet Users (named as enterprise_admin_users) has specified the following line: <indexer-class>com.liferay.portlet.enterpriseadmin.util.UserIndexer</indexer-class> As shown in the preceding code, the indexer-class value, which is the specified indexer framework, must be a class that implements com.liferay.portal.kernel.search.Indexer and is called to create or update a search index for the portlet Users. Additionally, you could fi nd the indexer framework in out-of-the-box portlets such as Organizations (portlet ID 126, called enterprise_admin_organizations), Web Content (portlet ID 15), Image Gallery (Portlet ID 31), Document Library (Portlet ID 20), and so on. Similarly the indexer-class value, which is the specified indexer framework, is also available in plugins. For example, the portlet Mail has specifi ed the following line in $AS_WEB_APP_HOME/mail-portlet/WEB-INF/liferay-portlet.xml. <indexer-class>com.liferay.mail.search.Indexer</indexer-class> In the same pattern, you may add the indexer framework in other plugins, like the Knowledge base portlet KBIndexer, which supports keyword search against titles, descriptions, content, tags, categories and category hierarchy, and "San Francisco" as oneword, and 'San Francisco' as multiple words ("San" or "Francisco") at http://liferay.cignex.com/palm_tree/book/0387/chapter11/knowledge-base-portlet-6.0.0.1.war
Read more
  • 0
  • 0
  • 1621
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-liferay-portal-6-employ-federated-search-opensearch-csz-search-maps-search-and-web-con
Packt
17 May 2010
12 min read
Save for later

Liferay Portal 6: Employ federated search, OpenSearch, CSZ search, maps search and web Content search

Packt
17 May 2010
12 min read
(Read more interesting articles on Liferay Portal 6 here.) Federated search Federated search is the simultaneous searching of multiple online databases or web resources, and it is an emerging feature of automated, web-based library, and information retrieval systems. Here, federated search refers to the portal. It is very useful to provide federated search abilities, such as searches for blog entries, users, organizations, Calendar entries, Bookmarks entries, Document Library documents, Image Gallery images, Message Boards messages, Wiki articles, Web Content articles, Directory, and so on. The portal provides a set of search portlets. In this section, we're going to take an in-depth look at these portlets. The Search portlet The Search portlet (portlet ID 3) is a JSR-286-compliant portlet that can be used for federated search. By default, the portal itself is the search provider. As shown in following screenshot, Search Portlet provides a federated search against Blogs entries, users, organizations, Calendar entries, Bookmarks entries, Document Library documents, Image Gallery images, Message Boards message, Wiki articles, Web Content articles, Directory, and so on. In addition, the Search Portlet provides a federated search against plugin portlets like the Alfresco Content portlet. The following is an example of how to use the Search portlet: Add the Search portlet to the page Home of the community Guest where you want to carry out a search, if the Search portlet isn't already present Enter the search criterion, for example My Click on the Search icon Note that when searching for assets, you will have the ability to specify the scope of the search results: Everything or This Community. Everything would generate search results that will come from any group in the current portal instance such as communities, organizations, and my community. This Community will generate search results that come from the current group in the portal instance such as community Guest, organization "Palm Tree Enterprise", and My Community. The search results would cover Blogs entries, users, organizations, Calendar entries, Bookmarks entries, Document Library documents, Image Gallery images, Message Boards messages, Wiki articles, Web Content articles, Directory, and so on. Additionally, search results will include assets from plugin portlets like Alfresco Content portlet. As you can see, search results would be displayed as a title with a link. If you have the proper permission on an asset, you could click on the title of the asset (which is a link to it) and view the asset as well. But if you don't have proper permission on an asset, clicking on the title would bring up a the permission error message. What's happening? The portal provides many portlets to support OpenSearch framework such as Message Boards, Blogs, Wikis, Directory and Document Library, Users, Organizations, and so on. In addition, plugins like the Alfresco Content portlet also supports the OpenSearch framework. Normally, these portlets have the following OpenSearch framework configuration. <open-search-class>class-name </open-search-class> The Search portlet obtains an OpenSearch instance from each portlet that has the tag &ltopen-search-class> definition. For example, the portlet Directory (portlet ID 11) allows users to search for other users, organizations, or user groups. OpenSearch has been specified for the portlet Directory in $PORTAL_ROOT_HOME/WEB-INF/liferayportlet. xml as follows: <open-search-class>com.liferay.portlet.directory.util.DirectoryOpenSearchImpl</open-search-class> As shown in the preceding code, the open-search-class value must be a class that implements com.liferay.portal.kernel.search.OpenSearch, which is called to get search results in the OpenSearch standard.Besides the OpenSearch framework, the portal provides UI taglib to display search results. In$PORTAL_ROOT_HOME/html/portlet/search/view.jsp, you could find the following code. <liferay-ui:search /> For more details on UI taglib <liferay-ui:search>, you would check JSP files start.jsp and end.jsp under the folder $PORTAL_ROOT_HOME/html/taglib/ui/ search. In addition, the portal scopes OpenSearch results through the UI taglib <liferay-ui:search>. For example, the scope of search results, namely, Everything or This Community has been specified in $PORTAL_ROOT_HOME/html/taglib/ui/search/start.jsp as follows: <select name="<%= namespace %>groupId"><!-ignore details --><option value="<%= group.getGroupId() %>" <%= (groupId != 0) ?"selected" : "" %>><liferay-ui:message key='<%= "this-" +(group.isOrganization() ? "organization" : "community") %>' /></option></select> As you can see, the value of This Community would be an organization or community. By default, the OpenSearch implementation in the portal supports both formats: ATOM and RSS. The default format would be ATOM. Therefore, the search results from plugin portlets must be returned in the format ATOM. For example, in the portlet Alfresco Content, the format of search results must be ATOM. Why? The portlet Search has specified the following code in $PORTAL_ROOT_HOME/html/ portlet/search/open_search_description.jsp. <OpenSearchDescription ><!-ignore details --><Url type="application/rss+xml" template="<%=themeDisplay.getPortalURL() %><%= PortalUtil.getPathMain() %>/search/open_search?keywords={searchTerms}&amp p={startPage?}&ampc={count?}&amp format=rss" /></OpenSearchDescription> In addition, search results are displayed in pagination through the search container. Fortunately, search container is configurable. The portal has specified the following properties in portal.properties. search.container.page.delta.values=5,10,20,30,50,75search.container.page.iterator.max.pages=25 As shown in the preceding code, the property search.container.page.delta. values sets the available values for the number of entries to be displayed per page. An empty value, or commenting out the value, will disable delta resizing. The default of 20 will apply in all cases. Note that you need to always include 20 because it is the default page size when no delta is specified. The absolute maximum allowed delta value is 200. The property search.container.page.iterator.max.pages sets the maximum number of pages, which are available before and / or after the currently displayed page. Of course, you could override these properties anytime in portal-ext.properties. Configuration As mentioned previously, OpenSearch in the Search portlet covers the in-and-out of Blogs, Calendar, Bookmarks, Document Library, Image Gallery, Message Boards, Wiki, Web Content, Directory, and so on. Fortunately, the portal adds the ability to remove these portlets from the list of portlets searched by the portlet Search as follows: com.liferay.portlet.blogs.util.BlogsOpenSearchImpl=true## ignore detailscom.liferay.portlet.wiki.util.WikiOpenSearchImpl=true As shown in the preceding code, you can set any of these properties to false to disable the portlet from being searched by the Search portlet in portal-ext.properties. Customization In real cases, you may be required to use the portlet Search in different ways. You would be able to customize the portlet Search. Here we're going to discuss how to use the Search portlet in Social Office and how to use the Search portlet in themes. The Social Office overrides the UI taglib <liferay-ui:search> in the portlet soportlet through JSP file hooks in $AS_WEB_APP_HOME/so-portlet/META-INF/ custom_jsps/html/taglib/ui/search/start.jsp as follows: <liferay-util:include page="/html/taglib/ui/search/start.portal.jsp"/><c:if test="<%= group.isUser() %>"><script type="text/javascript">var searchOptions = jQuery('select[name=<%= namespace %>groupId] option')searchOptions.each( //ignore details )</script></c:if> As shown in the preceding code, the Social Office overrides the look and feel of the portlet Search. For example, it will remove search options. Of course, you can add the portlet Search as a runtime portlet in themes. You could add the Velocity template $theme.search() in the theme, specifically in the VM file portal_normal.vm or the VM file included in portal_normal.vm. For example,Social Office specified the following lines in the theme so-theme such as $AS_WEB_ APP_HOME/so-theme/templates/navigation_top.vm. #if ($is_signed_in)<div class="my-search">$theme.search()</div>#end As shown in the preceding code, when the user signs in, the Social Office will show the customized portlet Search in "my-search" style. OpenSearch in plugins In general, the portal provides an OpenSearch framework, so that a user can create an OpenSearch implementation in the plugin environment. The portal will try to call this OpenSearch implementation when you hit the Search portlet. The Search portlet goes through all registered implementations and tries to create an instance. We could search content from the Alfresco repository, just as we did for Blogs, Bookmarks, Calendar, Directory, and so on via the OpenSearch framework of the portlet Search. How does it work? How does it work? First of all, we need to install the Alfresco Web Client, and then we need to deploy the portlet Alfresco Content. By following these three steps, you would bring the Alfresco Web Client into Tomcat as well: Download the latest Alfresco-Tomcat bundle from http://www.alfresco.com, and install it to the folder $ALFRESCO_HOME. Locate the Alfresco Web Client application alfresco.war under the folder $ALFRESCO_HOME, and drop it to the folder $TOMCAT_AS_DIR/webapps. Create a database alfresco in MySQL and restart Tomcat. drop database if exists alfrescocreate database alfresco character set utf8grant all on alfresco.* to 'alfresco'@'localhost' identified by'alfresco' with grant optiongrant all on alfresco.* to 'alfresco'@'localhost.localdomain'identified by 'alfresco' with grant option Then we could deploy the plugin Alfresco Content portlet. The following is example of how to bring the portlet Alfresco Content into the portal. Download the WAR file ${alfresco.content.portlet.war} from http:// liferay.cignex.com/palm_tree/book/0387/chapter12/netvibeswidget- portlet-6.0.0.1.war. Drop the WAR file ${alfresco.content.portlet.war} to the folder$LIFERAY_HOME/deploy when the portal is running. That's it! When you search for content again in the portlet Search, you will be able to see assets coming from the Alfresco Web Client. In addition, you would see a message like "Searched Alfresco Content, Blogs …" in the portlet Search. Web services As you can see, the Alfresco Content plugin displays content from the Alfresco repository. Two kinds of services are involved—web services and RESTful services. A web service is a software system designed to support interoperable machine-tomachine interaction over a network. With the portlet Alfresco Content, you could search or navigate content of the Alfresco repository via web services. You have to simply go to More | Configuration | Setup | Current of the portlet Alfresco Content first. Then you should enter a User ID like "admin" and a password like "admin", and click on the Save button. Now, you will be able to see the root folder "Company Home". The following property is specified in the portlet Alfresco Content: $AS_WEB_APP_HOME/alfresco-content-portlet/WEB-INF/classes/portlet.propertiescontent.server.url=http://localhost:8080 As shown in the preceding code, the property content.server.url sets the location of the Alfresco server URL. RESTful services Representational State Transfer (REST) is a style of software architecture for distributed hypermedia systems. Alfresco not only provides the ability to expose its search engines via OpenSearch, but it also provides an aggregate OpenSearch feature in the Alfresco Web Client through RESTful services. To summarize, Alfresco RESTful services-based keyword search mimics the keyword search of the Alfresco Web Client. The following search URL template is used for OpenSearch in the plugin Alfresco Content. http://<host>:<port>/alfresco/service/api/search/keyword.atom?q={searchTerms}&p={startPage?}&c={count?}&l={language?} In the preceding code, the URL will have the following values: searchTerms: The keyword or keywords to search startPage (optional): The page number of search results desired by the client count (optional): The number of search results per page (the default is 10) language (optional): The locale to search with (XML 1.0 Language ID, for example en-GB) Besides RESTful APIs for OpenSearch, Alfresco provides the following RESTful APIs built as Web Scripts: Repository API Reference: Remote services for interacting with the Alfresco Repository CMIS API Reference: Content Management Interoperability Services Portlets such as My Inbox and My Checked-Out for hosting in any portal Office Integration for hosting in Microsoft Office Moreover, in order to allow the Alfresco Content portlet to support OpenSearch, the portlet has set the value open-search-class at $AS_WEB_APP_HOME/alfrescocontent-portlet/WEB-INF/liferay-portlet.xml as follows: <open-search-class>com.liferay.portlet.alfrescocontent.util.AlfrescoOpenSearchImpl</open-search-class> Finally, the portlet has set the following values in $AS_WEB_APP_HOME/alfrescocontent-portlet/WEB-INF/classes/portlet.properties, which will be used to query Alfresco via OpenSearch. open.search.enabled=true## ignore details open.search.path=/alfresco/service/api/search/keyword.atom Of course, you could override the preceding properties according to your own environment's, for example, server domain name, port number, search user name, search password, and so on. CMIS Besides web services and OpenSearch, Alfresco supports CMIS as well. Content Management Interoperability Services (CMIS) is a specification that defines how Enterprise Content Management (ECM) systems exchange content, defining a domain model and set of bindings, such as Web Service and RESTful Atom-Pub that can be used by applications to work with one or more content management repositories. Alfresco supports the CMIS REST API Binding, the CMIS web services API Binding, and Web Service WSDL. The portal has specified the following properties for CMIS in portal.properties: cmis.credentials.username=nonemis.credentials.password=nonecmis.repository.url=http://localhost:8080/alfresco/service/api/cmiscmis.repository.version=1.0cmis.system.root.dir=Liferay Home As mentioned earlier, we could use CMIS hook to configure a repository. In addition, we could use these properties in the Alfresco Content portlet and provide OpenSearch capabilities based on CMIS.
Read more
  • 0
  • 0
  • 2891

article-image-audio-enhancements-p4aploneaudio-plone-33
Packt
17 May 2010
14 min read
Save for later

Audio Enhancements with p4a.ploneaudio in Plone 3.3

Packt
17 May 2010
14 min read
(For more resources on Plone, see here.) Audio enhancements with p4a.ploneaudio One of the most advanced products to boost the audio features of Plone is p4a.ploneaudio. Like its image sister p4a.ploneimage it doesn't bring a content type on its own, but expands existing ones. As you might have guessed already, the File content type and the folderish ones (Folder, Large Folder, and Collection) are chosen for the enhancement. To install it, add the following code to the buildout of our instance: [buildout]...[instance]...eggs =${buildout:eggs}Plonep4a.ploneaudiozcml =p4a.ploneaudio After running the buildout and restarting the instance, we need to install the product as an add-on product. We find it with the product name Plone4Artists Audio (p4a.ploneaudio). Enhancing files Installing the p4a.ploneaudio product enables the enhancement of the File content type of ATContentTypes. Unlike with the image enhancement, not all files are automatically enhanced with additional audio features. p4a.ploneaudio comes with a MIME type filter. If we upload a file with one of the meta types such as audio/MPEG or application/Ogg, the file will automatically be audio enhanced. All other files (such as ZIP files, EXE files, and so on) stay untouched. Technically speaking, this works via a named adapter. The first thing we see is the modified default view for audio-enhanced files: On the right side we see some technical information about the audio file itself. We find the size, the format (MP3 or Ogg), the bitrate, the frequency, and the length of the track there. As with any other content type, we have the title and the description at the top of the content area. For the audio-enhanced content, the description has changed from a simple text field to a rich text field. We find four buttons after the usual CMS bar (the belowcontenttitle slot) containing the author and the modification date of the file. Each of these buttons retrieves the audio file in a different way: Button Action Description     Play An embedded audio player written in Flash. Clicking on it starts playback immediately.     Pop up Opens a pop-up window with a Flash player playing the audio track. This is useful if someone wants to play the track while continuing to browse the site.     Stream Clicking on the button returns an M3U playlist with the URL of the file. The browser/operating system needs to take care of the handling of the stream. If you have a Mac, the file will be streamed to iTunes.     Download This is the standard behavior of Plone’s File content-type. The file is returned to the client like any other file object. It can be saved or opened with the favorite media player of the operating system.   We find a long list of additional information on the audio track below the player and streaming buttons. This information is the metadata stored with the audio file and is gathered during the enhancing process. It can be changed and written back to the file. Let's take a closer look on the enhancement process. One important step here is marking the content object with two interfaces: One is p4a.subtyper.interfaces.ISubtyped. This interface marks the content as subtyped. The other interface is p4a.audio.interfaces.IAudioEnhanced. This interface describes the type of enhancement, which is audio content in this case. All other views and components available with the enhanced version bind to the p4a.audio.interfaces.IAudioEnhanced interface. Additionally, p4a.ploneaudio tries to extract as much of the metadata information from the file as possible. The title is retrieved from the metadata and changed. Let's see what happens when a file is added in detail: It is possible to write custom audio enhancers if needed. The enhancers are queried as named adapters by the MIME type on the IAudioDataAccessor interface. Enhancing containers With p4a.ploneaudio, we can turn any Plone folder into an audio-enhanced folder by choosing Audio container from the Subtype menu. Two marker interfaces are attached to the container: p4a.subtyper.interfaces.ISubtyped p4a.audio.interfaces.IAudioContainerEnhanced The default view of the container is changed utilizing the IAudioContainerEnhanced interface. The new default view is audio-container.html, which comes with the p4a.ploneaudio product. In the View option we see one box for each track. For each track, the title and the cover artwork is shown. There is also an embedded Flash player to play each track directly. There are some other container views that come with the product as follows: audio-album.html (album view) audiocd-popup.html (pop-up view) cd_playlist.xspf And the default edit view for IAudioContainerEnhaced-marked folders is overridden. The audio-album.html view presents the audio content of the container in a slightly different way. The single tracks are arranged in a table. Two variants of this view are exposed in the Display menu of the container—Album view and Album view with no track numbers. Both these views are more compact than the default audio container view and have the same layout, except that the second one omits the column with the track numbers. As for the other audio container views, there is a player for each track. Moreover, there are two buttons on the top of the page. One is the commonly used RSS icon and the other one is the familiar pop-up player button . By clicking on the RSS icon, we get to the stream (or podcast of the folder). This may not be too interesting for a standard static Folder, but can be for a Collection where the content changes more dynamically. The pop-up player for a folder looks and operates slightly differently as the file standalone variant. It contains all tracks that are part of the audio container as a playlist. Lastly, there is the cd_playlist.xspf view. This view is not exposed via a display or as an action. It provides the audio data as a XSPF stream. The XML Shareable Playlist Format: XSPF The XML Shareable Playlist Format (XSPF) is an XML file format for storing playlists of digital audio. The audio can be located locally or online. Last.fm uses XSPF for providing its playlists. An example playlist looks like this: <?xml version="1.0" encoding="UTF-8"?><playlist version="1" ><trackList><track><location>example.mp3</location><creator>Tom</creator><album>Thriller</album><annotation>A comment</annotation></track><track><location>another.mp3</location><creator>Tom</creator></track></trackList></playlist> There is a list of applications supporting the XSPF format on the XSPF (http://xspf.org/) website. The default XSPF view of p4a.ploneaudio does not include all possible information. It provides the following attributes: location: This is the required location (URL) of the song. image: The album artwork that may be included with each track. annotation: p4a.ploneaudio collects information about the title, artist, album, and year in this field. It is easy to write a custom implementation of an XSPF view. Look at the available fields at the XSPF home page and the XSPF implementation of p4a.audio. We find the template named cd_playlist.xspf.pt in the p4a.audio.browser module. p4a.ploneaudio and the Plone catalog Besides the customized default views and the additional views, p4a.ploneaudio comes with a number of other changes. One very important change is the disclosure of some audio metadata fields to the portal catalog. This allows us to use them in catalog queries in general and smart folders in particular. The following indexes are added: Artist Genre Track Format The Artist attribute is exposed as metadata information in the catalog. Also, the genre and the artist name are added to the full text index SearchableText. The values for the genre field are hardcoded. The ID3 tag genre list is used together with the Winamp extensions. They are stored as a vocabulary. The term titles are resolved for Searchable Text, but not for the index and the Collection field. Accessing audio metadata in Collections To access catalog information in collections, it needs to be exposed to the collections tool. This can either be done by a product or TTW in the Plone configuration panel. p4a.ploneaudio comes with a modification of the fields: Artist (Artist name) Genre (Genre) Format (MIME Types) Let's say we want a collection of all our MP3 files. All we have to do is add a MIME Types criterion to our collection and set audio/mpeg as the value: ATAudio migration If you have an older Plone site (2.5), you probably have ATAudio installed to deal with audio content.ATAudio has features similar to p4a.ploneaudio. This is not surprising as p4a.ploneaudio was derived from ATAudio. The main difference is that ATAudio provides a content type, while p4a.ploneaudio reuses an existing one. If you want to switch from ATAudio to p4a.ploneaudio for one or the other reason, p4a.ploneaudio comes with a migration routine. One reason for switching might be that ATAudio is not actively developed any more and probably doesn't work with recent versions of Plone. For migrating, you need to call migrate-ataudioconfiglet.html and follow the instructions there. The migration view is available only if ATAudio is installed. There is a little bit of a catch-22 situation because p4a.ploneaudio doesn't run on Plone 2.5 and ATAudio doesn't run on Plone 3. This means there is no good starting point for the migration. At least, there is a version of ATAudio that does install in Plone 3 in the collective repository: http://svn.plone.org/svn/collective/ATAudio/tags/0.7- plone3migration/. Extracting metadata with AudioDataAccessors The IAudioDataAccessor interface is used for extracting metadata from binary audio content. If uploading a file, Plone tries to acquire a named adapter for the interface with the MIME type as the key. It has the following layout: class IAudioDataAccessor(interface.Interface):"""Audio implementation accessor (ie MP3, ogg, etc)."""audio_type = schema.TextLine(title=_(u'Audio Type'),required=True,readonly=True)def load(filename):"""Load from filename"""def store(filename):"""Store to filename""" The audio_type field contains a human-readable description of the audio type. In the case of MP3, the Unicode string "MPEG-1 Audio Layer 3" is used. The load and store methods are used for reading/writing the metadata from/to the audio file. The definition for the MP3 adapter looks like this: <adapterfor="p4a.audio.interfaces.IPossibleAudio"factory="._audiodata.MP3AudioDataAccessor"provides="p4a.audio.interfaces.IAudioDataAccessor"name="audio/mpeg"/> The component is registered for the p4a.audio.interfaces.IPossibleAudio interface. All classes marked with this interface are capable of getting converted to an audio-enhanced object. The standard product marks the File content type with this interface. The adapter provides the p4a.audio.interfaces.IAudioDataAccessor interface, which is the marker for the lookup. The name attribute of adapter is the key for the lookup and needs to be set to the MIME type of the audio file that should be processed. Now, the factory does the actual work of loading and storing the metadata from the audio file. p4a.ploneaudio and FLAC For the moment, p4a.ploneaudio only supports MP3 and Ogg Vorbis. This is a reasonable choice. Both formats are streamable and were made for good audio quality with small file sizes. We want to add FLAC support. We use mutagen for metadata extraction. Mutagen is an audio metadata extractor written in Python. It is capable of reading and writing many audio metadata formats including: FLAC M4A Monkey's Audio MP3 Musepack Ogg Vorbis True Audio WavPack OptimFROG Let's remember the flow chart of the audio adding process. We recall that we need a metadata extractor for our FLAC MIME type. First, we need to register a named adapter for this purpose. This is very similar to the MP3 adapter we saw before: <adapterfor="p4a.audio.interfaces.IPossibleAudio"factory=".flac._audiodata.FlacAudioDataAccessor"provides="p4a.audio.interfaces.IAudioDataAccessor"name="application/x-flac"/> The adapter is used for objects implementing the p4a.audio.interfaces.IPossibleAudio interface. The factory does the work of extracting the metadata. The adapter provides the p4a.audio.interfaces.IAudioDataAccessor interface. This is what the adapter is made for and the name is application/x-flac, which is the MIME type of FLAC audio files. Next, we define the metadata accessor: from mutagen.flac import Open as openaudio...from p4a.audio.ogg._audiodata import _safe First, we need some third-party imports. For the metadata extraction, we use the FLAC accessor of the mutagen library. _safe is a helper method. It returns the first element if the given parameter is a list or a tuple, or the element itself. class FlacAudioDataAccessor(object):"""An AudioDataAccessor for FLAC"""implements(IAudioDataAccessor)def __init__(self, context):self._filecontent = context The first lines are the boilerplate part. The adapter class implements the interface the adapter provides. In the constructor, we get the context of the adapter and save it in the _filecontent variable of the instance. @propertydef audio_type(self):return 'FLAC'@propertydef _audio(self):return IAudio(self._filecontent)@propertydef _audio_data(self):annotations = IAnnotations(self._filecontent)return annotations.get(self._audio.ANNO_KEY, None) The audio_type property is just for information purposes and required by the interface. It is displayed in the audio view. The _audio property is a shortcut for accessing the IAudio adapter for the context. The audio_data property is a shortcut for accessing the metadata annotated to the context. def load(self, filename):flacfile = openaudio(filename)self._audio_data['title'] = _safe(flacfile.get('title', ''))self._audio_data['artist'] = _safe(flacfile.get('artist', ''))self._audio_data['album'] = _safe(flacfile.get('album', ''))self._audio_data['year'] = _safe(flacfile.get('date', ''))self._audio_data['idtrack'] = _safe(flacfile.get('tracknumber', ''))self._audio_data['genre'] = _safe(flacfile.get('genre', ''))self._audio_data['comment'] = _safe(flacfile.get('description', ''))self._audio_data['bit_rate'] = long(flacfile.info.bits_per_sample)self._audio_data['length'] = long(flacfile.info.length)self._audio_data['frequency'] = long(flacfile.info.sample_rate) The load method is required by the IAudioDataAccessor interface. It fetches the metadata using the mutagen method from the audio file and stores it as an annotation on the context. def store(self, filename):flacfile = openaudio(filename)flacfile['title'] = self._audio.title or u''flacfile['artist'] = self._audio.artist or u''flacfile['album'] = self._audio.album or u''flacfile['date'] = self._audio.year or u''flacfile['tracknumber'] = self._audio.idtrack or u''flacfile.save() The store method is required by the IAudioDataAccessor interface as well and its purpose is to write the metadata from the context annotation back to the audio file. We have covered the following in this article series: Manipulation of audio content stored as File content in Plone The different formats used for the binary storage of audio data Storing and accessing MP3 audio metadata with the ID3 tag format Managing metadata, formats, and playlists with p4a.ploneaudio in Plone Including a custom embedded audio player in Plone Using the Flowplayer product to include an audio player standalone in rich text and as a portlet >> Continue Reading: Using Flowplayer in Plone 3. Further resources on this subject: Plone 3 Multimedia [book] Using Flowplayer in Plone 3 [article] Audio Enhancements with p4a.ploneaudio in Plone 3.3 [article] Red5: A video-on-demand Flash Server [article]   Plone 3.3 Products Development Cookbook [book] Creating a custom type with paster in plone 3 [article] Improving Plone 3 Product Performance [article]   Plone 3 for Education [book] Calendaring with Plone 3 for Education [article] Showcasing Personnel with Faculty/Staff Directory using Plone 3 [article] Plone 3 Themes [article] Blogs and forums using Plone 3 [article]   Plone 3 Theming [book] Creating, Installing and Tweaking your theme using Plone 3 [article] Skinner's Toolkit for Plone 3 Theming (Part 1) [article] Skinner's Toolkit for Plone 3 Theming (Part 2) [article] Add-on Tools and Theming Tips for Plone 3 [article]   Practical Plone 3: A Beginner's Guide to Building Powerful Websites [book] Find and Install Add-Ons that Expand Plone Functionality [article] Structure the Content on your Plone Site [article] Safely manage different vesions of content with plone [article] Creating New Types of Plone Portlets [article] Show Additional Information to Users and Visitors of Your Plone Site [article]
Read more
  • 0
  • 0
  • 1635

article-image-customizing-your-vim-work-area
Packt
14 May 2010
12 min read
Save for later

Customizing Your Vim for work area

Packt
14 May 2010
12 min read
(Read more interesting articles on Hacking Vim 7.2 here.) Work area personalization In this article, we introduce a list of smaller, good-to-know modifications for the editor area in Vim. The idea with these recipes is that they all give you some sort of help or optimization when you use Vim for editing text or code. Adding a more visual cursor Sometimes, you have a lot of syntax coloring in the file you are editing. This can make the task of tracking the cursor really hard. If you could just mark the line the cursor is currently in, then it would be easier to track it. Many have tried to fix this with Vim scripts, but the results have been near useless (mainly due to slowness, which prevented scrolling longer texts at an acceptable speed). Not until version 7 did Vim have a solution for this. But then it came up with not just one, but two possible solutions for cursor tracking. The first one is the cursorline command , which basically marks the entire line with, for example, another background color without breaking the syntax coloring. To turn it on, use the following command: :set cursorline The color it uses is the one defined in the CursorLine color group. You can change this to any color or styling you like, for example: :highlight CursorLine guibg=lightblue ctermbg=lightgray If you are working with a lot of aligned file content (such as tab-separated data), the next solution for cursor tracking comes in handy: :set cursorcolumn This command marks the current column (here the cursor is placed) by coloring the entire column through the entire file, for example. As with the cursor line, you can change the settings for how the cursor column should be marked. The color group to change is named cursorcolumn. Adding both the cursor line and column marking makes the cursor look like a crosshair, thus making it impossible to miss. Even though the cursorline and cursorcolumn functionalities are implemented natively in Vim, it can still give quite a slowdown when scrolling through the file. Adding line numbers Often when compiling and debugging code, you will get error messages stating that the error is in some line. One could, of course, start counting lines from the top to find the line, but Vim has a solution to go directly to some line number. Just execute :XXX where XXX is the line number, and you will be taken to the XXX line. Alternatively, you can go into normal mode (press the Esc key) and then simply use XXXgg or XXXG (again XXX is the line number). Sometimes, however, it is nice to have an indication of the line number right there in the editor, and that's where the following command comes in handy: :set number Now, you get line numbers to the left of each line in the file. By default, the numbers take up four columns of space, three for numbers, and one for spacing. This meansthat the width of the numbers will be the same until you have more than 999 lines. If you get above this number of lines, an extra column will be added and the content will be moved to the right. Of course, you can change the default number of columns used for the line numbers. This can be achieved by changing the following property: :set numberwidth=XXX Replace XXX with the number of columns that you want. Even though it would be nice to make the number of columns higher in order to get more spacing between code and line numbers, this is not achievable with the numberwidth property. This is because the line numbers will be right-aligned within the columns. In the following figure, you can see how line numbers are shown as right-aligne when a higher number of columns are set in numberwidth: You can change the styling of the line numbers and the columns they are in by making changes to the LineNr color group. Spell checking your language We all know it! Even if we are really good spellers, it still happens from time to time that we misspell a word or hit the wrong keys. In the past, you had to run your texts (that you had written in Vim) through some sort of spell checker such as Aspell or Ispell . This was a tiresome process that could only be performed as a final task, unless you wanted to do it over and over again. With version 7 of Vim, this troublesome way of spell checking is over. Now, Vim has got a built-in spell checker with support for more than 50 languages from around the world. The new spell checker marks the wrongly written words as you type them in, so you know right away that there is an error. The command to execute to turn on this helpful spell checker feature is: :set spell This turns on the spell checker with the default language (English). If you don't use English much and would prefer to use another language in the spell checker, then there is no problem changing this. Just add the code of the language you would like to use to the spelllang property . For example: :set spelllang=de Here, the language is set to German (Deutsch) as the spell checker language of choice. The language name can be written in several different formats. American English, for example, can be written as: en_us us American Names can even be an industry-related name such as medical. If Vim does not recognize the language name, Vim will highlight it when you execute the property-setting command. If you change the spelllang setting to a language not already installed, then Vim will ask you if it should try to automatically retrieve it from the Vim homepage. Personally, I tend to work in several different languages in Vim, and I really don't want to tell Vim all the time which language I am using right now. Vim has a solution for this. By appending more language codes to the spelllang property (separated by commas), you can tell Vim to check the spelling in more than one language. :set spelllang=en,da,de,it Vim will then take the languages from the start to the end, and check if the words match any word in one of these languages. If they do, then they are not marked as a spelling error. Of course, this means that you can have a word spelled wrong in the language you are using but spelled correctly in another language, thereby introducing a hidden spelling error. You can find language packages for a lot of languages at the Vim FTP site: ftp://ftp.vim.org/pub/vim/runtime/spell. Spelling errors are marked differently in Vim and Gvim. In regular Vim, the misspelled word is marked with the SpellBad color group (normally, white on red). In Gvim, the misspelled word is marked with a red curvy line underneath the word. This can, of course, be changed by changing the settings of the color group. Whenever you encounter a misspelled word, you can ask Vim to suggest better ways to spell the word. This is simply done by placing the cursor over the word, going into the normal mode (press Esc), and then pressing Z + =. If possible, Vim will give you a list of good guesses for the word you were actually trying to write. In front of each suggestion is a number. Press the number you find in front of the right spelling (of the word you wanted) or press Enter if the word is not there. Often Vim gives you a long list of alternatives for your misspelled word, but unless you have spelled the word completely wrong, chances are that the correct word is within the top five of the alternatives. If this is the case, and you don't want to look through the entire list of alternatives, then you can limit the output with the following command: :set spellsuggest=X Set X to the number of alternative ways of spelling you want Vim to suggest. Adding helpful tool tips In the Modifying tabs recipe, we learned about how to use tool tips to store more information using less space in the tabs in Gvim. To build on top of that same idea with this recipe, we move on and use tool tips in other places in the editor. The editing area is the largest part of Vim. So, why not try to add some extra information to the contents of this area by using tool tips? In Vim, tool tips for the editing area are called balloons and they are only shown when the cursor is hovering over one of the characters. The commands you will need to know in order to use the balloons are: The first command is the one you will use to actually turn on this functionality in Vim. :set ballooneval The second command tells Vim how long it should wait before showing the tool tip/balloon (the delay is in milliseconds and as a default is set to 600). :set balloondelay=400 The last command is the one that actually sets the string that Vim will show in the balloon. :set ballonexpr="textstring" This can either be a static text string or the return of some function. In order to have access to information about the place where you are hovering over a character in the editor, Vim provides access to a list of variables holding such information: abc<space>and abc<enter> Both expand 123abc<space> Will not expand as the abbreviation is part of a word abcd<space> Will not expand because there are letters after the abbreviation abc Will not expand until another special letter is pressed So with these variables in hand, let's look at some examples. Example 1: The first example is based on one from the Vim help system. It shows how to make a simple function that will show the information from all the available variables. function! SimpleBalloon() return 'Cursor is at line/column: ' . v:beval_lnum . '/' . v:beval_col . ' in file ' . bufname(v:beval_bufnr) . '. Word under cursor is: "' . v:beval_text . '"' endfunction set balloonexpr=SimpleBalloon() set balloonevalcode 59 The result will look similar to the following screenshot: Example 2: Let's look at a more advanced example that explores the use of balloons for specific areas in editing. In this example, we will put together a function that gives us great information balloons for two areas at the same time: Misspelled words: The balloon gives ideas for alternative words Folded text: The balloon gives a preview of what's in the fold So, let's take a look at what the function should look for, to detect if the cursor is hovering over either a misspelled word or a fold line (a single line representing multiple lines folded behind it). In order to detect if a word is misspelled, the spell check would need to be turned on: :set spell If it is on, then calling the built-in spell checker function—spellsuggest()—would return alternative words if the hovered word was misspelled. So, to see if a word is misspelled, just check if the spellsuggest() returns anything. There is, however, a small catch. spellsuggest() also returns alternative, similar words if the word is not misspelled. To get around this, another function has to be used on the input word before putting it into the spellsuggest() function . This extra function is the spellbadword(). This basically moves the cursor to the first misspelled word in the sentence that it gets as input, and then returns the word. We just input a single word and if it is not misspelled, then the function cannot return any words. Putting no word into spellsuggest() results in getting nothing back, so we can now check if a word is misspelled or not. It is even simpler to check if a word is in a line, in a fold. You simply have to call the foldclosed()function on the line number of the line over which the cursor is hovering (remember v:beval_lnum ?), and it will return the number of the first line in the current fold; if not in a fold, then it returns -1. In other words, if foldclosed(v:beval_lnum) returns anything but -1 and 0, we are in a fold. Putting all of this detection together and adding functionality to construct the balloon text ends up as the following function: function! FoldSpellBalloon() let foldStart = foldclosed(v:beval_lnum ) let foldEnd = foldclosedend(v:beval_lnum) let lines = [] " Detect if we are in a fold if foldStart < 0 " Detect if we are on a misspelled word let lines = spellsuggest( spellbadword(v:beval_text)[ 0 ], 5, 0 ) else " we are in a fold let numLines = foldEnd - foldStart + 1 " if we have too many lines in fold, show only the first 14 " and the last 14 lines if ( numLines > 31 ) let lines = getline( foldStart, foldStart + 14 ) let lines += [ '-- Snipped ' . ( numLines - 30 ) . ' lines --' ] let lines += getline( foldEnd - 14, foldEnd ) else "less than 30 lines, lets show all of them let lines = getline( foldStart, foldEnd ) endif endif " return result return join( lines, has( "balloon_multiline" ) ? "n" : " " ) endfunction set balloonexpr=FoldSpellBalloon() set ballooneval The result is some really helpful balloons in the editing area of Vim that can improve your work cycle tremendously. The following screenshot shows how the information balloon could look when it is used to preview a folded range of lines from a file: Instead, if the balloon is used on a misspelled word, it will look like the following screenshot: In Production Boosters, you can learn more about how to use folding of lines to boost productivity in Vim.
Read more
  • 0
  • 0
  • 4103

article-image-creating-nhibernate-session-access-database-within-aspnet
Packt
14 May 2010
7 min read
Save for later

Creating a NHibernate session to access database within ASP.NET

Packt
14 May 2010
7 min read
NHibernate is an open source object-relational mapper, or simply put, a way to rapidly retrieve data from your database into standard .NET objects. This article teaches you how to create NHibernate sessions, which use database sessions to retrieve and store data into the database. In this article by Aaron B. Cure, author of Nhibernate 2 Beginner's Guide we'll talk about: What is an NHibernate session? How does it differ from a regular database session? Retrieving and committing data Session strategies for ASP.NET (Read more interesting articles on Nhibernate 2 Beginner's Guide here.) What is an NHibernate session? Think of an NHibernate session as an abstract or virtual conduit to the database. Gone are the days when you have to create a Connection, open the Connection, pass the Connection to a Command object, create a DataReader from the Command object, and so on. With NHibernate, we ask the SessionFactory for a Session object, and that's it. NHibernate handles all of the "real" sessions to the database, connections, pooling, and so on. We reap all the benefits without having to know the underlying intricacies of all of the database backends we are trying to connect to. Time for action – getting ready Before we actually connect to the database, we need to do a little "housekeeping". Just a note, if you run into trouble (that is, your code doesn't work like the walkthrough), then don't panic. See the troubleshooting section at the end of this Time for action section. Before we get started, make sure that you have all of the Mapping and Common files and that your Mapping files are included as "Embedded Resources". Your project should look as shown in the following screenshot: The first thing we need to do is create a new project to use to create our sessions. Right-click on the Solution 'Ordering' and click on Add | New Project. For our tests, we will use a Console Application and name it Ordering.Console. Use the same location as your previous project. Next, we need to add a few references. Right-click on the References folder and click on Add Reference. In VB.NET, you need to right-click on the Ordering.Console project, and click on Add Reference. Select the Browse tab, and navigate to the folder that contains your NHibernate dlls. You should have six files in this folder. Select the NHibernate.dll, Castle.Core.dll, Castle.DynamicProxy2.dll, Iesi.Collections.dll, log4net.dll, and NHibernate.ByteCode.Castle.dll files, and click on OK to add them as references to the project. Right-click on the References folder (or the project folder in VB.NET), and click on Add Reference again. Select the Projects tab, select the Ordering.Data project, and click on OK to add the data tier as a reference to our console application. The last thing we need to do is create a configuration object. We will discuss configuration in a later chapter, so for now, it would suffice to say that this will give us everything we need to connect to the database. Your current Program.cs file in the Ordering.Console application should look as follows: using System;using System.Collections.Generic;using System.Text;namespace Ordering.Console{ class Program { static void Main(string[] args) { } }} Or, if you are using VB.NET, your Module1.vb file will look as follows: Module Module1 Sub Main() End SubEnd Module At the top of the file, we need to import a few references to make our project compile. Right above the namespace or Module declarations, add the using/Imports statements for NHibernate, NHibernate.Cfg, and Ordering.Data: using NHibernate;using NHibernate.Cfg;using Ordering.Data; In VB.NET you need to use the Imports keyword as follows: Imports NHibernateImports NHibernate.CfgImports Ordering.Data Inside the Main() block, we want to create the configuration object that will tell NHibernate how to connect to the database. Inside your Main() block, add the following code: Configuration cfg = new Configuration();cfg.Properties.Add(NHibernate.Cfg.Environment.ConnectionProvider, typeof(NHibernate.Connection.DriverConnectionProvider) .AssemblyQualifiedName); cfg.Properties.Add(NHibernate.Cfg.Environment.Dialect, typeof(NHibernate.Dialect.MsSql2008Dialect) .AssemblyQualifiedName); cfg.Properties.Add(NHibernate.Cfg.Environment.ConnectionDriver, typeof(NHibernate.Driver.SqlClientDriver) .AssemblyQualifiedName); cfg.Properties.Add(NHibernate.Cfg.Environment.ConnectionString, "Server= (local)SQLExpress;Database= Ordering;Trusted_Connection=true;"); cfg.Properties.Add(NHibernate.Cfg.Environment. ProxyFactoryFactoryClass, typeof (NHibernate.ByteCode.LinFu.ProxyFactoryFactory) .AssemblyQualifiedName); cfg.AddAssembly(typeof(Address).AssemblyQualifiedName); For a VB.NET project, add the following code: Dim cfg As New Configuration()cfg.Properties.Add(NHibernate.Cfg.Environment. _ ConnectionProvider, GetType(NHibernate.Connection. _ DriverConnectionProvider).AssemblyQualifiedName) cfg.Properties.Add(NHibernate.Cfg.Environment.Dialect, _ GetType(NHibernate.Dialect.MsSql2008Dialect). _ AssemblyQualifiedName) cfg.Properties.Add(NHibernate.Cfg.Environment.ConnectionDriver, _ GetType(NHibernate.Driver.SqlClientDriver). _ AssemblyQualifiedName) cfg.Properties.Add(NHibernate.Cfg.Environment.ConnectionString, _ "Server= (local)SQLExpress;Database=Ordering; _ Trusted_Connection=true;") cfg.Properties.Add(NHibernate.Cfg.Environment. _ ProxyFactoryFactoryClass, GetType _ (NHibernate.ByteCode.LinFu.ProxyFactoryFactory). _ AssemblyQualifiedName) cfg.AddAssembly(GetType(Address).AssemblyQualifiedName) Lastly, right-click on the Ordering.Console project, and select Set as Startup Project, as shown in the following screenshot: Press F5 or Debug | Start Debugging and test your project. If everything goes well, you should see a command prompt window pop up and then go away. Congratulations! You are done! However, it is more than likely you will get an error on the line that says cfg.AddAssembly(). This line instructs NHibernate to "take all of my HBM.xml files and compile them". This is where we will find out how well we handcoded our HBM.xml files. The most common error that will show up is MappingException was unhandled. If you get a mapping exception, then see the next step for troubleshooting tips. Troubleshooting: NHibernate will tell us where the errors are and why they are an issue. The first step to debug these issues is to click on the View Detail link under Actions on the error pop up. This will bring up the View Detail dialog, as shown in the following screenshot: If you look at the message, NHibernate says that it Could not compile the mapping document: Ordering.Data.Mapping.Address.hbm.xml. So now we know that the issue is in our Address.hbm.xml file, but this is not very helpful. If we look at the InnerException, it says "Problem trying to set property type by reflection". Still not a specific issue, but if we click on the + next to the InnerException, I can see that there is an InnerException on this exception. The second InnerException says "class Ordering.Data.Address, Ordering.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null not found while looking for property: Id". Now we are getting closer. It has something to do with the ID property. But wait, there is another InnerException. This InnerException says "Could not find a getter for property 'Id' in class 'Ordering.Data.Address'". How could that be? Looking at my Address.cs class, I see: using System;using System.Collections.Generic;using System.Text;namespace Ordering.Data{ public class Address { }} Oops! Apparently I stubbed out the class, but forgot to add the actual properties. I need to put the rest of the properties into the file, which looks as follows: using System;using System.Collections.Generic;using System.Text; namespace Ordering.Data{ public class Address { #region Constructors public Address() { } public Address(string Address1, string Address2, string City, string State, string Zip) : this() { this.Address1 = Address1; this.Address2 = Address2; this.City = City; this.State = State; this.Zip = Zip; } #endregion #region Properties private int _id; public virtual int Id { get { return _id; } set { _id = value; } } private string _address1; public virtual string Address1 { get { return _address1; } set { _address1 = value; } } private string _address2; public virtual string Address2 { get { return _address2; } set { _address2 = value; } } private string _city; public virtual string City { get { return _city; } set { _city = value; } } private string _state; public virtual string State { get { return _state; } set { _state = value; } } private string _zip; public virtual string Zip { get { return _zip; } set { _zip = value; } } private Contact _contact; public virtual Contact Contact { get { return _contact; } set { _contact = value; } } #endregion }} By continuing to work my way through the errors that are presented in the configuration and starting the project in Debug mode, I can handle each exception until there are no more errors. What just happened? We have successfully created a project to test out our database connectivity, and an NHibernate Configuration object which will allow us to create sessions, session factories, and a whole litany of NHibernate goodness!
Read more
  • 0
  • 0
  • 8751
article-image-personalizing-vim
Packt
14 May 2010
12 min read
Save for later

Personalizing Vim

Packt
14 May 2010
12 min read
(Read more interesting articles on Hacking Vim 7.2 here.) Some of these tasks contain more than one recipe because there are different aspects for personalizing Vim for that particular task. It is you, the reader, who decides which recipes (or parts of it) you would like to read and use. Before we start working with Vim, there are some things that you need to know about your Vim installation, such as where to find the configuration files. Where are the configuration files? When working with Vim, you need to know a range of different configuration files. The location of these files is dependent on where you have installed Vim and the operating system that you are using. In general, there are three configuration files that you must know where to find: vimrc gvimrc exrc The vimrc file is the main configuration file for Vim. It exists in two versions—global and personal. The global vimrc file is placed in the folder where all of your Vim system files are installed. You can find out the location of this folder by opening Vim and executing the following command in normal mode: :echo $VIM The examples could be: Linux: /usr/share/vim/vimrc Windows: c:program filesvimvimrc The personal vimrc file is placed in your home directory. The location of the home directory is dependent on your operating system. Vim was originally meant for Unixes, so the personal vimrc file is set to be hidden by adding a dot as the first character in the filename. This normally hides files on Unix, but not on Microsoft Windows. Instead, the vimrc file is prepended with an underscore on these systems. So, examples would be: Linux: /home/kim/.vimrc Windows: c:documents and settingskim_vimrc Whatever you change in the personal vimrc file will overrule any previous setting made in the global vimrc file. This way you can modify the entire configuration without having to ever have access to the global vimrc file. You can find out what Vim considers as the home directory on your system by executing the following command in normal mode: :echo $HOME Another way of finding out exactly which vimrc file you use as your personal file is by executing the following command in the normal mode: :echo $MYVIMRC The vimrc file contains ex (vi predecessor) commands, one on each line, and is the default place to add modifications to the Vim setup. In the rest of the article, this file is just called vimrc. Your vimrc can use other files as an external source for configurations. In the vimrc file, you use the source command like this: source /path/to/external/file Use this to keep the vimrc file clean, and your settings more structured. (Learn more about how to keep your vimrc clean in Appendix B, Vim Configuration Alternatives). The gvimrc file is a configuration file specifically for Gvim. It resembles the vimrc file previously described, and is placed in the same location as a personal version as well as a global version. For example: Linux: /home/kim/.gvimrc and /usr/share/vim/gvimrc Windows: c:documents and settingskim_gvimrc and c:program filesvimgvimrc This file is used for GUI-specific settings that only Gvim will be able to use. In the rest of the article, this file is called gvimrc. The gvimrc file does not replace the vimrc file, but is simply used for configurationsthat only apply to the GUI version of Vim. In other words, there is no need to haveyour configurations duplicated in both the vimrc file and the gvimrc file. The exrc file is a configuration file that is only used for backwards compatibility with the old vi / ex editor. It is placed at the same location (both global and local) as vimrc, and is used the same way. However, it is hardly used anymore except if you want to use Vim in a vi-compatible mode. Changing the fonts In regular Vim, there is not much to do when it comes to changing the font because the font follows one of the terminals. In Gvim, however, you are given the ability to change the font as much as you like. The main command for changing the font in Linux is: :set guifont=Courier 14 Here, Courier can be exchanged with the name of any font that you have, and 14 with any font size you like (size in points—pt). For changing the font in Windows, use the following command: :set guifont=Courier:14 If you are not sure about whether a particular font is available on the computer or not, you can add another font at the end of the command by adding a comma between the two fonts. For example: :set guifont=Courier New 12, Arial 10 If the font name contains a whitespace or a comma, you will need to escape it with a backslash. For example: :set guifont=Courier New 12 This command sets the font to Courier New size 12, but only for this session. If you want to have this font every time you edit a file, the same command has to be added to your gvimrc file (without the : in front of set). In Gvim on Windows, Linux (using GTK+), Mac OS, or Photon, you can get a font selection window shown if you use this command: :set guifont=*. If you tend to use a lot of different fonts depending on what you are currently working with (code, text, logfiles, and so on.), you can set up Vim to use the correct font according to the file type. For example, if you want to set the font to Arial size 12 every time a normal text file (.txt) is opened, this can be achieved by adding the following line to your vimrc file: autocmd BufEnter *.txt set guifont=Arial 12 The window of Gvim will resize itself every time the font is changed. This means, if you use a smaller font, you will also (as a default) have a smaller window. You will notice this right away if you add several different file type commands like the one previously mentioned, and then open some files of different types. Whenever you switch to a buffer with another file type, the font will change, and hence the window size too. You can find more information about changing fonts in the Vim help system under Help | guifont. Changing color scheme Often, when working in a console environment, you only have a black background and white text in the foreground. This is, however, both dull and dark to look at. Some colors would be desirable. As a default, you have the same colors in the console Vim as in the console you opened it from. However, Vim has given its users the opportunity to change the colors it uses. This is mostly done with a color scheme file. These files are usually placed in a directory called colors wherever you have installed Vim. You can easily change the installed color schemes with the command: :colorscheme mycolors Here, mycolors is the name of one of the installed color schemes. If you don't know the names of the installed color schemes, you can place the cursor after writing: :colorscheme Now, you can browse through the names by pressing the Tab key. When you find the color scheme you want, you can press the Enter key to apply it. The color scheme not only applies to the foreground and background color, but also to the way code is highlighted, how errors are marked, and other visual markings in the text. You will find that some color schemes are very alike and only minor things have changed. The reason for this is that the color schemes are user supplied. If some user did not like one of the color settings in a scheme, he or she could just change that single setting and re-release the color scheme under a different name. Play around with the different color schemes and find the one you like. Now, test it in the situations where you would normally use it and see if you still like all the color settings. While learning Basic Vim Scripting, we will get back to how you can change a color scheme to fit your needs perfectly. Personal highlighting In Vim, the feature of highlighting things is called matching. With matching, you can make Vim mark almost any combination of letters, words, numbers, sentences, and lines. You can even select how it should be marked (errors in red, important words in green, and so on). Matching is done with the following command: :match Group /pattern/ The command has two arguments. The first one is the name of the color group that you will use in the highlight. Compared to a color scheme, which affects the entire color setup, a color group is a rather small combination of background (or foreground) colors that you can use for things such as matches. When Vim is started, a wide range of color groups are set to default colors, depending on the color scheme you have selected. To see a complete list of color groups, use the command: :so $VIMRUNTIME/syntax/hitest.vim. The second argument is the actual pattern you want to match. This pattern is a regular expression and can vary from being very simple to extremely complex, depending on what you want to match. A simple example of the match command in use would be: :match ErrorMsg /^Error/ This command looks for the word Error (marked with a ^) at the beginning of all lines. If a match is found, it will be marked with the colors in the ErrorMsg color group (typically white text on red background). If you don't like any of the available color groups, you can always define your own. The command to do this is as follows: :highlight MyGroup ctermbg=red guibg=red gctermfg=yellowguifg=yellow term=bold This command creates a color group called MyGroup with a red background and yellow text, in both the console (Vim) and the GUI (Gvim). You can change the following options according to your preferences: ctermb Background color in console guibg Background color in Gvim ctermf Text color in console guifg Text color in Gvim gui Font formatting in Gvim term Font formatting in console (for example, bold) If you use the name of an existing color group, you will alter that group for the rest of the session. When using the match command, the given pattern will be matched until you perform a new match or execute the following command: :match NONE The match command can only match one pattern at a time, so Vim has provided you with two extra commands to match up to three patterns at a time. The commands are easy to remember because their names resemble those of the match command: :2match:3match You might wonder what all this matching is good for, as it can often seem quite useless. Here are a few examples to show the strength of matching. Example 1: Mark color characters after a certain column In mails, it is a common rule that you do not write lines more than 74 characters (a rule that also applies to some older programming languages such as, Fortran-77). In a case like this, it would be nice if Vim could warn you when you reached this specific number of characters. This can simply be done with the following command: :match ErrorMsg /%>73v.+/ Here, every character after the 73rd character will be marked as an error. This match is a regular expression that when broken down consists of: %> Match after column with the number right after this 73 The column number V Tells that it should work on virtual columns only .+ Match one or more of any character Example 2: Mark tabs not used for indentation in code When coding, it is generally a good rule of thumb to use tabs only to indent code, and not anywhere else. However, for some it can be hard to obey this rule. Now, with the help of a simple match command, this can easily be prevented. The following command will mark any tabs that are not at the beginning of the line (indentation) as an error: :match errorMsg /[^t]zst+/ Now, you can check if you have forgotten the rule and used the Tab key inside the code. Broken down, the match consists of the following parts: [^ Begin a group of characters that should not be matched t The tab character ] End of the character group zs A zero-width match that places the 'matching' at the beginning of the line ignoring any whitespaces t+ One or more tabs in a row This command says: Don't match all the tab characters; match only the ones that are not used at the beginning of the line (ignoring any whitespaces around it). If instead of using tabs you want to use the space character for indentation, you can change the command to: :match errorMsg /[t]/ This command just says: Match all the tab characters. Example 3: Preventing errors caused by IP addresses If you write a lot of IP addresses in your text, sometimes you tend to enter a wrong value in one (such as 123.123.123.256). To prevent this kind of an error, you can add the following match to your vimrc file: match errorMsg /(2[5][6-9]|2[6-9][0-9]|[3-9][0-9][0-9])[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}|[0-9]{1,3}[.](2[5][6-9]|2[6-9][0-9]| [3-9][0-9][0-9])[.][0-9]{1,3}[.][0-9]{1,3}|[0-9]{1,3}[.][0-9]{1,3}[.](2[5] [6-9]|2[6-9][0-9]|[3-9][0-9][0-9])[.][0-9]{1,3}|[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.](2[5][6-9]|2[6-9][0-9]|[3-9][0-9][0-9])/ Even though this seems a bit too complex for solving a small possible error, you have to remember that even if it helps you just once, it is worth adding. If you want to match valid IP addresses, you can use this, which is a much simpler command: match todo /((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).) {3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/
Read more
  • 0
  • 0
  • 6786

article-image-manage-your-money-simple-invoices
Packt
13 May 2010
6 min read
Save for later

Manage Your Money with Simple Invoices

Packt
13 May 2010
6 min read
As a freelancer I have one primitive motive. I want to do work and get paid. Getting paid means I need to generate invoices and keep track of them. I've tried to manage my invoices via spreadsheets and documents, but keeping track of my payments in a series of disconnected files is a fragile and inefficient process. Simple Invoices provides a solution to this. Simple Invoices is a relatively young project, and working with it requires that you're willing to do some manual configurations and tolerate the occasional problem. To work with and install the application, you need to be familiar with running a web server on OS X, Windows, or Linux. The next section, Web Server Required provides some out of the box server packages that allow you to run a server environment on your personal computer. It's point and click easy and perfect for an individual user. Not up for running a web server, but still need to find a reliable invoicing application? No problem. Visit www.simpleinvoices.com for a list of hosted solutions. Let's get started. Web Server Required Simple Invoices is a web application that requires Apache, PHP, and MySQL to function. Even if you're not a system administrator, you can still run a web server on your computer, regardless of your operating system. Windows users can get the required software by installing WAMP from www.wampserver.com. OS X users can install MAMP from www.mamp.info. Linux users can install Apache, MySql, and PHP5 using their distribution's software repositories. The database administrative tool, phpMyAdmin makes managing the MySQL database intuitive. Both the WAMP and MAMP installers contain phpMyAdmin, and we'll use it to setup our databases. Take a moment to setup your web server before continuing with the Simple Invoices installation. Install Simple Invoices Our first step will be to prepare the MySQL database. Open a web browser and navigate to http://localhost/phpmyadmin. Replace localhost with the actual server address. A login screen will display and will prompt you for a user name and password. Enter the the root login information for your MySQL install. MAMP users might try root for both the user name and password. WAMP users might try root with no password. If you plan on keeping your WAMP or MAMP servers installed, setting new root passwords for your MySQL database is a good idea, even if you do not allow external connections to your server. After you log in to phpMyAdmin, you will see a list of databases on the left sidebar; the main content window displays a set of tabs, including Databases, SQL, and Status. Let's create the database. Click on the Privileges tab to display a list of all users and associated access permissions. Find the Add a New User link and click on it. The Add New User page displays. Complete the following fields: User Name: enter simpleinvoices Host: select Local Password: specify a password for the user; then retype it in the field provided Database for User: select the Create database with same name and grant all privileges option Scroll to the bottom of the page and click the Go button. This procedure creates the database user and the database at the same time. If you wanted to use a database name that was different than the user name, then could have selected None for the Database for user configuration and added the database manually via the Databases tab in phpMyAdmin. If you prefer to work with MySQL directly, the SQL code for the steps we just ran is (the *** in the first line is the password): CREATE USER 'simpleinvoices'@'localhost' IDENTIFIED BY '***'; GRANT USAGE ON *.* TO 'simpleinvoices'@'localhost' IDENTIFIED BY '***' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0;CREATE DATABASE IF NOT EXISTS `simpleinvoices`; GRANT ALL PRIVILEGES ON `simpleinvoices`.* TO 'simpleinvoices'@'localhost'; Now that the database is setup, let's download the stable version of Simple Invoices by visiting www.simpleinvoices.org and following the Download link. The versions are identified by the year and version. At the time of this writing, the stable version is 2010.1. Unzip the Simple Invoices download file into a subdirectory on your web server. Because I like to install a lot of software, I like to keep the application name in my directory structure, so my example installation installs to a directory named simpleinvoices. That makes my installation available at http://localhost/simpleinvoices. Pick a directory path that makes sense for you. Not sure where the root of your web server resides on your server? Here are some of the default locations for the various server environments: WAMP – C:wampwww MAMP – /Applications/MAMP/htdocs Linux – /var/www Linux users will need to set the ownership of the tmp directory to the web user and make the tmp directory writable. For an Ubuntu system, the appropriate commands are: chown -R www-data tmpchmod -R 775 tmp The command syntax assumes we're working from the Simple Invoices installation directory on the web server. The web user on Ubuntu and other Debian-based systems is www-data. The -R option in both commands applies the permissions to all sub-directories and files. With the chmod command, you are granting write access to the web user. If you have problems or feel like being less secure, you can reduce this step down to one command: chmod -R 777 tmp. We're almost ready to open the Simple Invoices installer, but before we go to the web browser, we need to define the database connections in the config/config.ini file. At a minimum, we need to specify the database.params.username and database.params.password with the values we used to setup the database. If you skip this step and try to open Simple Invoices in your web browser, you will receive an error message indicating that your config.ini settings are incorrect. The following screenshot shows the relevant settings in confi.ini. Now, we're ready to start Simple Invoices and step through the graphical installer. Open a web browser and navigate to your installation (for example: http://localhost/simpleinvoices). Step 1: Install Database will display in the browser. Review the database connection information and click the Install Database button. Step 2: Import essential data displays. Click the Install Essential Data button to advance the installation. Step 3: Import sample data displays. We can choose to import sample data or start using the application. The sample data contains a few example billers, customers, and invoices. We're going to set all that up from scratch, so I recommend you click the Start using Simple Invoices button. At this point the Simple Invoices dashboard displays with a yellow note that instructs us to configure a biller, a customer, and a product before we create our first invoice. See the following screenshot. You might notice that the default access to Simple Invoices is not protected by a username and password. We can force authentication by adding a user and password via the People > Users screen. Then set the authentication.enabled field in config.ini equal to true.
Read more
  • 0
  • 0
  • 3024

article-image-creating-new-publication-using-mobile-database-workbench-oracle-mobile-server
Packt
13 May 2010
8 min read
Save for later

Creating a New Publication using Mobile Database Workbench with Oracle Mobile Server

Packt
13 May 2010
8 min read
If you are a mobile device user, it is likely that you would have performed a sync at one point in time (with or without being aware of it). We are all familiar with the convenience of being able to just dock our PDA devices and have our calendars, tasks, and contacts automatically synced to our desktop machines. The synchronization process is a necessity for any type of mobile device, whether it's a Smart Phone, iPhone, or a Pocket PC. The core of this necessity is simple—people need to have access to their data when they're on the move and when they're back at the office, and this data needs to be consistent—wherever they're accessing it from. In a business scenario, the importance of this necessity increases manifold—it's not just about your personal data anymore. The data you've keyed in on your PDA needs to be synced to the server so that it can be shared with other users, used to generate reports, or even sent for number-crunching. With hundreds of mobile users synchronizing their data and server-side applications updating this data at the same time, things can quickly get messy. The synchronization process has to ensure that conflicts are gracefully handled, auto-generated numbers don't overlap, that each user only syncs down the data they're meant to see, and so on. The Oracle Mobile Server can be a bit tedious to set up for first time beginners. Once you get going, however, it can be a powerful tool that can manage not only database synchronization but also mobile application deployment. A publication represents an application (and its database) in the Oracle mobile server. You can create a publication through the Mobile Database Workbench tool provided with Oracle Mobile Server. Creating a new mobile project Launch the Mobile Database Workbench tool from Start | All Programs | Oracle Database Lite 10g | Mobile Database Workbench. Create a new project by clicking on the File | New | Project menu item in the Mobile Database Workbench window. A project creation wizard will run. Specify a name for your project and a location to store the project files. The next screen will request you to key in mobile repository particulars. Specify your mobile repository connection settings, and use the mobile server administrator password you specified earlier to log in. In the next step, specify a schema to use for the application. As you've created the master tables in the MASTER schema, you can specify your MASTER account username and password here. The next screen will show a summary of what you've configured so far. Click the Finish button to generate the project. If your project is generated successfully, you should be able to see your project and a tree list of its components in the left pane. Adding publication items to your project Each publication item corresponds to a database table that you intend to publish. For example, if your application contained five tables, you will need to create five publication items. Let's create the publication items now for the Accounts, AccountTasks, AccountHistories, AccountFiles, and Products tables. Click on the File | New | Publication Item menu item to launch the Publication Item wizard. In the first step of the wizard, specify a name for the publication item (use the table name as a rule of thumb). There are two options here worth noting: Synchronization refresh type This refers to the type of refresh used for a particular table: Fast: This is a type of incremental refresh—only the changes are synced down from the server during a sync. This is the most common mode of refresh used. Complete: In this type of refresh, all content is synced down from the server during each sync. It is comparatively more time consuming and resource intensive. You might use this option with tables containing small lists of data that change very frequently. Queue based: This is a custom refresh in that the developer can define the entire logic for the sync. It can be used for custom scenarios that may not exactly require synchronization—for instance you might need to simply collect data on the client and have it stored at the server. In such a case, the queue-based refresh works better because you can bypass the overhead of conflict detection. Enable automatic synchronization Automatic synchronization allows a sync to be initiated automatical-ly in the background of the mobile device when a set of rules are met. For example, you might decide to use automatic synchronization if you wanted to spread out synchronization load over time and reduce peak-out on the server. In the next step, choose the table that you want to map the publication item to. Select the MASTER schema, and click the Search button to retrieve a list of the tables under this schema. Locate the Accounts table and highlight it. In the next screen, you will need to select all the columns you need from the Accounts table. As you need to sync every single column from the snapshot to the master table, include all columns. Move all columns from the Available list to the Selected list using the arrow buttons and click on the Next button to proceed. The next step is one of the most important steps in creating a publication item. The SQL statement shown here basically defines how data is retrieved from the Accounts table at the server and synced down to the snapshot on the mobile device. This SQL statement is called the Publication Item Query. The first obvious thing you need to do is to edit the default query. You need to include a filter to sync down only the accounts owned by the specific mobile device user. You can easily use a filter that looks like the following: WHERE OwnerID = :OwnerID The following screenshot shows how your Publication Item Query will look after editing. If any part of it is defined or formatted incorrectly, you will receive a notification. Click on Next after that to get to the summary screen, then click on the Finish button to generate the publication item. After creating the publication item for the Accounts table, let's move on to a child table—the AccountTasks table. Create another publication item in the same fashion that maps to the AccountTasks table. At Step 4 of the wizard, the Publication Item Query that you need to specify will be a little bit different. The AccountTasks table does not contain the OwnerID field, so how do we filter what gets synced down to each specific mobile device. You obviously don't want to sync down every single record in this table—including those that are not meant to be accessible by the specific mobile device user. One way to still apply the OwnerID filter is to use a table join with the Accounts table. You can easily specify a table join in the following manner: SELECT "TASKID", A."ACCOUNTGUID", "TASKSUBJECT", "TASKDESCRIPTION", "TASKCREATED", "TASKDATE", "TASKSTATUS" FROM MASTER.ACCOUNTTASKS A, MASTER.ACCOUNTS B WHERE A.ACCOUNTGUID=B.ACCOUNTGUID AND B.OWNERID = :OwnerID If you try to save the Publication Item Query above in the Edit Query box, it may prompt you to select the primary base object for the publication item (as shown in the following screenshot). This should be set to AccountTasks because we are creating a publication item that maps to this table. If you choose the Accounts table again, you will end up with two publication items that map to the same Accounts table. This will cause problems when you attempt to add both items to a publication. If you have typed in everything correctly, you will be able to see your Publication Item Query show up in the Query tab shown as follows. You can then click on the Next and Finish buttons to complete the wizard. Now that you've seen how to create a publication item based on a child table, repeat the same steps above for the other child tables – AccountFiles and AccountHistories. The last table—the Products table deserves a special mention because it's different. You do not need a filter for this table, simply because every mobile device user will need to see the full list of products. You can, therefore, use the default Publication Item Query for the Products table: SELECT "PRODUCTID", "PRODUCTCODE", "PRODUCTNAME", "PRODUCTPRICE" FROM MASTER.Products After you've done this, you can now move on to creating the "sequences" necessary in this mobile application.
Read more
  • 0
  • 0
  • 1757
article-image-introduction-flash-builder-4-network-monitor
Packt
13 May 2010
3 min read
Save for later

An Introduction to Flash Builder 4-Network Monitor

Packt
13 May 2010
3 min read
Adobe Flash Builder 4 (formally known as Adobe Flex Builder), which no doubt needs no words of introduction, has become a de-facto standard in rich internet applications development. Latest version is considered as a ground breaking release not only for its dozens of new and enhanced features but also for its new-fangled component architectures like Spark, designer-developer workflow, integration with flash and catalyst, Data centric development, Unit testing, Debugging enhancements etc. In this article, we’ll get acquainted with a brand new premium feature of Adobe Flash Builder 4 called Network Monitor. Network Monitor enables developers to inspect and monitor client-server traffic in the form of textual, XML, AMF, or JSON data within the Adobe Flash Builder 4. It shows real-time data-traffic between application and a local or remote server along with wealth of other related information about the transferred data such as status, size, body etc. If you have used FireBug (A firefox plugin), then you will appreciate Network Monitor too. It is extremely handy during HTTP errors to check the response which is not accessible from the fault event object. Creating a Sample Application Enough Talking lets start and create a very simple application which will serve as groundwork to explore Network Monitor. Assuming you are already equipped with basic knowledge of application creation, we will move on quickly without going through minor details. This sample application will read the PackPublishing Official RSS feed and display every news title along with its publishing date in a DataGrid control. Network monitor will set forth into action when data request will be triggered. Go to File Menu, Select New > Flex Project. Insert information in the New Flex Project dialog box according to following screenshot and hit Enter. In Flex 4, all the non-visual mxml components such as RPC components, effects, validators, formatters etc are declared inside <fx:Declarations> tag. Declare a HTTPService component inside <fx:Declarations> tag. Set its id property to newsService Set its url property to https://www.packtpub.com/rss.xml Set its showBusyCursor property to true and resultFormat property to e4x. Generate result and fault event handlers, though only result event handler will be used. Your HTTPService code should look like following <s:HTTPService id="newsService" url="https://www.packtpub.com/rss.xml" showBusyCursor="true" resultFormat="e4x" result="newsService_resultHandler(event)" fault="newsService_faultHandler(event)"/> Now set the application layout to VerticalLayout <s:layout> <s:VerticalLayout verticalAlign="middle" horizontalAlign="center"/> </s:layout> Add a Label control and set its text property to Packt Publishing Add a DataGrid control, set its id property to dataGrid, and add two DataGridColumn in it. Set first column’s dataField property to title and headerText to Title Set second column’s dataField property to pubDate and headerText to Date Your controls should look like as following <s:Label text="Packt Publishing" fontWeight="bold" fontSize="22"/> <mx:DataGrid id="dataGrid" width="600"> <mx:columns> <mx:DataGridColumn dataField="title" headerText="Title"/> <mx:DataGridColumn dataField="pubDate" width="200" headerText="Date"/> </mx:columns> </mx:DataGrid> Finally add following code in newsService’s result handler. var xml:XML = XML(event.result); dataGrid.dataProvider = xml..item;
Read more
  • 0
  • 0
  • 2391

article-image-data-binding-expression-blend-4-silverlight-4
Packt
13 May 2010
7 min read
Save for later

Data binding from Expression Blend 4 in Silverlight 4

Packt
13 May 2010
7 min read
Using the different modes of data binding to allow persisting data Until now, the data has flowed from the source to the target (the UI controls). However, it can also flow in the opposite direction, that is, from the target towards the source. This way, not only can data binding help us in displaying data, but also in persisting data. The direction of the flow of data in a data binding scenario is controlled by the Mode property of the Binding. In this recipe, we'll look at an example that uses all the Mode options and in one go, we'll push the data that we enter ourselves to the source. Getting ready This recipe builds on the code that was created in the previous recipes, so if you're following along, you can keep using that codebase. You can also follow this recipe from the provided start solution. It can be found in the Chapter02/SilverlightBanking_Binding_ Modes_Starter folder in the code bundle that is available on the Packt website. The Chapter02/SilverlightBanking_Binding_Modes_Completed folder contains the finished application of this recipe. How to do it... In this recipe, we'll build the "edit details" window of the Owner class. On this window, part of the data is editable, while some isn't. The editable data will be bound using a TwoWay binding, whereas the non-editable data is bound using a OneTime binding. The Current balance of the account is also shown—which uses the automatic synchronization—based on the INotifyPropertyChanged interface implementation. This is achieved using OneWay binding. The following is a screenshot of the details screen: Let's go through the required steps to work with the different binding modes: Add a new Silverlight child window called OwnerDetailsEdit.xaml to the Silverlight project. In the code-behind of this window, change the default constructor—so that it accepts an instance of the Owner class—as shown in the following code: private Owner owner; public OwnerDetailsEdit(Owner owner) { InitializeComponent(); this.owner = owner; } In MainPage.xaml, add a Click event on the OwnerDetailsEditButton: <Button x_Name="OwnerDetailsEditButton" Click="OwnerDetailsEditButton_Click" > In the event handler, add the following code, which will create a new instance of the OwnerDetailsEdit window, passing in the created Owner instance: private void OwnerDetailsEditButton_Click(object sender, RoutedEventArgs e) { OwnerDetailsEdit ownerDetailsEdit = new OwnerDetailsEdit(owner); ownerDetailsEdit.Show(); } The XAML of the OwnerDetailsEdit is pretty simple. Take a look at the completed solution (Chapter02/SilverlightBanking_Binding_Modes_Completed)for a complete listing. Don't forget to set the passed Owner instance as the DataContext for the OwnerDetailsGrid. This is shown in the following code: OwnerDetailsGrid.DataContext = owner; For the OneWay and TwoWay bindings to work, the object to which we are binding should be an instance of a class that implements the INotifyPropertyChanged interface. In our case, we are binding an Owner instance. This instance implements the interface correctly. The following code illustrates this: public class Owner : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; ... } Some of the data may not be updated on this screen and it will never change. For this type of binding, the Mode can be set to OneTime. This is the case for the OwnerId field. The users should neither be able to change their ID nor should the value of this field change in the background, thereby requiring an update in the UI. The following is the XAML code for this binding: <TextBlock x_Name="OwnerIdValueTextBlock" Text="{Binding OwnerId, Mode=OneTime}" > </TextBlock> The CurrentBalance TextBlock at the bottom does not need to be editable by the user (allowing a user to change his or her account balance might not be benefi cial for the bank), but it does need to change when the source changes. This is the automatic synchronization working for us and it is achieved by setting the Binding to Mode=OneWay. This is shown in the following code: <TextBlock x_Name="CurrentBalanceValueTextBlock" Text="{Binding CurrentBalance, Mode=OneWay}" > </TextBlock> The final option for the Mode property is TwoWay. TwoWay bindings allow us to persist data by pushing data from the UI control to the source object. In this case, all other fields can be updated by the user. When we enter a new value, the bound Owner instance is changed. TwoWay bindings are illustrated using the following code: <TextBox x_Name="FirstNameValueTextBlock" Text="{Binding FirstName, Mode=TwoWay}" > </TextBox> We've applied all the different binding modes at this point. Notice that when you change the values in the pop-up window, the details on the left of the screen are also updated. This is because all controls are in the background bound to the same source object as shown in the following screenshot: How it works... When we looked at the basics of data binding, we saw that a binding always occurs between a source and a target. The first one is normally an in-memory object, but it can also be a UI control. The second one will always be a UI control. Normally, data flows from source to target. However, using the Mode property, we have the option to control this. A OneTime binding should be the default for data that does not change when displayed to the user. When using this mode, the data flows from source to target. The target receives the value initially during loading and the data displayed in the target will never change. Quite logically, even if a OneTime binding is used for a TextBox, changes done to the data by the user will not flow back to the source. IDs are a good example of using OneTime bindings. Also, when building a catalogue application, OneTime bindings can be used, as we won't change the price of the items that are displayed to the user (or should we...?). We should use a OneWay binding for binding scenarios in which we want an up-to-date display of data. Data will flow from source to target here also, but every change in the values of the source properties will propagate to a change of the displayed values. Think of a stock market application where updates are happening every second. We need to push the updates to the UI of the application. The TwoWay bindings can help in persisting data. The data can now flow from source to target, and vice versa. Initially, the values of the source properties will be loaded in the properties of the controls. When we interact with these values (type in a textbox, drag a slider, and so on), these updates are pushed back to the source object. If needed, conversions can be done in both directions. There is one important requirement for the OneWay and TwoWay bindings. If we want to display up-to-date values, then the INotifyPropertyChanged interface should be implemented. The OneTime and OneWay bindings would have the same effect, even if this interface is not implemented on the source. The TwoWay bindings would still send the updated values if the interface was not implemented; however, they wouldn't notify about the changed values. It can be considered as a good practice to implement the interface, unless there is no chance that the updates of the data would be displayed somewhere in the application. The overhead created by the implementation is minimal. There's more... Another option in the binding is the UpdateSourceTrigger. It allows us to specify when a TwoWay binding will push the data to the source. By default, this is determined by the control. For a TextBox, this is done on the LostFocus event; and for most other controls, it's done on the PropertyChanged event. The value can also be set to Explicit. This means that we can manually trigger the update of the source. BindingExpression expression = this.FirstNameValueTextBlock. GetBindingExpression(TextBox.TextProperty); expression.UpdateSource(); See also Changing the values that flow between source and target can be done using converters. Data binding from Expression Blend 4 While creating data bindings is probably a task mainly reserved for the developer(s) in the team, Blend 4—the design tool for Silverlight applications—also has strong support for creating and using bindings. In this recipe, we'll build a small data-driven application that uses data binding. We won't manually create the data binding expressions; we'll use Blend 4 for this task.
Read more
  • 0
  • 0
  • 5475
Modal Close icon
Modal Close icon