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

7019 Articles
article-image-troubleshooting-freenas-server
Packt
28 Oct 2009
9 min read
Save for later

Troubleshooting FreeNAS server

Packt
28 Oct 2009
9 min read
Where to Look for Log Information The first place to head whenever you have a configuration problem with FreeNAS is to the related configuration section and check that it is configured as expected. If, having double checked the settings, the problem persists, the next port of call is the log and information files in the Diagnostics: section of the web interface. Keep Diagnostics Section ExpandedBy default, the menu tree in the Diagnostics section of the web interface is collapsed, meaning the menu items aren't visible. To see the menu items, you need to click the word Diagnostics and the tree will expand. During initial setup and if you are doing lots of troubleshooting, you can save yourself a click by having the Diagnostics section permanently expanded. To set this option, go to System: Advanced and click on the Navigation - Keep diagnostics in navigation expanded tick box. The Diagnostics sections has five sections, the first two are logs and information pages about the status of the FreeNAS server. The other three are networking diagnostic tools and information. Diagnostics: Logs This section collates all the different log files that are generated by the FreeNAS server into one convenient place. There are several tabs, one for each different service to log file type. Some of the information can be very technical, especially in the System tab. However, with some key information they can become more readable. The tabs are as follows: Tab Meaning System When FreeBSD (the underlying OS of FreeNAS) boots, various log entries are recorded here about the hardware of the server and various messages about the boot process. FTP This shows the activity on the FTP server including successful logins and failed logins. RSYNC The log information for the RSYNC server is divided into three sections: Server, Client, and Local. Depending on which type of RSYNC operation you are interested, click the appropriate tab. SSHD Here you will find log entries from the SSH server including some limited startup information and records of logins and failed login attempts. SMARTD This tab logs the output of the S.M.A.R.T daemon. Daemon Any other minor system service like the built-in HTTP server, the Apple Filing Protocol server and Windows networking server (Samab) will log information to this page. UPnP The log information from the FreeNAS UPnP server called "MediaTomb" is displayed here. The logging can be quite verbose so careful attention is needed when reading it. Don't be distracted by entires such as "INFO: Config: option not found:" as this is just the server logging that it will be using a default value for that particular attribute. Settings The settings tab allows you to change how the log information is displayed including the sort order and the number of entries shown. What is a Daemon?In UNIX speak, a Daemon is a system service. It is a program that runs in the background performing certain tasks. The Daemons in FreeNAS don't work with the users in an interactive mode (via the monitor, mouse, and keyboard) and as such need a place to log the results (or problems)of their actives. The FreeNAS Daemons are launched automatically by FreeBSD when it boots and some are dependent on being enabled in the web interface. Understanding Diagnostics Logs: System The most complicated of all the log pages is the System log page. Here, FreeBSD logs information about the system, its hardware, and the startup process. At first, this page can seem intimidating but with a little help, this page can be very helpful particularly in tracking down hardware or driver related problems. 50 Log Entries Might Not be EnoughThe default number of log entries shown on the Diagnostics: Logs page is 50. For most situations, this will be sufficient but there can be times when it is not enough. For example in the Diagnostics: Logs: System tab, the total number of log entries made during the boot up process is more than 50. If you want to see how much system memory has been recognized by FreeBSD, you won't find it within the standard 50 entries. The solution is to increase the Number of log entries to show parameter on the Diagnostics: Logs: Setting tab. The best way to learn to read the Diagnostics: Logs: System page is by example, below are several different log entry examples including logs about the CPU, memory, disks, and disk controllers: kernel: FreeBSD 6.2-RELEASE-p11 #0: Wed Mar 12 18:17:49 CET 2008 This first entry shows the heritage of the FreeNAS server. It is based on FreeBSD and in this particular case, we see that this version of FreeNAS is using FreeBSD 6.2. There are plans (which may have already become reality) to use FreeBSD version 7.0 as the base for FreeNAS. kernel: CPU: Intel(R) Xeon(TM) CPU 1.70GHz (1680.52-MHz 686-class CPU) Here, the type of CPU that was detected by the FreeBSD is displayed. In this case, it is an Intel Xeon CPU running at 1.7GHz. kernel: FreeBSD/SMP: Multiprocessor System Detected: 2 CPUs If your system has more than one CPU or is a dual core machine then you will see an entry in the log file (like the one above) recognizing the second CPU. If your machine has Hyper-threading technology, then the second logical processor will be reported like this: Logical CPUs per core:2 Apr 1 11:06:00 kernel: real memory = 268435456 (256 MB)Apr 1 11:06:00 kernel: avail memory = 252907520 (241 MB) These log entries show how much memory the system has detected. The difference in size between real memory and available memory is the difference between the amount of RAM physically installed in the computer and the amount of memory left over after the FreeBSD kernel is loaded. kernel: atapci0: <Intel PIIX4 UDMA33 controller> port 0x1f0-0x1f7,0x3f6,0x170-0x177,0x376,0x1050-0x105f at device 7.1 on pci0 kernel: ata0: <ATA channel 0> on atapci0 kernel: ata1: <ATA channel 1> on atapci0 For disks to work on your FreeNAS server, a disk controller is needed and it will be either a standard ATA/IDE controller, a SATA controller or a SCSI controller. Above are the log entries for a standard ATA controller built into the motherboard. You can see that it is an Intel controller and that two channels have been seen (the primary and the secondary). kernel: atapci1: <SiS 181 SATA150 controller> irq 17 at device 5.0 on pci0kernel: ata2: <ATA channel 0> on atapci1kernel: ata3: <ATA channel 1> on atapci1 Like the ATA controller listed a moment ago, SATA controllers are all recognized at boot up. Here is a SiS 181 SATA 150 controller with two channels. They are listed as devices ata2 and ata3 as ata0 and ata1 are used by the standard ATA/IDE controller. kernel: mpt0: <LSILogic 1030 Ultra4 Adapter> irq 17 at device 16.0 on pci0 Like IDE and SATA controllers, all recognized SCSI drivers are listed in the boot up system log. Here, the controller is an LSILogic 1030 Ultra4. kernel: ad0: 476940MB <WDC WD5000AAJB-00YRA0 12.01C02> at ata0-master UDMA100kernel: ad4: 476940MB <Seagate ST3500320AS SD04> at ata2-master SATA150 Once the disk controllers are recognized by the system, FreeBSD can search to see which disks are attached. Above is an example of a Western Digital 500GB hard drive using the standard ATA100 interface at 100MB/s. There is also a 500GB Seagate drive connected using the SATA interface. acd0: CDROM <TOSHIBA CD-ROM XM-7002B/1005> at ata1 as master UDMA33 When the CDROM (which is normally attached to an ATA/IDE controller) is recognized, it will look like the above. kernel: da0 at ahd0 bus 0 target 0 lun 0kernel: da0: <MAXTOR ATLAS10K4_73WLS DFL0> Fixed Direct Access SCSI-3 devicekernel: da0: 320.000MB/s transfers (160.000MHz, offset 127, 16bit), Tagged Queueing Enabledkernel: da0: 70149MB (143666192 512 byte sectors: 255H 63S/T 8942C) SCSI addressing is a little more complicated than that of ATA/IDE. In SCSI land, you have a controller, a channel (bus), a disk (target), and the Logical Unit Number (LUN). The example above shows that a disk (which has been assigned the device name da0) is found on the controller ahd0 on bus 0, as target 0 with the LUN 0. SCSI controllers can have multiple buses and multiple targets. Further down, you can see that the disk is a MAXTOR 73GB SCSI-3 disk. kernel: da0 at umass-sim0 bus 0 target 0 lun 0kernel: da0: <Verbatim Store 'n' Go 1.30> Removable Direct Access SCSI-2 devicekernel: da0: 40.000MB/s transferskernel: da0: 963MB (1974271 512 byte sectors: 64H 32S/T 963C) If you are using a USB flash disk for storing the configuration information, it will most likely appear in the log file as a type of SCSI disk. The above example shows a 1GB Verbatim Store 'n' Go disk. kernel: lnc0: <PCNet/PCI Ethernet adapter> irq 18 at device 17.0 on pci0kernel: lnc0: Ethernet address: 00:0c:29:a5:9a:28 Another important device that needs to work correctly on your system is the network interface card. Like disk controllers and disks, it will be logged in the log file when FreeBSD recognizes it. Above is an example of an AMD Lance/PCNet-based Ethernet adapter. Each Ethernet card has a unique address know as the Ethernet address or the MAC address. It is made up of 6 numbers specified using a colon notation. Once found, FreeBSD queries the card to find its MAC address and logs the result. In the above example, it is "00:0c:29:a5:9a:28". Converting between Device Names and the Real World In the SCSI example above, the SCSI controller listed is ahd0. The trick to understanding these log entries better is to know how to interpret the device name ahd0. First of all ahd0 means it is a device using the ahd driver and it is the first one in the system (with numbering starting from 0). So what is a ahd? The first place to look is further up in the log file. There should be an entry like: kernel: ahd0: <Adaptec 39320 Ultra320 SCSI adapter> irq 11 at device 1.0 on pci2 This shows that the particular device is an Adaptec 39320 SCSI 3 controller. You can also find out more about the the ahd driver (and all FreeBSD drivers) at: http://www.freebsd.org/releases/6.2R/hardware-i386.html Search for ahd and you will find which controllers this driver supports (in this case, they are all controllers from Adaptec. If you click on the link provided, you will be taken to a specific help page about this driver. When FreeNAS moves to FreeBSD 7, then the relevant web page will be: http://www.freebsd.org/releases/7.0R/hardware.html.
Read more
  • 0
  • 0
  • 13837

article-image-real-content-php5-cms-part-3
Packt
27 Oct 2009
8 min read
Save for later

Real Content in PHP5 CMS: Part 3

Packt
27 Oct 2009
8 min read
Administering text items—viewer Generating the XHTML is handled in a separate class, thus implementing the principles of the MVC pattern. The viewer class constructor establishes strings for translation in a way that will allow them to be picked up by gettext, as well as invoking the constructor in the parent class basicAdminHTML, which will provide useful methods and also transfer information such as the page navigation object from the controller object passed as a parameter: class listTextHTML extends basicAdminHTML { public function __construct ($controller) { parent::__construct($controller); $lang_strings = array(T_('Simple Text'),T_('Title'), T_('Byline'),T_('Version'), T_('Publishing'),T_('Published'), T_('Start date'),T_('End date'), T_('Article text'),T_('Metadata'), T_('Keys'),T_('Description'), T_('Hits'),T_('ID')); $this->translations = array_combine( $lang_strings, $lang_strings); } The actual display of a list of text items is then quite simple, involving the creation of a heading first, followed by a loop through the text items, and then some final XHTML including hidden fields that allow for effective navigation. Note that the parent class will have set up $this->optionurl and $this->optionline to help in the construction of links within the component and a hidden variable to identify the component respectively. public function view ($rows) { $mainhtml = $this->listview($rows); echo <<<ALL_HTML $mainhtml <div> <input type="hidden" name="task" value="" /> $this->optionline <input type="hidden" name="boxchecked" value="0" /> <input type="hidden" name="hidemainmenu" value="0" /> </div>ALL_HTML; } The view method does very little, relying on the listview method for most of the work, and only adding hidden fields needed to ensure that navigation and the toolbar will work correctly. Note that the parent class helps us by setting $this->optionline with a hidden input field for the critical option variable needed to ensure the correct component is invoked when the form is submitted. Actual XHTML form tags are created by the CMS framework so that every administrator page is a form. The reason for splitting the page creation in this way will become apparent later, when we look at menu creation. So, moving on to the listview method, we find quite a lot of simple code, which is mainly just a definition of the page in XHTML. The second and third parameters will be set differently from their default values when we come to menu creation. public function listview ($rows, $showlinks=true, $subhead='') { $rowcount = count($rows); $html = <<<ADMIN_HEADER {$this->header($subhead)} <table class="adminlist" width="100%"> <thead> <tr> <th width="3%" class="title"> <input type="checkbox" name="toggle" value="" onclick="checkAll($rowcount);" /> </th> <th> {$this->T_('ID')} </th> <th width="50%" class="title"> {$this->T_('Title')} </th> <th> {$this->T_('Byline')} </th> <th> {$this->T_('Hits')} </th> <th align="left"> {$this->T_('Published')} </th> </tr> </thead> <tbody>ADMIN_HEADER; $i = $k = 0; foreach ($rows as $i=>$row) { if ($showlinks) $title = <<<LINK_TITLE <a href="{$this->optionurl}&amp;task=edit&amp; id=$row->id">$row->title</a>LINK_TITLE; else $title = $row->title; $html .= <<<END_OF_BODY_HTML <tr class="row$k"> <td> {$this->html('idBox', $i, $row->id)} </td> <td align="center"> $row->id </td> <td> $title </td> <td> $row->byline </td> <td align="center"> $row->hits </td> <td align="center"> {$this->html('publishedProcessing', $row, $i )} </td> </tr>END_OF_BODY_HTML; $i++; $k = 1 - $k; } if (0 == $rowcount) $html .= <<<NO_ITEMS_HTML <tr><td colspan="6" class="center"> {$this->T_('No items')} </td></tr>NO_ITEMS_HTML; $html .= <<<END_OF_FINAL_HTML </tbody> </table> {$this->pageNav->getListFooter()}END_OF_FINAL_HTML; return $html; } When it comes to adding a new item or editing an existing one, no looping is required, and the WYSIWYG editor is activated to provide a helpful interface for the administrator who is editing a text item. Note that the use of PHP heredoc allows the XHTML to be written out quite plainly, with the PHP insertions unobtrusive but effective. Actual text for translation is shown in its correct place (in the base language) by using the T_ method that is inherited from aliroBasicHTML via basicAdminHTML. public function edit ($text) { $subhead = $text->id ? 'ID='.$text->id : T_('New'); $editor = aliroEditor::getInstance(); echo <<<EDIT_HTML {$this->header($subhead)} <div id="simpletext1"> <div> <label for="title">{$this->T_('Title')}</label><br /> <input type="text" name="title" id="title" size="80" value="$text->title" /> </div> <div> <label for="byline">{$this->T_('Byline')}</label><br /> <input type="text" name="byline" id="byline" size="80" value="$text->byline" /> </div> <div> <label for="version">{$this->T_('Version')}</label><br /> <input type="text" name="version" id="version" size="80" value="$text->version" /> </div> <div> <label for="article">{$this->T_('Article text')}</label><br /> {$editor->editorAreaText( 'article', $text->article, 'article', 500, 200, 80, 15 )} </div> </div> <div id="simpletext2"> <fieldset> <legend>{$this->T_('Publishing')}</legend> <div> <label for="published">{$this->T_('Published')}</label><br /> <input type="checkbox" name="published" id="published" value="1" {$this->checkedIfTrue($text->published)} /> </div> <div> <label for="publishstart">{$this->T_('Start date')}</label><br /> <input type="text" name="publish_start" id="publishstart" size="20" value="$text->publish_start" /> </div> <div> <label for="publishend">{$this->T_('End date')}</label><br /> <input type="text" name="publish_end" id="publishend" size="20" value="$text->publish_end" /> </div> </fieldset> <fieldset> <legend>{$this->T_('Metadata')}</legend> <div> <label for="metakey">{$this->T_('Keys')}</label><br /> <textarea name="metakey" id="metakey" rows="4" cols="40">$text->metakey</textarea> </div> <div> <label for="metadesc">{$this->T_('Description')}</label><br /> <textarea name="metadesc" id="metadesc" rows="4" cols="40">$text->metadesc</textarea> </div> </fieldset> <input type="hidden" name="task" value="" /> $this->optionline </div> <div id="simpletext3"> <input type="hidden" name="id" value="$text->id" /> <input type="hidden" name="boxchecked" value="0" /> <input type="hidden" name="hidemainmenu" value="0" /> </div>EDIT_HTML; } Finally, there is a common method to deal with the creation of the heading. It uses the addCSS method provided by the parent class to link to a small amount of CSS that is held in a separate file. Although the list of text items defined in the XHTML above is perfectly legitimate as a table, since it really is a tabular structure, the heading would be better built out of other XHTML elements. The only reason for using a table here is that it is one of the features retained from earlier systems for the sake of backwards compatibility: private function header ($subhead='') { $this->addCSS(_ALIRO_ADMIN_DIR.'/components /com_text/admin.text.css'); if ($subhead) $subhead = "<small>[$subhead]</small>"; return <<<HEAD_HTML <table class="adminheading"> <tr> <th class="user"> {$this->T_('Simple Text')} $subhead </th> </tr> </table>HEAD_HTML; } }
Read more
  • 0
  • 0
  • 2309

article-image-data-migration-scenarios-sap-business-one-application-part-2
Packt
27 Oct 2009
7 min read
Save for later

Data Migration Scenarios in SAP Business ONE Application- part 2

Packt
27 Oct 2009
7 min read
Advanced data migration tools: xFusion Studio For our own projects, we have adopted a tool called xFusion. Using this tool, you gain flexibility and are able to reuse migration settings for specific project environments. The tool provides connectivity to directly extract data from applications (including QuickBooks and Peachtree). In addition, it also supports building rules for data profiling, validation, and conversions. For example, our project team participated in the development of the template for the Peachtree interface. We configured the mappings from Peachtree, and connected the data with the right fields in SAP. This was then saved as a migration template. Therefore, it would be easy and straightforward to migrate data from Peachtree to SAP in any future projects. xFusion packs save migration knowledge Based on the concept of establishing templates for migrations, xFusion provides preconfigured templates for the SAP Business ONE application. In xFusion, templates are called xFusion packs. Please note that these preconfigured packs may include master data packs, and also xFusion packs for transaction data. The following xFusion packs are provided for an SAP Business ONE migration: Administration Banking Business partner Finance HR Inventory and production Marketing documents and receipts MRP UDFs Services You can see that the packs are also grouped by business object. For example, you have a group of xFusion packs for inventory and production. You can open the pack and find a group of xFusion files that contain the configuration information. If you open the inventory and production pack, a list of folders will be revealed. Each folder has a set of Excel templates and xFusion fi les (seen in the following screenshot). An xFusion pack essentially incorporates the configuration and data manipulation procedures required to bring data from a source into SAP. The source settings can be saved in xFusion packs so that you can reuse the knowledge with regards to data manipulation and formatting. Data "massaging" using SQL The key for the migration procedure is the capability to do data massaging in order to adjust formats and columns, in a step-by-step manner, based on requirements. Data manipulation is not done programmatically, but rather via a step-by-step process, where each step uses SQL statements to verify and format data. The entire process is represented visually, and thereby documents the steps required. This makes it easy to adjust settings and fine-tune them. The following applications are supported and can, therefore, be used as a source for an SAP migration: (They are existing xFusion packs) SAP Business ONE Sage ACT! SAP SAP BW Peachtree QuickBooks Microsoft Dynamics CRM The following is a list of supported databases: Oracle ODBC MySQL OLE DB SQL Server PostgrSQL Working with xFusion The workflow in xFusion starts when you open an existing xFusion pack, or create a new one. In this example, an xFusion pack for business partner migration was opened. You can see the graphical representation of the migration process in the main window (in the following screenshot). Each icon in the graphic representation represents a data manipulation and formatting step. If you click on an icon, the complete path from the data source to the icon is highlighted. Therefore, you can select the previous steps to adjust the data. The core concept is that you do not directly change the input data, but define rules to convert data from the source format to the target format. If you open an xFusion pack for the SAP Business ONE application, the target is obviously SAP Business ONE. Therefore, you need to enter the privileges and database name so that the pack knows how to access the SAP system. In addition, the source parameters need to be provided. xFusion packs come with example Excel fi les. You need to select the Excel fi les as the relevant source. However, it is important to note that you don't need to use the Excel files. You can use any database, or other source, as long as you adjust the data format using the step-by-step process to represent the same format as provided in Excel. In xFusion. you can use the sample files that come in Excel format. The connection parameters are presented once you double-click on any of the connections listed in the Connections section as follows: It is recommended to click on Test Connection to verify the proper parameters. If all of the connections are right, you can run a migration from the source to the target by right-clicking on an icon and selecting Run Export as shown here: The progress and export is visually documented. This way, you can verify the success. There is also a log file in the directory where the currently utilized xFusion pack resides, as shown in the following screenshot: Tips and recommendations for your own project Now you know all of the main migration tools and methods. If you want to select the right tool and method for your specific situation, you will see that even though there may be many templates and preconfigured packs out there, your own project potentially comes with some individual aspects. When organizing the data migration project, use the project task skeleton I provided. It is important to subdivide the required migration steps into a group of easy-to-understand steps, where data can be verified at each level. If it gets complicated, it is probably not the right way to move forward, and you need to re-think the methods and tools you are using. Common issues The most common issue I found in similar projects is that the data to be migrated is not entirely clean and consistent. Therefore, be sure to use a data verification procedure at each step. Don't just import data, only to find out later that the database is overloaded with data that is not right. Recommendation Separate the master data and the transaction data. If you don't want to lose valuable transaction data, you can establish a reporting database which will save all of the historic transactions. For example, sales history can easily be migrated to an SQL database. You can then provide access to this information from the required SAP forms using queries or Crystal Reports. Case study During the course of evaluating the data import features available in the SAP Business ONE application, we have already learned how to import business partner information and item data. This can easily be done using the standard SAP data import features based on the Excel or text files. Using this method allows the lead, customer, and vendor data to be imported. Let's say that the Lemonade Stand enterprise has salespeople who travel to trade fairs and collect contact information. We can import the address information using the proven BP import method. But after this data is imported, what would the next step be? It would be a good idea to create and manage opportunities based on the address material. Basically, you already know how to use Excel to bring over address information. Let's enhance this concept to bring over opportunity information. We will use xFusion to import opportunity data into the SAP Business ONE application. The basis will be the xFusion pack for opportunities. Importing sales opportunities for the Lemonade Stand The xFusion pack is open, and you can see that it is a nice and clean example without major complexity. That's how it should be, as you see here:
Read more
  • 0
  • 0
  • 2782

article-image-creating-dialplan-asterisk-16-part-2
Packt
27 Oct 2009
14 min read
Save for later

Creating a Dialplan in Asterisk 1.6: Part 2

Packt
27 Oct 2009
14 min read
Advanced Call Distribution What exactly is Advanced Call Distribution ? Many phone systems tout this feature, but most do not adequately define what it means. Basically, it refers to using call queues, parking calls for another user to answer, and Direct Inward Dialing (DID). So that we keep our focus, we will look at each of these elements individually. Call queues We have already configured call queues through the /etc/asterisk/queues.conf file. As we go through how we're going to use our queues, we may decide we want to change the way our queues are configured. There is absolutely no problem with changing the configuration so that it more accurately reflects our needs. Just remember that we need to issue a reload on the Asterisk console, or type #asterisk –r –x reload at the command line. The power and flexibility of other ACD systems can be matched or exceeded by Asterisk. As we evaluate our needs, we should remember that configuring a single aspect of Asterisk sometimes requires changes to more than one file. For example, queues will be configured both in the queues.conf file and the extensions.conf file. We will discuss how to set up extensions.conf to give us the desired result. When dealing with call queues, we need to think about the two types of users we have. First, we have the caller who calls in and waits in the queue for the next agent. We can think of this person as our customer. Next, we have the agents who work the queue. We can think of these people as our users. As a business, we have to decide what we want our customers' experience to be. Our call queue can make it sound like a phone is ringing. Or we can use music on hold while the customer waits. We can also announce call position and estimated wait time if we want to. When we place customers in a queue, we use the Queue application. To place a caller in the queue named bob, we would use something like: exten => 1000,1,Queue(bob) Suppose we have an operator's extension. As Ollie the operator may have more than one call at a time, we decide to give him a call queue. His calls are always about a minute long. The customers waiting for him are going to be there because they got lost in a system of menus. His queue will be named operator. In this instance, we will choose to have the customer hear the ring, so they will believe they are about to be helped. The sound of ringing should not last more than about a minute. We will not announce call queue length because our customer should not know that he or she is in a queue. The entry for this queue would be: exten => 0,1,Queue(operator|tr) Notice our use of options. Options for the queue application include: t: Allow the user to transfer the customer. T: Allow the customer to transfer the user. d: This is a data-quality call. H: Allow the customer to hang up by hitting *. n: Do not retry on timeout. The next step in the dialplan will be executed. r: Give the customer the ringing sound instead of music on hold. Thus, we told the Queue application to make the customer hear the ring, and the user (Ollie) the ability to transfer calls (as he's the operator). Now, suppose we have Rebecca, the receptionist at SIP phone 1006. When Ollie goes to the bathroom, we want our poor lost customers to be routed to her. So we could use the following in our extensions.conf file: exten => 0,1,Queue(operator|trn)exten => 0,2,Dial(SIP/1006) Now, Rebecca had better answer this. Until she does, the phone will continue to ring. Notice that this call will never end up in Rebecca's voicemail, as it is not transferred to her extension, but instead dials her phone directly. We have adequately addressed the customer's experience. But now we need to look at how our users will join and leave the queue. Previously, we discussed the power and flexibility of using agents in queues. As with most things in Asterisk, there are many ways we can associate members to queues. The three main ways are—statically, dynamically, and by using agents. Our first option is to have members statically assigned to the queue. In order to do this, we use the member directive in the queues.conf file. This is most helpful when we have a queue with fixed members, such as a switchboard queue. Our second option is to allow members to log in dynamically. We do this through the AddQueueMember application. An example of this would be: exten => 8101,1,AddQueueMember(myqueue|SIP/1001) Whenever anybody dials extension 8101, the telephone handset SIP/1001 would be added to the queue named myqueue. All that we would have to do is define a login extension for every member of every queue. What happens when this member no longer wishes to be in the queue? We use the RemoveQueueMember application, like this: exten => 8201,1,RemoveQueueMember(myqueue|SIP/1001) With this configuration, whenever anybody dials extension 8201, the telephone handset at SIP/1001 is removed. Again, we would have to define a logout extension for each member of the queue. Suppose we did not wish to define a login and logout extension for each member. We have the option of leaving off the interface (SIP/1001 in the previous example) and having Asterisk use our current extension. While this is very useful, Asterisk does not always use the right value. However, if it works for all extensions that need to be in the queue, we would only have to define one login and one logout per queue. The code would look like: exten => 8101,1,AddQueueMember(myqueue)exten => 8201,1,RemoveQueueMember(myqueue) This is better than having to define a login and logout for each member of each queue, but sometimes users are not good at remembering multiple extensions to dial. The AddQueueMember application will jump to priority n+101 if that interface is already a member of the queue. Therefore, we could define an extension like: exten => 8101,1,Answerexten => 8101,2,AddQueueMember(myqueue)exten => 8101,3,Playback(agent-loginok)exten => 8101,4,Hangupexten => 8101,103,RemoveQueueMember(myqueue)exten => 8101,102,Playback(agent-loggedoff)exten => 8101,105,Hangup When we define it this way, a user dialing extension 8101 is logged in if not already a member of the queue, or logged out if in the queue. Also, we added a confirmation to the action, so that the user can know if they are now in or out of the queue. Notice that before we could use the Playback application, we had to answer the call. If we have a lot of these, we could define a macro extension, like: [macro-queueloginout]exten => s,1,Answerexten => s,2,AddQueueMember(${ARG1})exten => s,3,Playback(agent-loginok)exten => s,4,Hangupexten => s,103,RemoveQueueMember(${ARG1})exten => s,104,Playback(agent-loggedoff)exten => s,105,Hangup. . .[default]exten => 8101,1,Macro(queueloginout|queue1)exten => 8102,1,Macro(queueloginout|queue2)exten => 8103,1,Macro(queueloginout|queue3) And thus we see that using a macro will save us five lines in our extensions.conf for every queue after the first. This is how we can add queue members dynamically. Our final option for adding queue members is by using Asterisk's agent settings. We were able to define agents in /etc/asterisk/agents.conf. We create an agent by defining an ID and a password, and listing the agent's name. In the queues.conf, we could define agents as members of queues. Calls will not be sent to agents unless they are logged in. In this way, queues can be both dynamic and static—they are static when we do not change the members of the queues, but dynamic when calls will go to different handsets based upon which agents are logged in. There are two main types of agents in this world. There are the archetypical large call center agents who work with a headset and never hear rings, and there are the lower-volume agents whose phone rings each time a call comes in. Asterisk has the flexibility to handle both types of agents, even in the same queue. First, imagine a huge call center that takes millions of phone calls per day. Each agent is in multiple queues, and we have set each queue to use an announcement at the beginning of calls to let the agent know which queue the call is coming in from. As employees arrive for their shift, they sit down at an empty station, plug in their headset, and log in. Each employee will hear music in between calls, and then hear a beep, and the call will be connected. To accomplish this, we use the line: exten => 8001,1,AgentLogin Through the normal login, the call is kept active the whole time. The agents will logout by hanging up the phone. This allows large call centers to be quieter, as the distraction of ringing phones will be removed. It also allows for more efficient answering of lines, as the time required to pick up the phone is eliminated. When our users arrive at work and wish to log in, they call extension 8001, where they are prompted for their agent ID, password, and then an extension number at which they will take calls. This is how Asterisk knows how to reach them. Our agents can log out when using AgentCallbackLogin by going through the same procedure as for login, with the exception that when they are prompted for their extension, they press the # key. It may be a good idea for us to review agents.conf. If we defined autologoff, then after the specified number of seconds of ringing, the agent will be automatically logged off. If we set ackcall to yes, then agents must press the # key to accept calls. If we created a wrapuptime (defined in milliseconds), then Asterisk will wait that many milliseconds before sending another call to the agent. These options can help us make our phone system as user friendly as we want it to be. Through the use of call queues, we can distribute our incoming calls efficiently and effectively. We have plenty of options, and can mix and match these three ways of joining users to queues. Call parking In many businesses across the United States, an operator can be heard announcing "John, you have a call on line 3. John, line 3." In Asterisk, we don't really have lines the way analog PBXs do. Our users are accustomed to not having to transfer calls, especially when they may not know exactly where John is. Asterisk uses a feature known as call parking to accomplish this same goal. Our users will transfer calls to a special extension, which will then tell them what extension to call in order to retrieve the call. Then our users can direct the intended recipient to dial that extension and connect to the call. In order to be able to use this feature, we must define our parking lot. This is done in the /etc/asterisk/parking.conf file. In this file, there are only a few options that we will need to configure. First, we must create the extension that people are to dial in order to park calls. This can be whatever extension is convenient for us. Then we will define a list of extensions on which to place parked calls. These extensions will be what users dial to retrieve a parked call. Next, we will define what context we want our parked calls to be in. Finally, we will define how many seconds a call remains parked before ringing back to the user who parked it. Here is an example: [general]parkext => 8100parkpos => 8101-8199context => parkedcallsparkingtime => 120 These settings would mean that we can park calls by dialing 8100, and the call will be placed in extensions 8101 through 8199, giving us the ability to have up to 99 parked calls at any given time. The calls will be in the context called parkedcalls, which means we should be careful to include it in any context where users should be able to park and retrieve calls. When our users transfer a call to extension 8100, they will hear Asterisk read out the extension that the call has been placed on. They can now make a note of it and notify the appropriate co-worker of the extension to reach the calling customer on. If the call is not picked up within the given parkingtime, then the call will ring back to the user who parked the call. By using call parking, we can help our users by providing a feature similar to that of previous generations of PBXs. This also allows users to collaborate and redirect callers to other users who are better equipped to handle our customers' needs. Direct Inward Dialing (DID) Suppose we work at a healthcare company with over 100 employees. We have two PRI lines coming in, and only three switchboard agents to handle incoming calls. As a healthcare company, we schedule many appointments, answer questions about prescriptions, and help patients with billing questions. These three agents are always busy. Now suppose the IT guy's wife calls in to ask if he wants sprouts or mash with his dinner. Do we want our switchboard agents to have to answer the call, find out who it is and what they want, and then transfer the call, or would we rather want the IT guy's wife to call her husband directly? This is where Direct Inward Dialing (DID) comes in handy. DID is a service provided by phone companies where they send an agreed-upon set of digits, depending on the number the customer dialed. For most phone companies, the sent digits will be the full ten-digit number (in the United States). But this can be as small as the last digit. All right, so the phone company is sending digits. What are we going to do with them? Imagine you have a PRI coming in to your office, and only ten phone numbers—a block from (850) 555-5550 to 5559. Your phone company has agreed to send you only the last digit dialed, which will be from 0 to 9, because you are guaranteed for this to be unique. Asterisk can route calls based on this DID information. If we have our PRI line's channels defined to go into a context called incoming, this context could look like: [incoming]s,1,Goto(default,s,1)i,1,Goto(default,s,1)t,1,Goto(default,s,1)0,1,Goto(default,1234,1)1,1,Goto(default,2345,1)2,1,Goto(default,3456,1)3,1,Goto(default,4567,1)4,1,Goto(default,5678,1)5,1,Goto(default,6789,1)6,1,Goto(default,7890,1)7,1,Goto(default,1111,1)8,1,Goto(default,1111,1)9,1,Goto(default,1111,1) There are a few things we should notice about this. First, we handled the error cases. What if a glitch at the phone company results in four digits being sent? We cannot allow a simple mistake on their end to interrupt our ability to receive phone calls. Secondly, we are using Goto statements. We've briefly discussed how they can be both good and bad. In this case, if a user moves from one extension to another by using Goto, we have to update it only in the default context. Finally, we are allowed to send multiple incoming DIDs to the same extension, if we so desire, as in the last three lines shown in the previous code. This might be useful if extension 1111 is the operator, and we do not yet have the number 7, 8, or 9 assigned to a user. Of course, in real life this is going to get much more complicated, as phone numbers will probably come in with the full ten digits. But the concept is the same—we can define extensions based upon information that the phone company sends when the call is established. By using DIDs, we can cut down on bottlenecks and give direct access to certain extensions. This tool of Asterisk helps make our phone system fast, efficient, and friendly to our users and customers.  
Read more
  • 0
  • 0
  • 3261

article-image-oracle-web-rowset-part2
Packt
27 Oct 2009
4 min read
Save for later

Oracle Web RowSet - Part2

Packt
27 Oct 2009
4 min read
Reading a Row Next, we will read a row from the OracleWebRowSet object. Click on Modify Web RowSet link in the CreateRow.jsp. In the ModifyWebRowSet JSP click on the Read Row link. The ReadRow.jsp JSP is displayed. In the ReadRow JSP specify the Database Row to Read and click on Apply. The second row values are retrieved from the Web RowSet: In the ReadRow JSP the readRow() method of the WebRowSetQuery.java application is invoked. TheWebRowSetQuery object is retrieved from the session object. WebRowSetQuery query=( webrowset.WebRowSetQuery)session.getAttribute("query"); The String[] values returned by the readRow() method are added to theReadRow JSP fields. In the readRow() method theOracleWebRowSet object cursor is moved to the row to be read. webRowSet.absolute(rowRead); Retrieve the row values with the getString() method and add to String[]. Return the String[] object. String[] resultSet=new String[5];resultSet[0]=webRowSet.getString(1);resultSet[1]=webRowSet.getString(2);resultSet[2]=webRowSet.getString(3);resultSet[3]=webRowSet.getString(4);resultSet[4]=webRowSet.getString(5);return resultSet; ReadRow.jsp JSP is listed as follows: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd"><%@ page contentType="text/html;charset=windows-1252"%><%@ page session="true"%><html><head><meta http-equiv="Content-Type" content="text/html;charset=windows-1252"><title>Read Row with Web RowSet</title></head><body><form><h3>Read Row with Web RowSet</h3><table><tr><td><a href="ModifyWebRowSet.jsp">Modify Web RowSetPage</a></td></tr></table></form><%webrowset.WebRowSetQuery query=null;query=( webrowset.WebRowSetQuery)session.getAttribute("query");String rowRead=request.getParameter("rowRead");String journalUpdate=request.getParameter("journalUpdate");String publisherUpdate=request.getParameter("publisherUpdate");String editionUpdate=request.getParameter("editionUpdate");String titleUpdate=request.getParameter("titleUpdate");String authorUpdate=request.getParameter("authorUpdate");if((rowRead!=null)){int row_Read=Integer.parseInt(rowRead);String[] resultSet=query.readRow(row_Read);journalUpdate=resultSet[0];publisherUpdate=resultSet[1];editionUpdate=resultSet[2];titleUpdate=resultSet[3];authorUpdate=resultSet[4];}%><form name="query" action="ReadRow.jsp" method="post"><table><tr><td>Database Row to Read:</td></tr><tr><td><input name="rowRead" type="text" size="25"maxlength="50"/></td></tr><tr><td>Journal:</td></tr><tr><td><input name="journalUpdate" value='<%=journalUpdate%>'type="text" size="50" maxlength="250"/></td></tr><tr><td>Publisher:</td></tr><tr><td><input name="publisherUpdate"value='<%=publisherUpdate%>' type="text" size="50"maxlength="250"/></td></tr><tr><td>Edition:</td></tr><tr><td><input name="editionUpdate" value='<%=editionUpdate%>'type="text" size="50" maxlength="250"/></td></tr><tr><td>Title:</td></tr><tr><td><input name="titleUpdate" value='<%=titleUpdate%>'type="text" size="50" maxlength="250"/></td></tr><tr><td>Author:</td></tr><tr><td><input name="authorUpdate" value='<%=authorUpdate%>'type="text" size="50" maxlength="250"/></td></tr><tr><td><input class="Submit" type="submit" value="Apply"/></td></tr></table></form></body></html>
Read more
  • 0
  • 0
  • 1587

article-image-creating-joomla-15-templates
Packt
27 Oct 2009
16 min read
Save for later

Creating Joomla 1.5 Templates

Packt
27 Oct 2009
16 min read
Corporate Identity Corporate Identity (CI) refers to the self-image and the appearance of an enterprise. This appearance, the identity, either arises from the enterprise's tradition or it is completely invented in a newly created establishment. This identity is important to give the customer a feel for the enterprise and to enable recognition. Corporate Identity includes: Corporate Image (price, product, and advertising strategy) Corporate Design (visual appearance) Corporate Communication Corporate Behavior (behavior of employees towards each other and the outside world) All of the above areas have to be considered when developing a website. In this article, we will examine Corporate Design. At a minimum, it consists of a logo, a character font, and the house colors that the enterprise uses. The visitors to your website should recognize your enterprise on the first visit. HTML/XHTML, CSS, and XML The abbreviations HTML/XHTML, CSS, and XML stand for Internet technologies that Joomla! works with. The World Wide Web Consortium standardizes these technologies. HTML/XHTML The World Wide Web is based on HTML. HTML is not a programming language, but a text-description language. Each piece of text consists of structures like headings, lists, bold and italic areas, tables, and much more. HTML works with so-called tags. A tag has an opening portion and a closing portion. For example, a first-level heading looks as follows: <h1>This is a heading</h1> The tags are interpreted in the browser and the text is displayed according to their significance. HTML is very easy to learn and many online tutorials can be found. HTML is not being developed any further; the successor to HTML is XHTML version 1.0. CSS Cascading Style Sheets (CSS) are an extension to HTML. CSS is not a programming language either, but a vocabulary for defining the format properties of individual HTML elements. With the help of CSS commands, you can, for example, specify that the first-level headings should have a character size of 18 points in the character font Arial, are not bold, and have a spacing of 1.9 cm to the next paragraph. Such options are not possible with pure HTML and were not necessary when HTML was first developed. With the progressive commercialization of the Internet, additional formatting possibilities do, however, become more and more important. CSS data can be integrated into HTML in the following three ways: In the Central HTML File The CSS commands are defined in the head section of the HTML file like this: <head><title>title of the file</title><style type="text/css"><!--/* ... this is where the CSS commands are defined ... */--></style></head> In a Separate CSS File If the CSS commands apply to several HTML files, they can be stored in a separate file and the path to this file can be specified in the HTML header. This is the version that Joomla! uses. <head><title>title of the file</title><link rel="stylesheet" type="text/css" href="formats.css"></head> Within an HTML Tag CSS commands can also be inserted within an HTML tag: <body><h1 style="… CSS commands ...">...</h1></body> Combinations These three methods can be combined without any problem in an HTML file. It is, for instance, possible to subsequently overwrite CSS commands that were defined in a central file in the additional source code of an HTML page. This practice, however, quickly leads to confusing structures; it is better to customize the central file. XML The Extended Markup Language (XML) is a universe in itself. It represents a meta‑language and is derived from the much more complex SGML (Standardized Generalized Markup Language) that was developed in the sixties. XML is often used for configuration files and as an interchange format. For our purposes, you need XML as the description language for the metadata of the templates that you want to create. These metadata are primarily relevant for the Template Installer and the display in the Template Manager. In principle, these data also consist of opening and closing tags. For example: <name>Joomla! Book</name> The difference between HTML and XML is that no tags are predefined in XML. Because of that, you are completely unrestricted in the organization of the structures and the naming of the tags. Creating Your Own Templates Now we want to create our own template. There are several things to consider before we have a finished template packages. Let's take it one step at a time. Concept Before you start working, you have to create a concept. The work starts with a sketch or a diagram, especially when producing templates. It is up to you whether you want to create this sketch with an image editing program like Adobe Photoshop, Microsoft Paint that comes with Windows, the open-source program GIMP, or even with a piece of paper and crayons. Fixed Size or Variable (Fluid) or Both You can create two kinds of templates. Templates that adapt their structure to the size of the browser window and templates that have a fixed size. An example for the flexible layout: if you have 2048 pixels across your screen and the browser window is maximized, then your page is stretched accordingly. That can look strange if you use graphical, non-scalable elements like logos and signatures in your template. You have no control of what it is going to look like. Your other choice is to decide on a certain resolution and to position all the elements exactly on the pixels in the template. This has the advantage that your web page always looks the way you want. Unfortunately, you do not know the resolution of the monitor that is viewing your page. If that monitor has a resolution of 800 x 600 pixels, then your page fills the screen. On a large screen with a resolution of 1400 x 1050 pixels, it occupies about a quarter of the screen surface and looks a little lost. You will have to weigh the pros and cons and make a decision on one or the other, or you can consider barrier freedom and offer both versions. You must have seen websites where you can even change the font size. In addition to the font size buttons there is also often a button to select different layouts. If you prefer the fixed size, you should select a size that looks presentable on most screens, in other words 800 x 600 pixels. Since the browser has a scroll bar on the right side and the browser window is framed, the available width is even smaller, meaning that you have a maximum of 780 pixels to work with. Structure You are dealing with structured data and first have to determine a general allocation. Joomla! normally uses a structure as shown in the following figure: Section 1: Part 1: This is where your logo or a picture and the name of the website goes. Part 2: This is where the search field is. Part 3: This is where the linked navigation path goes (Breadcrumbs). Section 2: Part 4: The most important menus are shown in the left column. Part 5: The actual page content goes here. Part 6: The right column is a place for additional menus. Section 3: Part 7: The footer.     HTML Conversion Now you have to convert the concept into HTML and CSS. Depending on the graphics editing program that you have used to create it, there is a possibility that the picture can be automatically exported to HTML code. You can also do the conversion manually in a text editor, in an HTML editor like Dreamweaver (http://www.adobe.com/products/dreamweaver), or in one of the numerous free HTML editors (http://www.thefreecountry.com/webmaster/htmleditors.shtml). <table> or <div>? The <div> tag is a replacement and a supplement for the <table> tag in HTML. You can enclose several HTML elements, such as text and graphics in one common area with it. This general area does nothing for the time being but start in a new line of the continuing text. The <div> tag does not have any other properties. There are big benefits, however, in using a combination of <div> tags with CSS commands. <div> was specifically developed for the purpose of being formatted with CSS commands. Until 2004, it was common practice to define website structures with generous employment of HTML tables. With CSS and the <div> HTML element becoming more and more popular and with browsers being able to interpret these, more and more templates are being structured without HTML tables. However, rarely do we see websites that contain only semantically correct HTML and that have layouts that are built 100% without tables. The first step in structuring your website in that direction is the use of the <div> tags. Joomla! 1.5 is also gradually straying from the 'table path' and is starting to deliver semantically correct HTML. Nonetheless, it continues to be possible to structure your site layout with HTML tables. There are no table tags in the included rhuk_milkyway template; the entire table-like structure is created with <div> tags. Take a look at the original source code of this template to familiarize yourself with this technology. You can get more information about <div> tags at selfhtml (in German). Dreamweaver also supports this technology. The source code of the HTML conversion looks somewhat like the following listing. The code is kept simple on purpose and is not consistent with the XHTML standard in the header. The file name of this layout file has to be index.php since Joomla! searches it for embedded commands per PHP. HTML file /index.php: <html> <head> <link href="/joomla150/templates/joomla150buch/css/template.css" rel="stylesheet" type="text/css" /> </head> <body> <div id="part11">header / header<br /><br /> <div id="section1">section1</div> <div id="section2">section2</div> </div> <div id="part2">main display area / main<br /><br /> <div id="section3">breadcrumbs</div> <div id="section6">right side</div> <div id="section4">left side</div> <div id="section5">content</div> </div> <div id="part3">footer /footer<br /><br /> <div id="section7">section7</div> </div> </body></html> The subsequent CSS file from the individual template is integrated into the header area of the code. At the moment this CSS file contains only one command that defines the typeface. CSS file /css/template.css: body{font-size: 12px;font-family: Helvetica,Arial,sans-serif; }#Part1{ /*header*/float: left;border: 2px dotted green; }#Part2{ /*main*/float: left;border: 2px dotted yellow; }#Part3{ /*footer*/clear:all;border: 2px dotted red; }#Section1{ /*top right*/float: left; width: 18em;margin: 0 0 1.2em;border: 1px dashed silver; background-color: #eee; }#Section2{ /*top left*/float: right; width: 12em;margin: 0 0 1.1em;background-color: #eee; border: 1px dashed silver; }#Section3{ /*breadcrumbs*/border: 1px dashed silver;background-color: #eee; }#Section4{ /*left side*/float: left; width: 15em;margin: 0 0 1.2em;border: 1px dashed silver; }#Section5{ /*content*/margin: 0 12em 1em 16em;padding: 0 1em;border: 1px dashed silver; }#Section6{ /*right side*/float: right; width: 12em;margin: 0 0 1.1em;background-color: #eee; border: 1px dashed silver; }#Section7{ /*footer*/margin: 0 0 1.1em;background-color: #eee; border: 1px dashed silver; } You will create this first template manually in the Joomla! directory. When the template is ready, you can turn it into a compressed installation package that it can then be installed by a third party (or by you yourself) using the Joomla! installer. Save the HTML layout file by the name of index.php in the also newly created [PathtoJoomla]/templates/joomla150book/ directory. Save the template.css file in the [PathtoJoomla]/templates/joomla150book/css/ directory. The basic structure of your template is done. Now you have to define the template more exactly for Joomla! with the help of an XML file so that it will be displayed in the template administration section. Directory Structures of the Template Now it's time to take care of certain conventions. As previously discussed, the template has to be stored in a specific directory structure. [PathtoJoomla]/templates/[name of the template]/[PathtoJoomla]/templates/[name of the template]/CSS/[PathtoJoomla]/templates/[name of the template]/images/ The name of the template cannot contain blanks and other special characters. When this template is later installed as a package, the Template Installer has to create a directory from this name. Depending on the operating system, exotic combinations of characters can cause problems. In addition, the name should be meaningful. Here we will use joomla150book as the name of the template. Various files with predefined names have to be present in the template directories. Layout File: This is the HTML file that we created earlier:/templates/joomla150book/index.php. It should have the .php ending, since the dynamic Joomla! module elements that we will insert later have to be interpreted by PHP. Preview Picture: The /templates/joomla150book/template_thumbnail.png file contains a preview image of your template for preview selection in Joomla! administration in the Extensions | Template Manager menu. Preview pictures have a format of 200 by approximately 150 pixels. You can create this file later when you can see your template. Metadata of the Template: The /templates/joomla150_book/templateDetails.xml file represents the construction manual for the template installer and contains the installations for the template selection in the template manager. Here you specify the location where the files are to be copied, who the author is, and additional metadata about the template. During subsequent installation of this file by the Joomla! installer, PHP reads this file and copies the files to the place specified by the XML file. For the example template, you can use the file from the following listing (templateDetails.xml) and populate it with your own data. For every file that you use in the template, a respective XML container has to be populated with the file name and the correct path. <files> <filename> ... enter the filename of a file in the TemplateRoot directory ... </filename> <filename> ... for every file a filename-Container </filename></files> The other containers of the XML file are there for the description of the template. Here is the complete functional listing of the XML file: templateDetails.xml: <install version="1.5" type="template"><name>joomla150book</name><version>1.0</version><creationDate>11.11.2007</creationDate><author>Hagen Graf</author><copyright>GNU/GPL</copyright><authorEmail>hagen@cocoate.com</authorEmail><authorUrl>http://www.cocoate.com</authorUrl><version>0.1</version><description>... description</description><files><filename>index.php</filename><filename>templateDetails.xml</filename><filename>template_thumbnail.png</filename><filename>css/template.css</filename></files></install> Create the templateDetails.xml file in the [PathtoJoomla]/templates/joomla150book/ directory as well. CSS File: You can use several CSS files for your template. What name you give the CSS file and how you create it is up to you. There are, however, standard descriptions for various CSS elements. For your first attempt, you need a CSS file with the name /templates/joomla150_book/css/template.css. Graphics, Images: Here you can enter user-defined image files that you need in your template. The installer then copies the files into the images folder. The file name appears as /templates/joomla150_book/images/[user-defined image files]. First Trial Run Once you have reproduced all the structures in the [pathtoJoomla!]/templates/ subdirectory, you can already see your new template in the Extensions | Template Manager menu of your Joomla! administration and you can make it default: When you call up your website, you will see your new template. Unfortunately, there is no content shown yet. Since this content is produced dynamically, you have to integrate it piece by piece into your new template. Integration of the Joomla! Module The integration of the Joomla! module takes place by means of commands embedded into the HTML code. Joomla! uses the namespace jdoc to integrate various elements into the template. If you insert the following highlighted line into the header of the layout file: <head><jdoc:include type="head" /> </head> the title of the site and the news feed symbol are already correctly displayed. If you call up the source code of this site, you will notice that Joomla! has copied the entire metadata that you had entered in administration into the HTML code. In addition, the RSS feeds have been integrated by means of link tags and these will be displayed as feed symbols in browsers like Firefox that support this technology. Joomla! Metadata: <head> <base href="http://localhost/joomla150/" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="robots" content="index, follow" /> <meta name="keywords" content="joomla, joomla!, Joomla, Joomla!, J!" /> <meta name="description" content="Joomla! - dynamic portal-engine and Content-Management-System" /> <meta name="generator" content="Joomla! 1.5 - Open Source Content Management" /> <title>Welcome to the Frontpage</title> <link href="/joomla150/index.php?format=feed&amp;type=rss" rel="alternate" type="application/rss+xml" title="RSS 2.0" /> <link href="/joomla150/index.php?format=feed&amp;type=atom" rel="alternate" type="application/atom+xml" title="Atom 1.0" /> <script type="text/javascript" src="/joomla150/media/system/js/mootools.js"></script> <script type="text/javascript" src="/joomla150/media/system/js/caption.js"></script>...  
Read more
  • 0
  • 0
  • 2039
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-how-create-tax-rule-magento
Packt
27 Oct 2009
11 min read
Save for later

How to create a Tax Rule in Magento

Packt
27 Oct 2009
11 min read
In this article by William Rice, we will see how to create Tax Rules in Magento. In the real world, the tax rate that you pay is based on three things: location, product type, and purchaser type. In Magento, we can create Tax Rules that determine the amount of tax that a customer pays, based upon the shipping address, product class, and customer class. When you buy a product, you sometimes pay sales tax on that product. The sales tax that you pay is based on: Where you purchased the product from. Tax rules vary in different cities, states, and countries. The type of product that you purchased. For example, many places don't tax clothing purchases. And, some places tax only some kinds of clothing. This means that you must be able to apply different tax rates to different kinds of products. The type of purchaser you are. For example, if you buy a laser printer for your home, it is likely that you will pay sales tax. This is because you are a retail customer. If you buy the same printer for your business, in most places you will not pay sales tax. This is because you are a business customer. The amount of the purchase. For example, some places tax clothing purchases only above a specific amount. Anatomy of a Tax Rule A Tax Rule is a combination of the tax rate, shipping address, product class, customer class, and amount of purchase. A Tax Rule states that you pay this amount of tax if you are this class of purchaser, and you bought this class of product for this amount, and are shipping it to this place. The components of a Tax Rule are shown in the following screenshot. This screen is found under Sales | Tax | Manage Tax Rules | Add New Tax Rule. You will see the Name of the Tax Rule while working in the backend. Customer Tax Class Customer Tax Class is a type of customer that is making a purchase. Before creating a Tax Rule, you will need to have at least one Customer Tax Class. Magento provides you with a Tax Rule called Retail Customer. If you serve different types of customers—retail, business, and nonprofit—you will need to create different Customer Tax Classes. Product Tax Class Product Tax Class is a type of Product that is being purchased. When you create a Product, you will assign a Product Tax Class to that Product. Magento comes with two Product Tax Classes:Taxable Goods and Shipping. The class Shipping is applied to shipping charges because some places charge sales tax on shipping. If your customer's sales tax is different for different types of Products, then you will need to create a Product Tax Class for each type of Product. Tax Rate Tax Rate is a combination of place, or tax zone, and percentage. A zone can be a country, state, or zip code. Each zone that you specify can have up to five sales tax percentages. For example, in the default installation of Magento, there is one tax rate for the zone New York. This is 8.3750 percent, and applies to retail customers. The following window can be found at Sales | Tax | Manage Tax Zones & Rates and then clicking on US-NY-*-Rate 1: So in the screenshot of our Tax Rule, the Tax Rate US-NY-*-Rate 1 doesn't mean "a sales tax of 1 percent." It means "Tax rate number 1 for New York, which is 8.3750 percent." In this scenario, New York charges 8.3750 percent sales tax on retail sales. If New York does not charge sales tax for wholesale customers, and you sell to wholesale customers, then you will need to create another Tax Rate for New York: Whenever a zone has different sales taxes for different types of products or customers, you will need to create different Tax Rates for that zone. Priority If several Tax Rules try to apply several Tax Rates at the same time, how should Magento handle them? Should it add them all together? Or, should it apply one rate, calculate the total, and then apply the second rate to that total? That is, should Magento add them or compound them? For example, suppose you sell a product in Philadelphia, Pennsylvania. Further suppose that according to the Tax Rule for Pennsylvania, the sales tax for that item is 6 percent, and that the Tax Rule for Philadelphia adds another 1 percent. In this case, you want Magento to add the two sales taxes. So, you would give the two Tax Rates the same Priority. By contrast, Tax Rates that belong to Tax Rules with different Priorities are compounded. The Tax Rate with the higher Priority (the lower number) is applied, and the next higher Priority is applied to that total, and so on. Sort Order Sort Order determines the Tax Rules' position in the list of Tax Rules. Why create Tax Rules now? Why create a Tax Rule now, before adding our first Product? When you add a Product to your store, you put that Product into a Category, assign an Attribute Set, and select a Tax Class for that Product. By default, Magento comes with two Product Tax Classes and one Tax Rule already created. The Product Tax Classes are Taxable Goods and Shipping. The Tax Rule is Retail Customer-Taxable Goods-Rate 1. If you sell anything other than taxable goods, or sell to anyone other than retail customers, you will need to create a new Tax Rule to cover that situation. Creating a Tax Rule The process for creating a Tax Rule is: Create the Customer Tax Classes that you need, or confirm that you have them. Create the Product Tax Classes that you need, or confirm that you have them. Create the Tax Rates that you need, or confirm that you have them and that they apply to the zones that you need. Create and name the Tax Rule: Assign Customer Tax Class, Product Tax Class, and Tax Rates to the Rule. Use the Priority to determine whether the Rule is added, or compounded, with other Rules. Determine the Sort Order of the Rule and save it. Each of these steps is covered in the subsections that follow. Time for action: Creating a Customer Tax Class From the Admin Panel, select Sales | Tax | Customer Tax Classes. The Customer Tax Classes page is displayed. If this is a new installation, only one Class is listed, Retail Customer as shown in the following screenshot: Click on Add New. A Customer Tax Class Information page is displayed. Enter a name for the Customer Tax Class. In our demo store, we are going to create Customer Tax Classes for Business and Nonprofit customers. Click on Save Class. Repeat these steps until all of the Customer Tax Classes that you need have been created. What just happened? A Tax Rule is composed of a Customer Class, Product Class, Tax Rate, and the location of the purchaser. You have just created the first part of that formula: the Customer Class. Time for action: Creating a Product Tax Class From the Admin Panel, select Sales | Tax | Product Tax Classes. The Product Tax Classes page is displayed. If this is a new installation, only two Classes are listed: Shipping and Taxable Goods. Click on Add New. The Product Tax Class Information page gets displayed: Enter a name for the Product Tax Class. In our demo store, we are going to create Product Tax Classes for Food and Nonfood products. We will apply the Food class to the coffee that we sell. We will apply the Nonfood class to the mugs, coffee presses, and other coffee accessories that we sell. Click on Save Class. Repeat these steps until all of the Product Tax Classes that you need have been created. What just happened? A Tax Rule is composed of a Customer Class, Product Class, Tax Rate, and the location of the purchaser. You have just created the second part of that formula: the Product Class. Creating Tax Rates In Magento, you can create Tax Rates one at a time. You can also import Tax Rates in bulk. Each method is covered in the next section. Time for action: Creating a Tax Rate in Magento From the Admin Panel, select Sales | Tax | Manage Tax Zones & Rates. The Manage Tax Rates page is displayed. If this is a new installation, only two Tax Rates are listed: US-CA-*-Rate 1 and US-NY-*-Rate 1. Click on Add New Tax Rate. The Add New Tax Rate page gets displayed: Tax Identifier is the name that you give this Tax Rate. You will see this name when you select this Tax Rate. The example that we saw is named US-CA-*-Rate 1. Notice how this name tells you the Country, State, and Zip/Post code for the Tax Rate. (The asterisk indicates that it applies to all zip codes in California.) It also tells which rate applies. Notice that the name doesn't give the actual percentage, which is 8.25%. Instead, it says Rate 1. This is because the percentage can change when California changes its tax rate. If you include the actual rate in the name, you would need to rename this Tax Rate when California changes the rate. Another way this rate could have been named is US-CA-All- Retail. Before creating new Tax Rates, you should develop a naming scheme that works for you and your business. Country, State, and Zip/Post Code determine the zone to which this Tax Rate applies. Magento calculates sales tax based upon the billing address, and not the shipping address. Country and State are drop-down lists. You must select from the options given to you. Zip/Post Code accepts both numbers and letters. You can enter an asterisk in this field and it will be a wild card. That is, the rate will apply to all zip/post codes in the selected country and state. You can enter a zip/post code without entering a country or state. If you do this, you should be sure that zip/post code is unique in the entire world. Suppose you have one tax rate for all zip codes in a country/state, such as 6% for United States/Pennsylvania. Also, suppose that you want to have a different tax rate for a few zip codes in that state. In this case, you would create separate tax rates for those few zip codes. The rates for the specific zip codes would override the rates for the wild card. So in a Tax Rate, a wild card means, "All zones unless this is overridden by a specific zone." In our demo store, we are going to create a Tax Rate for retail customers who live in the state of Pennsylvania, but not in the city of Philadelphia as shown: Click on Save Rate. You are taken back to the Manage Tax Rates page. The Tax Rate that you just added should be listed on the page. This procedure is useful for adding Tax Rates one at a time. However, if you need to add many Tax Rates at once, you will probably want to use the Import Tax Rates feature. This enables you to import a .csv, or a text-only file. You usually create the file in a spreadsheet such as OpenOffice Calc or Excel. The next section covers importing Tax Rates. What just happened? A Tax Rule is composed of a Customer Class, Product Class, Tax Rate, and the location of the purchaser. You have just created the third part of that formula: the Tax Rate. The Tax Rate included the location and the percentage of tax. You created the Tax Rate by manually entering the information into the system, which is suitable if you don't have too many Tax Rates to type. Time for action: Exporting and importing Tax Rates In my demo store, I have created a Tax Rate for the state of Pennsylvania. The Tax Rate for the city of Philadelphia is different. However, Magento doesn't enable me to choose a separate Tax Rate based on the city. So I must create a Tax Rate for each zip code in the city of Philadelphia. At this time there are 84 zip codes, and are shown here:     19019 19092 19093 19099 19101 19102 19103 19104 19105 19106 19107 19108 19109 19110 19111 19112 19113 19114 19115 19116 19118 19119 19120 19121 19122 19123 19124 19125 19126 19127 19128 19129 19130 19131 19132 19133 19134 19135 19136 19137 19138 19139 19140 19141 19142 19143 19144 19145 19146 19147 19148 19149 19150 19151 19152 19153 19154 19155 19160 19161 19162 19170 19171 19172 19173 19175 19177 19178 19179 19181 19182 19183 19184 19185 19187 19188 19191 19192 19193 19194 19196 19197 19244 19255        
Read more
  • 0
  • 0
  • 12449

article-image-creating-student-blog-drupal-using-cloning
Packt
27 Oct 2009
6 min read
Save for later

Creating the Student Blog in Drupal using Cloning

Packt
27 Oct 2009
6 min read
For the purpose of this article we will clone the already existing Teacher Blog and create the Student Blog. Setting Up the Student Blog To create the student blog, we need to do two things: Give users in the student role permissions over the blog post content type. Clone the teacher_blog view, and edit it to display student blog posts. Assigning Permissions To allow students to blog in the site, we need to allow users in the student role the ability to create blog posts. Click the Administer | User management | Roles link, or navigate to admin/user/roles. Click the link to edit permissions for the student role. Navigate down to the section for the node module. Select the options for create blog_post content, delete own blog_post content, and edit own blog_post content. Click the Save permissions button to save the settings. Students can now blog in the site. Clone the Teacher Blog Now that students have the ability to create blog posts, we now need to create a central place where people can read these posts. We have already set up this structure for the teacher blog; cloning this pre-existing view will allow us to quickly replicate this structure for the student blog. To begin, click the Administer | Site building | Views link, or navigate to admin/build/views. Scroll down to the teacher_blog view and click the Clone link. Change the view name to student_blog; change the view description to All posts to be displayed in the Student blog; change the View tag to student. Click the Next button to continue. In the default settings, we want to change the User: Roles filter. As shown in the following screenshot, you can verify that you are editing the Defaults as indicated by Item 1; to edit the User: Roles filter, click the link as indicated by Item 2; and to edit the Title, click the link indicated by Item 3. Change the User: Roles setting to student; this will only select content posted by users in the student role. Change the Title setting to Student blog. As we add more content types (audio, video, and images) we will need to revisit this view to update the Node:Type filter. At this stage, this filter only selects blog posts and bookmarks. Then, as shown in the following screenshot, click the Page link (indicated by Item 1) to change the settings for the Page display for this view. We need to edit both of the options under Page settings (indicated by Item 2). We also need to edit the Header (indicated by Item 3) in the Basic settings. Under Page settings, change the Path to student-blog, and change Menu to Normal: Student blog. Under Basic settings, edit the Header to read Hello! You are viewing posts from the student blog. Enjoy your reading, and comment frequently. Click the Save button to save the view. All student blog posts are now visible at http://yoursite.org/student-blog. Getting Interactive Now that students can create blogs in the site, you have the ability to foster dialogue within your class. The easiest way, of course, is simply through commenting. Students have the rights to comment on assignments, and on teacher and student blog posts. However, students might also want to reference other pieces of content in their work. In this section, we will set up a mechanism that will keep track of when one post within the site references another post within the site. This way, people can see when exchanges are occurring about different posts, and it provides another way (in addition to comment threads) for people to hold discussions within the course. Seeing Who's Discussing What Within the site, we will want to see who is discussing what posts. In web parlance, this is referred to as a backlink. Fortunately, the Views module comes with a means of tracking backlinks by default. We will clone and customize this existing view to get exactly the functionality we want. The process of cloning this view includes the following steps: The default backlinks view needs to be enabled and cloned. In the cloned view, the different displays need to be edited: In the Default display, Fields need to be added to the view, the Arguments need to be adjusted, and the Empty text needs to be deleted. As the new view will only generate a block, the Page display should be removed. In the Block display, the Items per page needs to be increased, the More link needs to be removed, and the Block settings needs to be changed. Then, once the new view has been saved, the block created by this view needs to be enabled. Enabling and Cloning the Backlinks View To get started, click the Administer | Site building | Views link, or navigate to admin/build/views. As shown in the following screenshot, enable the default backlinks view. Once we have enabled the backlinks view, we want to clone it. So, we click the Clone link. Change the View name to conversations, and change the View description to Cloned from default "backlinks" view; displays a list of nodes that link to the node, using the search backlinks table. The View tag can be left blank. Click the Next button, which brings us to the Edit page for the view. Editing the Default Display As shown in the following screenshot, we will make four main edits to this view. We will add Fields, adjust the Arguments, delete the Empty text, and remove the Page display. To add Fields, click the + icon as indicated, in the preceding screenshot, by Item 1. Add three fields: Node: Post Date; Node: Type; and User: Name. Click the Add button, and then configure the new fields to your preferences. Next, edit the Arguments by clicking the Search: Links to link as indicated in the preceding screenshot by Item 2. We will edit the argument handling as shown in the following screenshot: Select the options to only validate for Blog posts and Bookmarks. Additionally, check the option for Validate user has access to the node. These argument settings confirm that we are only checking for backlinks on Blog posts and Bookmarks. As we add more content types (for audio, video, and images) we will need to update this view to check for backlinks on these additional content types as well. Click the Update button to store these changes. Then, we will remove the Empty text by clicking the Filtered HTML link as indicated by Item 3 in the screenshot just above the preceding one. Delete the existing empty text string, and click the Update button to store the changes. Deleting the empty text makes it so the view will not be displayed if the view returns no content. Although this would not be useful on a Page display, it is useful for a Block display, as this hides the block when there is nothing to show.
Read more
  • 0
  • 0
  • 2893

article-image-real-content-php5-cms-part-2
Packt
27 Oct 2009
8 min read
Save for later

Real Content in PHP5 CMS: Part 2

Packt
27 Oct 2009
8 min read
Framework solution To explore implementation details, we will look at an example that is simple enough to be shown in some detail. It is an application for handling pages composed largely of text and images. After studying the example, we will consider how the application could be made more advanced. A simple text application Here, we'll look at a component that can be used on its own but is also intended as a starting point for more sophisticated uses. Its essence is that it handles a piece of text, created using the site WYSIWYG editor by the administrator. The text can be displayed as the main portion of a Web page. Ancillary information is held about the text. Any particular text can be the target of a menu entry, so the component can be used for simple pages. The WYSIWYG editor provides for moderately complex text layout and the inclusion of images. We shall see that writing a text handling extension is made very much simpler by the various elements of the CMS framework. The database table for simple text After the ID number that is used as the main key we have the primary constituents of a piece of text. They are the headline, the subheading, and the body of the article. Each of these will simply reflect whatever text is put in them by the author, who in this simple implementation must also be an administrator. Next we have a couple of time stamps that can be automatically maintained by the software. Rather obviously, the created time stamp is set when the row is created, and the modified time stamp is set every time the row is updated. We then have fields that control the publication of the text. First, there is a simple indicator, which is set to zero if the text is not published and is set to one if it is published. When set to unpublished, the indicator overrides the start and end dates, if they are present. If a non-zero start date is set, then the text will not be published before that date. Likewise, if a non-zero finish date is set, the article will cease to be published after that date. Publishing dates are very useful to control when text will appear as it is often helpful to time the start of publication, and it creates a bad impression if obsolete text is not removed. Then we have data that describes who has worked on the text. The original creator is recorded as a user ID, and the last modifier is likewise recorded as a user ID. These fields are intended for tracking what is happening to the text rather than for display. On the other hand, the byline is entirely for display. Version is a character field that has no defined structure in this simple component, but could be elaborated in many different ways. Storage for metadata is provided as keys and description. This information is not for display on the browser page, but is used to generate meta information in the header of a page containing the text. Tags containing metadata can influence search engines used for indexing of pages, although description is much more influential than keywords, which are believed to be largely disregarded. Finally, a hit counter is automatically maintained by the system, being set initially to zero and then updated every time the text is shown to a site visitor. A text data object When a text item is loaded into memory from the database, a class provides for the definition of the object will be created. For the simple text application, the class is: class textItem extends aliroDatabaseRow { protected $DBclass = 'aliroDatabase'; protected $tableName = '#__simple_text'; protected $rowKey = 'id'; public function store ($updateNulls=false) { $userid = aliroUser::getInstance()->id; if ($this->id) { $this->modified = date('Y-m-d H:i:s'); $this->modify_id = $userid; } else { $ this->created = date('Y-m-d H:i:s'); $this->author_id = userid; } parent::store($updateNulls); } } Much of the hard work is done in the parent class, aliroDatabaseRow. Because the database framework derives information from the database itself, there is no need to specify the fields that are in the table, which makes it easier to cope with future changes. The minimum that has to be done is to specify the name of the singleton database class, the name of the table (using a symbol in place of the actual prefix), and to define the name of the primary key field. In this case, the store method is also extended. This provides an easy way to maintain the time stamps on the text. The current user is found through the aliroUser singleton class. We know whether a text row is new from whether it already has a value for id. The correct date and user field can then be updated. Finally, the standard store method in the parent class is invoked. Administering text items—controller The administrator logic for handling simple text follows the usual pattern of first providing a list of items, paged if necessary, then allowing more detailed access to individual items, including the ability to edit. Logic for overall control is provided by the aliroComponentAdminManager class, and the aliroComponentAdminControllers class. In fact, we could nominate in the packaging XML aliroComponentAdminManager as the adminclass for our component, since the dedicated textAdmin class does nothing: class textAdmin extends aliroComponentAdminManager { // This could be omitted - included here in case extra code needs to be added public function __construct ($component, $system, $version) { parent::__construct ($component, $system, $version); } // Likewise, this could be omitted unless extra code is needed public function activate () { parent::activate(); } } Why might we want to write a dedicated extension to aliroComponentAdminManager? Well, this is the common entry point for the administrator side of our component, so if we wanted any processing to exist that could affect every use of the component, this is the place to put it. The two possible locations are the constructor and the activation method. The constructor receives information from the CMS environment in the form of a component object (describing this component), the name of the system that is calling us, and its version. It is invoked as soon as the correct component has been determined. The standard processing in the aliroComponentAdminManager constructor includes creating the controller class, and acquiring some common variables from $_REQUEST. Once setup is completed, the activation method is invoked without any parameters. The activate method of the aliroComponentAdminManager class strips any magic quotes, and decides what method to call. Of course, the framework allows us to construct a component completely differently if we choose. The only constraint is that we must write a class whose name is given in the packaging XML, and provide it with an activate method. But usually it is a lot easier to follow the standard construction, and the bare bones of a new component can be built and downloaded online from http://developer.aliro.org. Nothing specific has been done yet, and we have to move into the controller code before we can find anything to do with handling text objects. The controller is subclassed from aliroComponentAdminControllers and starts off as shown: class textAdminText extends aliroComponentAdminControllers { private static $instance = null; // If no code is needed in the constructor, it can be omitted, relying on the parent class protected function __construct ($manager) { parent::__construct ($manager); } public static function getInstance ($manager) { return is_object(self::$instance) ? self::$instance : (self::$instance = new self ($manager)); } public function getRequestData () { // Get information from $_POST or $_GET or $_REQUEST // This method will be called before the toolbar method } // If this method is provided, it should return true if permission test is satisfied, false otherwise public function checkPermission () { $authoriser = aliroAuthoriser::getInstance(); if ($test = $authoriser->checkUserPermission('manage', 'aSimpleText', '*')) { if (!$this->idparm) return true; if ($authoriser->checkUserPermission('edit', 'aSimpleText', $this->idparm)) return true; } return false; } Here, the constructor is not needed; it is shown only to indicate the possibility of having code at the point the controller object is created. The constructor receives the manager object as a parameter, in this case an instance of textAdmin, a subclass of aliroComponentAdminManager. The controller is a singleton class, and here a form of the getInstance method is shown that can be used completely unchanged from component to component. Then we have two methods that are standard. Neither has to be provided, and in this case, the getRequestData method is not needed since it does nothing. Its purpose is to run early on (it is called before the toolbar processing and well before the processing specific to the current request) to acquire information from $_REQUEST or $_GET or $_PUT (or possibly other super-globals). They can be saved as object properties so as to be available for toolbar construction or other processing. The checkPermission method provides the component with a way to easily control who is able to access its facilities. If the method returns true then the user will be allowed to continue, but if it returns false, they will be refused access. In this example, there is always a check that the user is permitted to manage objects of the type aSimpleText and if a specific one is identified by its ID, then there is a further check that the user is permitted to edit that particular text item.
Read more
  • 0
  • 0
  • 1832

article-image-aspnet-social-networks-blogs-fisharoo
Packt
27 Oct 2009
8 min read
Save for later

ASP.NET Social Networks—Blogs in Fisharoo

Packt
27 Oct 2009
8 min read
Problem This article, as stated in Introduction, is all about adding the Blogging feature to our site. This will handle creating and managing a post. It will also handle sending alerts to your friends' filter page. And finally we will handle creating a friendly URL for your blog posts. Here we are making our first post to our blog: Once our post is created, we will then see it on the Blogs homepage and the My Posts section. From here we can edit the post or delete it. Also, we can click into the post to view what we have seen so far. The following screenshot shows what one will see when he/she clicks on the post: I have the blog post set up to show the poster's avatar. This is a feature that you can easily add to or remove. Most of your users want to be able to see who the author is that they are currently reading! Also, we will add a friendly URL to our blog post's pages. Design The design of this application is actually quite simple. We will only need one table to hold our blog posts. After that we need to hook our blog system into our existing infrastructure. Blogs In order for us to store our blog, we will need one simple table. This table will handle all the standard attributes of a normal blog post to include the title, subject, page name, and the post itself. It has only one relationship out to the Accounts table so that we know who owns the post down the road. That's it! Solution Let's take a look at the solution for these set of features. Implementing the database Let's take a look at the tables required by our solution. Blogs The blogs table is super simple. We discussed most of this under the Blogs section. The one thing that is interesting here is the Post column. Notice that I have this set to a varchar(MAX) field. This may be too big for your community, so feel free to change it down the road. For my community I am not overly worried. I can always add a UI restriction down the road without impacting my database design using a validation control. After that we will look at the IsPublished flag. This flag tells the system whether or not to show the post in the public domain. Next to that we will also be interested in the PageName column. This column is what we will display in the browser's address bar. As it will be displayed in the address bar, we need to make sure that the input is clean so that we don't have parsing issues (responsible for causing data type exceptions) down the road. We will handle that on the input side in our presenter later. Creating the relationships Once all the tables are created, we can then create all the relationships. For this set of tables we have relationships between the following tables: Blogs and Accounts Setting up the data access layer To set up the data access layer follow the steps mentioned next: Open the Fisharoo.dbml file. Open up your Server Explorer window. Expand your Fisharoo connection. Expand your tables. If you don't see your new tables try hitting the Refresh icon or right-clicking on tables and clicking Refresh. Then drag your new tables onto the design surface. Hit Save and you should now have the following domain objects to work with! Keep in mind that we are not letting LINQ track our relationships, so go ahead and delete them from the design surface. Your design surface should have all the same items as you see in the screenshot (though perhaps in a different arrangement!). Building repositories With the addition of new tables will come the addition of new repositories so that we can get at the data stored in those tables. We will be creating the following repository to support our needs. BlogRepository Our repository will generally have a method for select by ID, select all by parent ID, save, and delete. We will start with a method that will allow us to get at a blog by its page name that we can capture from the browser's address bar. public Blog GetBlogByPageName(string PageName, Int32 AccountID){Blog result = new Blog();using(FisharooDataContext dc = _conn.GetContext()){result = dc.Blogs.Where(b => b.PageName == PageName &&b.AccountID == AccountID).FirstOrDefault();}return result;} Notice that for this system to work we can only have one blog with one unique page name. If we forced our entire community to use unique page names across the community, we would eventually have some upset users. We want to make sure to enforce unique page names across users only for this purpose. To do this, we require that an AccountID be passed in with the page name, which gives our users more flexibility with their page name overlaps! I will show you how we get the AccountID later. Other than that we are performing a simple lambda expression to select the appropriate blog out of the collection of blogs in the data context. Next, we will discuss a method to get all the latest blog posts via the GetLatestBlogs() method. This method will also get and attach the appropriate Account for each blog. Before we dive into this method, we will need to extend the Blog class to have an Account property. To extend the Blog class we will need to create a public partial class in the Domain folder. using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace Fisharoo.FisharooCore.Core.Domain{ public partial class Blog { public Account Account { get; set; } }} Now we can look at the GetLatestBlogs() method. public List<Blog> GetLatestBlogs(){ List<Blog> result = new List<Blog>(); using(FisharooDataContext dc = _conn.GetContext()) { IEnumerable<Blog> blogs = (from b in dc.Blogs where b.IsPublished orderby b.UpdateDate descending select b).Take(30); IEnumerable<Account> accounts = dc.Accounts.Where(a => blogs.Select(b => b.AccountID).Distinct().Contains(a.AccountID)); foreach (Blog blog in blogs) { blog.Account = accounts.Where(a => a.AccountID == blog.AccountID).FirstOrDefault(); } result = blogs.ToList(); result.Reverse(); } return result;} The first expression in this method gets the top N blogs ordered by their UpdateDate in descending order. This gets us the newest entries. We then add a where clause looking for only blogs that are published. We then move to getting a list of Accounts that are associated with our previously selected blogs. We do this by selecting a list of AccountIDs from our blog list and then doing a Contains search against our Accounts table. This gives us a list of accounts that belong to all the blogs that we have in hand. With these two collections in hand we can iterate through our list of blogs and attach the appropriate Account to each blog. This gives us a full listing of blogs with accounts. As we discussed earlier, it is very important for us to make sure that we keep the page names unique on a per user basis. To do this we need to have a method that allows our UI to determine if a page name is unique or not. To do this we will have the CheckPageNameIsUnique() method. public bool CheckPageNameIsUnique(Blog blog){ blog = CleanPageName(blog); bool result = true; using(FisharooDataContext dc = _conn.GetContext()) { int count = dc.Blogs.Where(b => b.PageName == blog.PageName && b.AccountID == blog.AccountID).Count(); if(count > 0) result = false; } return result;} This method looks at all the blog entries except itself to determine if there are other blog posts with the same page name that are also by the same Account. This allows us to effectively lock down our users from creating duplicate page names. This will be important down the road when we start to discuss our pretty URLs. Next, we will look at a private method that will help us clean up these page name inputs. Keep in mind that these page names will be displayed in the browser's address bar and therefore need not have any characters in them that the browser would want to encode. While we can decode the URL easily, this conversation is more about keeping the URL pretty so that the user and search engine spiders can easily read where they are at. When we have characters in the URL that are encoded, we will end up with something like %20 where %20 is the equivalent to a space. But to read my%20blog%20post is not that easy. It is much easier to ready my-blog-post. So we will strip out all of our so called special characters and replace all spaces with hyphens. This method will be the CleanPageName() method. private Blog CleanPageName(Blog blog){ blog.PageName = blog.PageName.Replace(" ", "-").Replace("!", "") .Replace("&", "").Replace("?", "").Replace(",", ""); return blog;} You can add to this as many filters as you like. For the time being I am replacing the handful of special characters that we have just seen in the code. Next, we will get into the service layers that we will use to handle our interactions with the system.
Read more
  • 0
  • 0
  • 4476
article-image-developing-web-applications-using-javaserver-faces-part-2
Packt
27 Oct 2009
5 min read
Save for later

Developing Web Applications using JavaServer Faces: Part 2

Packt
27 Oct 2009
5 min read
JSF Validation Earlier in this article, we discussed how the required attribute for JSF input fields allows us to easily make input fields mandatory. If a user attempts to submit a form with one or more required fields missing, an error message is automatically generated. The error message is generated by the <h:message> tag corresponding to the invalid field. The string First Name in the error message corresponds to the value of the label attribute for the field. Had we omitted the label attribute, the value of the fields id attribute would have been shown instead. As we can see, the required attribute makes it very easy to implement mandatory field functionality in our application. Recall that the age field is bound to a property of type Integer in our managed bean. If a user enters a value that is not a valid integer into this field, a validation error is automatically generated. Of course, a negative age wouldn't make much sense, however, our application validates that user input is a valid integer with essentially no effort on our part. The email address input field of our page is bound to a property of type String in our managed bean. As such, there is no built-in validation to make sure that the user enters a valid email address. In cases like this, we need to write our own custom JSF validators. Custom JSF validators must implement the javax.faces.validator.Validator interface. This interface contains a single method named validate(). This method takes three parameters: an instance of javax.faces.context.FacesContext, an instance of javax.faces.component.UIComponent containing the JSF component we are validating, and an instance of java.lang.Object containing the user entered value for the component. The following example illustrates a typical custom validator. package com.ensode.jsf.validators;import java.util.regex.Matcher;import java.util.regex.Pattern;import javax.faces.application.FacesMessage;import javax.faces.component.UIComponent;import javax.faces.component.html.HtmlInputText;import javax.faces.context.FacesContext;import javax.faces.validator.Validator;import javax.faces.validator.ValidatorException;public class EmailValidator implements Validator { public void validate(FacesContext facesContext, UIComponent uIComponent, Object value) throws ValidatorException { Pattern pattern = Pattern.compile("w+@w+.w+"); Matcher matcher = pattern.matcher( (CharSequence) value); HtmlInputText htmlInputText = (HtmlInputText) uIComponent; String label; if (htmlInputText.getLabel() == null || htmlInputText.getLabel().trim().equals("")) { label = htmlInputText.getId(); } else { label = htmlInputText.getLabel(); } if (!matcher.matches()) { FacesMessage facesMessage = new FacesMessage(label + ": not a valid email address"); throw new ValidatorException(facesMessage); } }} In our example, the validate() method does a regular expression match against the value of the JSF component we are validating. If the value matches the expression, validation succeeds, otherwise, validation fails and an instance of javax.faces.validator.ValidatorException is thrown. The primary purpose of our custom validator is to illustrate how to write custom JSF validations, and not to create a foolproof email address validator. There may be valid email addresses that don't validate using our validator. The constructor of ValidatorException takes an instance of javax.faces.application.FacesMessage as a parameter. This object is used to display the error message on the page when validation fails. The message to display is passed as a String to the constructor of FacesMessage. In our example, if the label attribute of the component is not null nor empty, we use it as part of the error message, otherwise we use the value of the component's id attribute. This behavior follows the pattern established by standard JSF validators. Before we can use our custom validator in our pages, we need to declare it in the application's faces-config.xml configuration file. To do so, we need to add a <validator> element just before the closing </faces-config> element. <validator> <validator-id>emailValidator</validator-id> <validator-class> com.ensode.jsf.validators.EmailValidator </validator-class></validator> The body of the <validator-id> sub element must contain a unique identifier for our validator. The value of the <validator-class> element must contain the fully qualified name of our validator class. Once we add our validator to the application's faces-config.xml, we are ready to use it in our pages. In our particular case, we need to modify the email field to use our custom validator. <h:inputText id="email" label="Email Address" required="true" value="#{RegistrationBean.email}"> <f:validator validatorId="emailValidator"/></h:inputText> All we need to do is nest an <f:validator> tag inside the input field we wish to have validated using our custom validator. The value of the validatorId attribute of <f:validator> must match the value of the body of the <validator-id> element in faces-config.xml. At this point we are ready to test our custom validator. When entering an invalid email address into the email address input field and submitting the form, our custom validator logic was executed and the String we passed as a parameter to FacesMessage in our validator() method is shown as the error text by the <h:message> tag for the field.
Read more
  • 0
  • 0
  • 1641

article-image-coldfusion-ajax-programming
Packt
27 Oct 2009
9 min read
Save for later

ColdFusion AJAX Programming

Packt
27 Oct 2009
9 min read
Binding When it comes to programming, the two most commonly used features are CFAJAXProxy and binding. The binding feature allows us to bind or tie things together by using a simpler technique than we would otherwise have needed to create. Binding acts as a double-ended connector in some scenarios. You can set the bind to pull data from another ColdFusion tag on the form. These must be AJAX tags with binding abilities. There are four forms of bindings, on page, CFC, JavaScript, and URL. Let's work through each style so that we will understand them well. We will start with on page binding. Remember that the tag has to support the binding. This is not a general ColdFusion feature, but we can use it wherever we desire. On Page Binding We are going to bind 'cfdiv' to pull its content to show on page binding. We will set the value of a text input to the div. Refer to the following code. ColdFusion AJAX elements work in a manner different from how AJAX is written traditionally. It is more customary to name our browser-side HTML elements with id attributes. This is not the case with the binding features. As we can see in our code example, we have used the name attribute. We should remember to be case sensitive, since this is managed by JavaScript. When we run the code, we will notice that we must leave the input field before the browser registers that there has been a change in the value of the field. This is how the event model for the browser DOM works. <cfform id="myForm" format="html"> This is my edit box.<br /> <cfinput type="text" name="myText"></cfform><hr />And this is the bound div container.<br /><cfdiv bind="{myText}"></cfdiv> Notice how we use curly brackets to bind the value of the 'myText' input box. This inserts the contents into 'div' when the text box loses focus. This is an example of binding to in-page elements. If the binding we use is tied to a hidden window or tab, then the contents may not be updated. CFC Binding Now, we are going to bind our div to a CFC method. We will take the data that was being posted directly to the object, and then we will pass it out to the CFC. The CFC is going to repackage it, and send it back to the browser. The binding will enable the modified version of the content to be sent to the div. Refer to the following CFC code: <cfcomponent output="false"> <cffunction name="getDivContent" returntype="string" access="remote"> <cfargument name="edit"> <cfreturn "This is the content returned from the CFC for the div, the calling page variable is '<strong>#arguments.edit#</strong>'."> </cffunction></cfcomponent> From the previous code, we can see that the CFC only accepts the argument and passes it back. This could have even returned an image HTML segment with something like a user picture. The following code shows the new page code modifications. <cfform id="myForm" format="html"> This is my edit box.<br /> <cfinput type="text" name="myText"></cfform><hr />And this is the bound div container.<br /><cfdiv bind="cfc:bindsource.getDivContent({myText})"></cfdiv> The only change lies in how we bind the cfdiv element tag. Here, you can see that it starts with CFC. Next, it calls bindsource, which is the name of a local CFC. This tells ColdFusion to wire up the browser page, so it will connect to the CFC and things will work as we want. You can observe that inside the method, we are passing the bound variable to the method. When the input field changes by losing focus, the browser sends a new request to the CFC and updates the div. We need to have the same number of parameters going to the CFC as the number of arguments in our CFC method. We should also make sure that the method has its access method set to remote. Here we can see an example results page. It is valid to pass the name of the CFC method argument with the data value. This can prevent exceptions caused by not pairing the data in the same order as the method arguments. The last line of the previous code can be modified as follows: <cfdiv bind="cfc:bindsource.getDivContent(edit:{myText})"></cfdiv> JavaScript Binding Now, we will see how simple power can be managed on the browser. We will create a standard JavaScript function and pass the same bound data field through the function. Whenever we update the text box and it looses focus, the contents of the div will be updated from the function on the page. It is suggested that we include all JavaScript rather than put it directly on the page. Refer to the following code: <cfform id="myForm" format="html"> This is my edit box.<br /> <cfinput type="text" name="myText"></cfform><hr />And this is the bound div container.<br /><cfdiv bind="javascript:updateDiv({myText})"></cfdiv><script> updateDiv = function(myEdit){ return 'This is the result that came from the JavaScript function with the edit box sending "<strong>'+myEdit+'</strong>"'; } </script> Here is the result of placing the same text into our JavaScript example. URL Binding We can achieve the same results by calling a web address. We can actually call a static HTML page. Now, we will call a .cfm page to see the results of changing the text box reflected back, as for CFC and JavaScript. Here is the code for our main page with the URL binding. <cfform id="myForm" format="html"> This is my edit box.<br /> <cfinput type="text" name="myText"></cfform><hr />And this is the bound div container.<br /><cfdiv bind="url:bindsource.cfm?myEdit={myText}"></cfdiv> In the above code, we can see that the binding type is set to URL. Earlier, we used the CFC method bound to a file named bindsource.cfc. Now, we will bind through the URL to a .cfm file. The bound myText data will work in a manner similar to the other cases. It will be sent to the target; in this case, it is a regular server-side page. We require only one line. In this example, our variables are URL variables. Here is the handler page code: <cfoutput> 'This is the result that came from the server page with the edit box sending "<strong>#url.myEdit#</strong>"'</cfoutput> This tells us that if there is no prefix to the browse request on the bind attribute of the <cfdiv> tag, then it will only work with on-page elements. If we prefix it, then we can pass the data through a CFC, a URL, or through a JavaScript function present on the same page. If we bind to a variable present on the same page, then whenever the bound element updates, the binding will be executed. Bind with Event One of the features of binding that we might overlook its binding based on an event. In the previous examples, we mentioned that the normal event trigger for binding took place when the bound field lost its focus. The following example shows a bind that occurs when the key is released. <cfform id="myForm" format="html"> This is my edit box.<br /> <cfinput type="text" name="myText"></cfform><hr />And this is the bound div container.<br /><cfdiv bind="{myText@keyup}"></cfdiv> This is similar to our first example, with the only difference being that the contents of the div are updated as each key is pressed. This works in a manner similar to CFC, JavaScript, and URL bindings. We might also consider binding other elements on a click event, such as a radio button. The following example shows another feature. We can pass any DOM attribute by putting that as an item after the element id. It must be placed before the @ symbol, if you are using a particular event. In this code, we change the input in order to have a class in which we can pass the value of the class attribute and change the binding attribute of the cfdiv element. <cfform id="myForm" format="html"> This is my edit box.<br /> <cfinput type="text" name="myText" class="test"> </cfform><hr />And this is the bound div container.<br /><cfdiv bind="{myText.class@keyup}.{myText}"></cfdiv> Here is a list of the events that we can bind. @click @keyup @mousedown @none The @none event is used for grids and trees, so that changes don't trigger bind events. Extra Binding Notes If you have an ID on your CFForm element, then you can refer to the form element based on the container form. The following example helps us to understand this better. Bind = "url:bindsource.cfm?myEdit={myForm:myText}" The ColdFusion 8 documents give the following guides in order to specify the binding expressions. cfc: componentPath.functionName (parameters) The component path cannot use a mapping. The componentPath value must be a dot-delimited path from the web root or the directory that contains the page. javascript: functionName (parameters) url: URL?parameters ULR?parameters A string containing one or more instances of {bind parmeter}, such as {firstname}.{lastname}@{domain} The following table represents the supported formats based on attributes and tags: Attribute Tags Supported Formats Autosuggest cfinput type="text" 1,2,3 Bind cfdiv, cfinput, cftextarea 1,2,3,5 Bind cfajaxproxy, cfgrid, cfselect cfsprydataset, cftreeitem 1,2,3 onChange cfgrid 1,2,3 Source cflayoutarea, cfpod, cfwindow 4
Read more
  • 0
  • 0
  • 6873

article-image-overview-cherrypy-web-application-server-part1
Packt
27 Oct 2009
6 min read
Save for later

Overview of CherryPy - A Web Application Server (Part1)

Packt
27 Oct 2009
6 min read
Vocabulary In order to avoid misunderstandings, we need to define a few key words that will be used. Keyword Definition Web server A web server is the interface dealing with the HTTP protocol. Its goal is to transform incoming HTTP requests into entities that are then passed to the application server and also transform information from the application server back into HTTP responses. Application An application is a piece of software that takes a unit of information, applies business logic to it, and returns a processed unit of information. Application server An application server is the component hosting one or more applications. Web application server A web application server is simply the aggregation of a web server and an application server into a single component. CherryPy is a web application server. Basic Example To illustrate the CherryPy library we will go through a very basic web application allowing a user to leave a note on the main page through an HTML form. The notes will be stacked and be rendered in a reverse order of their creation date. We will use a session object to store the name of the author of the note. Each note will have a URI attached to itself, of the form /note/id. Create a blank file named note.py and copy the following source code. #!/usr/bin/python# -*- coding: utf-8 -*# Python standard library importsimport os.pathimport time################################################################The unique module to be imported to use cherrypy###############################################################import cherrypy# CherryPy needs an absolute path when dealing with static data_curdir = os.path.join(os.getcwd(), os.path.dirname(__file__))################################################################ We will keep our notes into a global list# Please not that it is hazardous to use a simple list here# since we will run the application in a multi-threaded environment# which will not protect the access to this list# In a more realistic application we would need either to use a# thread safe object or to manually protect from concurrent access# to this list###############################################################_notes = []################################################################ A few HTML templates###############################################################_header = """<html><head><title>Random notes</<title><link rel="stylesheet" type="text/css" href="/style.css"></link></head><body><div class="container">"""_footer = """</div></body></html>"""_note_form = """<div class="form"><form method="post" action="post" class="form"><input type="text" value="Your note here..." name="text"size="60"></input><input type="submit" value="Add"></input></form></div>"""_author_form = """<div class="form"><form method="post" action="set"><input type="text" name="name"></input><input type="submit" value="Switch"></input></form></div>"""_note_view = """<br /><div>%s<div class="info">%s - %s <a href="/note/%d">(%d)</a></div></div>"""################################################################ Our only domain object (sometimes referred as to a Model)###############################################################class Note(object):def __init__(self, author, note):self.id = Noneself.author = authorself.note = noteself.timestamp = time.gmtime(time.time())def __str__(self):return self.note################################################################ The main entry point of the Note application###############################################################class NoteApp:"""The base application which will be hosted by CherryPy"""# Here we tell CherryPy we will enable the session# from this level of the tree of published objects# as well as its sub-levels_cp_config = { 'tools.sessions.on': True }def _render_note(self, note):"""Helper to render a note into HTML"""return _note_view % (note, note.author,time.strftime("%a, %d %b %Y %H:%M:%S",note.timestamp),note.id, note.id)@cherrypy.exposedef index(self):# Retrieve the author stored in the current session# None if not definedauthor = cherrypy.session.get('author', None)page = [_header]if author:page.append("""<div><span>Hello %s, please leave us a note.<a href="author">Switch identity</a>.</span></div>"""%(author,))page.append(_note_form)else:page.append("""<div><a href="author">Set youridentity</a></span></div>""")notes = _notes[:]notes.reverse()for note in notes:page.append(self._render_note(note))page.append(_footer)# Returns to the CherryPy server the page to renderreturn page@cherrypy.exposedef note(self, id):# Retrieve the note attached to the given idtry:note = _notes[int(id)]except:# If the ID was not valid, let's tell the# client we did not find itraise cherrypy.NotFoundreturn [_header, self._render_note(note), _footer]@cherrypy.exposedef post(self, text):author = cherrypy.session.get('author', None)# Here if the author was not in the session# we redirect the client to the author formif not author:raise cherrypy.HTTPRedirect('/author')note = Note(author, text)_notes.append(note)note.id = _notes.index(note)raise cherrypy.HTTPRedirect('/')class Author(object):@cherrypy.exposedef index(self):return [_header, _author_form, _footer]@cherrypy.exposedef set(self, name):cherrypy.session['author'] = namereturn [_header, """Hi %s. You can now leave <a href="/" title="Home">notes</a>.""" % (name,), _footer]if __name__ == '__main__':# Define the global configuration settings of CherryPyglobal_conf = {'global': { 'engine.autoreload.on': False,'server.socket_host': 'localhost','server.socket_port': 8080,}}application_conf = {'/style.css': {'tools.staticfile.on': True,'tools.staticfile.filename': os.path.join(_curdir,'style.css'),}}# Update the global CherryPy configurationcherrypy.config.update(global_conf)# Create an instance of the applicationnote_app = NoteApp()# attach an instance of the Author class to the main applicationnote_app.author = Author()# mount the application on the '/' base pathcherrypy.tree.mount(note_app, '/', config = application_conf)# Start the CherryPy HTTP servercherrypy.server.quickstart()# Start the CherryPy enginecherrypy.engine.start() Following is the CSS which should be saved in a file named style.css and stored in the same directory as note.py. html, body {background-color: #DEDEDE;padding: 0px;marging: 0px;height: 100%;}.container {border-color: #A1A1A1;border-style: solid;border-width: 1px;background-color: #FFF;margin: 10px 150px 10px 150px;height: 100%;}a:link {text-decoration: none;color: #A1A1A1;}a:visited {text-decoration: none;color: #A1A1A1;}a:hover {text-decoration: underline;}input {border: 1px solid #A1A1A1;}.form {margin: 5px 5px 5px 5px;}.info {font-size: 70%;color: #A1A1A1;} In the rest of this article we will refer to the application to explain CherryPy's design.
Read more
  • 0
  • 0
  • 3751
article-image-managing-student-work-using-moodle-part-3
Packt
27 Oct 2009
5 min read
Save for later

Managing Student Work using Moodle: Part 3

Packt
27 Oct 2009
5 min read
Specifying Custom Grades Currently, I'm marking my projects out of 100 but, as I mentioned previously, that's not how they are graded. According to the syllabus, I can only give students one of four grades: Distinction, Merit, Pass, and Referral. So how do you specify your own grades? Let's learn how to do that now. Time for Action – Create a Custom Grade Scale Return to your course front page and look for Grades in the Administration block: Click on Grades and you'll be taken to the Grader report page. We are now in the Moodle grade book. I'm not going to worry too much about all of the features in the grade book for the moment—but while you are there you might like to spend a little time having a look. As with anything else in Moodle, you can't do any damage by doing something by mistake. At the top left of the page, you will find a list of view options: From the list select Scales. You're now taken to the scales page. We need to add a new scale, so press the Add a new scale button in the center of the page. On the following page, give your new scale a name and in the Scale box you can specify the possible grades contained in your new scale. Separate the grades with commas—no spaces. Make sure you specify the grades in order of increasing value: You don't have to worry about a description. Are the grades you are specifying here used for grading in other courses? If you tick the Standard scale box then your scale will be made available to teachers on all courses. When you are done, press the Save changes button. Your new scale is listed on the scales page. Because I didn't make my new scale a standard scale, it's listed as a custom scale: What Just Happened? I don't give students a numerical grade for the Backyard Ballistics projects. The syllabus requires a qualitative grade, but luckily the system makes it easy to import my own custom grade scales. All I need to do now is modify my two assignment activities to use the new scale. That only involves a few clicks, so let's do that now... Time for Action – Grading Using a Custom Scale Return to your course front page and click on the update icon next to the assignment you want to change to use your new custom scale. The Editing assignment page is displayed. Scroll down to the Grade drop-down list. Click on the list. Scroll up if you need to, because the custom scale we want to use will be towards the very top: With the new grading scale selected, scroll down to the bottom of the page and press the Save and return to course button. That's it. You will now be able to grade your project using your new scale. What Just Happened? We've just modified the assignment to use our new grading scale. All that remains now is to demonstrate how you use it. Now that we are back at the course front page, click on the link to the assignment itself to display the assignment's main page (displaying the description of the task we've set). Click on the View submitted assignments link in the top right-hand corner of the page to take you to the Submissions page. Choose a student and down in the Status column click on the Grade link. If you've already marked that student then the link will say Update: Click on the link to open the Feedback dialog. Click on the Grade list at the top right-hand corner of the page to display the grades you can give to this piece of work. The grades listed are the ones from our new custom grade scale: More Uses for Moodle Assignments We aren't limited to using the four assignment activities just for major projects. Here are some more ideas on using the assignment activity to convert your current teaching over to Moodle... Include an online text assignment for discursive tasks, for example writing a short story or for short essay homework tasks. If you're able to display the submissions page of a single file assignment to the class during teaching time, keep refreshing the page as homework is submitted. You'll quickly find that there'll be a race on to be the first to hand their homework in. You could easily turn that into a game for younger students. Use an Offline activity to manage the grades of any task you set for your students—homework handed in on paper, for example. You don't have to confine yourself to just projects. On that last point, there is another way of managing grades directly. We've already been briefly into the Moodle Grader report when we set up our custom scale. Let's revisit that page to see how we can set up custom grading items. Grading Students on Core Competencies Often, as educators, we need to grade assignments on core competencies, otherwise known as key skills or goals. That certainly applies to my syllabus: A percentage of the final grade for my course includes marks for numeracy, literacy, and the use of ICT. Because we are converting to Moodle, and in Moodle-speak, the competencies that I am grading are called "outcomes", in this final section, we learn how to specify the core competencies we need to grade, and how we can then grade students on them. There are pros and cons of converting to Moodle, specifically: I can choose to enable outcomes on a per assignment basis, but you can't use the default numeric grading scale to grade outcomes, only standard and custom grading scales (like my custom Backyard Ballistics scale that I created in Time for action – Create a Custom Grade Scale).
Read more
  • 0
  • 0
  • 1537

article-image-understanding-model-development-process-ibm-cognos-8
Packt
27 Oct 2009
23 min read
Save for later

Understanding the Model Development Process in IBM Cognos 8

Packt
27 Oct 2009
23 min read
The process The Model Development Process is a proven step-by-step approach for designing and deploying planning models in an organization. This process enables us to chart various activities involved in identifying the organization's planning requirements in order to devise functional and efficient modeling solutions. The following diagram illustrates the Model Development Process and shows the typical stakeholders and IBM Cognos tools involved in the process: In the previous diagram, we saw four typical roles in organizations that are currently using the IBM Cognos Planning model and applications. They are described briefly as: Analyst Modeler: Responsible for gathering business requirements—designing, building, and testing Analyst models, and managing the data workflow within the model. System or Contributor Administrator: Responsible for creating, maintaining, and securing Contributor applications translated from Analyst models. Business Users: Responsible for entering, submitting, and reviewing planning data. Users will be referred to as the Business Users or Planners. Support Team: Responsible for maintaining models and applications, during or after the initial roll-out. Considerations for building an Analyst planning model When purchasing a vehicle, you may consider many attributes before finalizing your decision. For example, you may determine the type of vehicle to buy (sedan, minivan, and so on) or may evaluate the commuting needs. Likewise, before beginning to build the planning model, you must consider some key factors about our planning processes. To build and deploy the correct planning models in an organization, Project Managers, Business Users, Modelers, and other project stakeholders should consider the following factors at the initial stage of the planning project: Planning functional models Planning cycles and horizons Planning approaches Planning functional models Every business organization uses a variety of planning models to produce its business plans. A number of planning models are common in most of the organizations. For example, many business organizations have some form of revenue, cost of sales, payroll, capital, and operating expense models. On the other hand, some models are unique to a particular industry and trade. For example, a pharmaceutical company may have a Clinical trial or R&D model, or an international shipping company may need an aircraft fleet cost-control model. Other models may reflect an organization's business focus. The organization may develop a model to project and control a particular cost that is critical to its business strategy. For instance, a beverage company that places a heavy emphasis on brand recognition may have a separate marketing model, or a consulting company that routinely rotates its employees to offices around the world may have a separate travel model. Whatever purpose the models serve, it is important that you understand the rationale underlying the organization's use of them, so that you can build models that are more closely aligned to the organization's business needs. Planning cycles and horizons You also need to be aware of the organization's planning cycle and horizon. The planning cycle refers to the frequency by which an organization develops or updates its business plans. The planning horizon refers to how far into the future the organization plans. An organization may have multiple planning cycles, but may only plan for a single time horizon. The frequency with which an organization plans depends on many factors. For instance, organizations that operate in highly dynamic and competitive environments, such as technology companies, tend to have more frequent planning cycles. Companies in more stable environments, such as an alkaline batteries manufacturing company, tend to have less frequent cycles. Planning horizons may be driven by the organization's strategic focus or the nature of the business. For instance, the planning horizon of a pharmaceutical company's R&D plan may span up to 20 years, which is the amount of time that a clinical drug may take to get from inception to testing and eventually to marketability. A construction company may require multi-year plans to coincide with the time it takes to construct a building. More commonly, organizations develop a plan once a year in the form of an annual budget. The organization then revisits and calibrates the plan mid-year, after several months of actual data has been gathered. Actual data is used to measure year-to-date performance against the plan, so that the organization can forecast for the remainder of the year. The typical planning horizon is twelve months, usually the organization's fiscal year. If a long-range plan exists, the long-range plan is updated with changes to the annual plan or forecast. Planning cycle refers to the frequency at which an organization develops or updates its business plans. Planning horizon refers to how far into the future the organization plans. Knowing an organization's planning cycle and horizon is important when building a model. Many organizations use cycle-specific models because the business assumptions and calculations tend to differ between planning cycles. For instance, an organization can have a P&L model for the annual budget and another for the mid-year forecast because an annual budget and mid-year forecast usually require different data and calculation requirements. Knowing an organization's planning cycle can give you an insight into how you may want to build your models. The organization may start with detailed plans once or twice a year. If rolling forecasts are prepared, the forecasts may be done at a higher level, for instance, at an account or organizational summary level. This means that you may have to create a detailed model and a summary model. Knowing the planning horizon enables you to construct the appropriate timescale that can be used by other models. An organization that plans its revenue every quarter may also plan its expenses in the same way. An efficient planning model is built on standard data structures, such as timescale. Thus, timescales are an important consideration because they can be shared across several of the organization's planning models. Planning approaches Business organizations can use different approaches to plan their budgets and forecasts. You need to consider these approaches when building the model, as these approaches dictate how the model will be designed and deployed. Examples of common approaches are as follows: Zero-based budgeting: Each planner prepares estimates of their proposed revenue or expenses for a specific period of time as if they were planning for the first time. By starting from scratch at each budget cycle, for example, managers are required to take a closer look at all of their revenues and expenses. Driver based: Driver based planning models typically calculate plan numbers by adding, subtracting, or multiplying various drivers or metrics. Examples of drivers: number of units sold, price of a product, and so on. Top-down: Top Upper-level management sets the targets and pushes them to lower management who then pushes them further down the organization. Then the plans for achieving the targets are submitted up the chain of command for review and approval. Bottom-up: Lower-level management prepares the plans and then submits them up the chain of command for review and approval. The approval and rejection process follows until the plan and finalized. Designing the model template in Analyst A planning model is a set of Analyst objects whose purpose is to generate specific plans using a variety of data inputs, assumptions, and calculations.  In practice, a model is named after the output it produces. An output can be a specific budget for product lines or it can be a category of expenses consisting of several general ledger accounts, such as payroll. Once you have identified the model output, break it down into its inputs, assumptions, and calculations. For example, a salary plan may be the outcome of the inputs of employees and positions, their current salary, earned merit increases, and bonuses. The salary for newly-hired staff may be assumed based on their position. To produce the salary plan, the model would calculate the merit increases and bonuses for each employee by multiplying the salary by the merit and bonus percentages and then by adding the results to the salary. Then it would pull the appropriate salary for each new hire depending on position. Finally, the model would aggregate all of the employees' and new hires' salaries to come up with the salary plan. In this simplified example, four model functions are apparent: inputs, assumptions, calculations, and outputs. In fact, you can say that a model is a collection of these four functions. The IBM Cognos Planning Analyst tool allows you to build objects that collect inputs from users, designate assumed values, and perform calculations on them in order to produce the expected output. Flowcharting the model structure Before building an effective planning model, it is important to develop a detailed flowchart that logically illustrates all of the model's structural components. Just as an architect develops a building's blueprints before even breaking the ground, you must begin with the model's blueprints. Often, many modelers skip this important step and begin constructing the objects, without a clear path to the final outcome. Unfortunately, such haste results in a disorganized and inefficient model. A poorly-designed model can adversely impact an application's performance and cause a downstream effect on user productivity. The consequence can be severe. When the model is deployed to hundreds or thousands of users, a single instance of inefficiency will multiply at an equivalent scale. Flowcharting helps you to avoid these problems. It gives you a glimpse of the final product and forces you to think through the various factors and issues that must be addressed before starting to build the model. A disciplined and methodical approach can steer you away from many of model building's hidden pitfalls. Indeed, a well thought out flowchart can cut the build time significantly by minimizing rework and trial and error. Flowcharting can lead you to uncovering the important design elements, such as the dimensions, datastore, and data flow. A good flowchart should show the sources of data inputs, and whether they are entered by the planner or originate from other data sources such as an ERP system or a general ledger system. The flowchart should also illustrate the way that data will be stored and used, how it enters the model, and how it flows from source to target. Finally, the flowchart should describe the different ways in which data can be viewed so that you can gather the various dimensions that need to be included in the model. For instance, data can be viewed by cost center, departments, or profit centers. Alternatively, it can be viewed across time (days, weeks, months, years) or by versions (this year, last year, plan, scenarios). Some developers may refer to model flowcharts as model schematics or Data Flow Diagrams (DFD). You, the Modeler, typically initiate this design step in the model development process after learning and understanding the key business planning requirements. You then 'white-board' the design of the model template, and then document the design specification in a document called a Detailed Design Specification (DDS). Finally, you take the design specification and implement it in IBM Cognos Planning Analyst using the Analyst's features and functionality. The concept of multi dimensionality IBM Cognos Planning is based on a multi-dimensional data structure in which data is organized around specific attributes, or dimensions. In the following table, data is organized around Account, Year, Version, Cost Center, and Month. Each record in the table contains data by account, year, version, cost center, and month. One of the most common ways of presenting multi-dimensional data is in the form of a cube. In a multi-dimensional cube, data is displayed as one slice at a time along two or more dimensions. Each slice represents a subset of the population. Those familiar with Excel pivot tables should have little problem grasping this concept. However, those who are only familiar with spreadsheets can still find some similarities. In a spreadsheet, the rows and columns are actually two separate dimensions. A third dimension, the worksheet, gives you a three-dimensional view of data. If you enter data into the first cell in a spreadsheet, you are actually entering the data along three dimensions—Sheet 1, Column A, and Row 1. Hence, when you reference that cell, Excel denotes it as      Sheet1!A1. A multi-dimensional cube lets you view data the same way. But a cube can have several dimensions. Each dimension contains a list of related data such as accounts, version, cost center, or time period. When two or more dimensions intersect, the intersection represents a record or view of the data. For instance, a cost center dimension may list all the cost centers in the organization. A second dimension lists a group of expense accounts, a third lists 12 months, and a fourth lists the version (Plan or Actual). The intersection of these dimensions gives you data by cost center, by account, by month, and by version. The following Excel pivot table is an example of a multi-dimensional cube. Here you see a slice of the cube with the following dimensions: Account, Cost Center, Month, and Version. In a multi-dimensional cube, you can arrange data in a variety of ways by swapping rows, columns, and pages. This is a powerful feature that facilitates in-depth data analysis. Those who have worked with multi-dimensional cubes understand their benefits. Multi-dimensional cubes can help you sift through masses of data to find valuable information. IBM Cognos Planning takes multi dimensionality a step further by leveraging its features to enforce rules and standards in order to make model maintenance easier. Analyst is the tool that lets you create the planning template that the users will use to enter their plans, while Contributor is the tool that lets you replicate the templates and deploy them to a number of users based on a defined hierarchy. The plans are stored in a central database, and users connect to it through the Web. In a spreadsheet environment, similarities exist. You have a master template that you can use to build the worksheets. The worksheets are stored in a central folder, within sub-folders that are organized according to a hierarchy. Users connect to the shared folder to access their worksheets.     Understanding dimensions, datastore, and data flow Analyst objects are the building blocks of the planning model. These objects enable you to define the data structure, store and calculate the data, and move data from source to targets. There are a host of objects in Analyst, each offering useful capabilities. However, the key objects are the D-List, D-Cube, and D-Link. These objects are indispensable to a model and thus deserve special attention. Determining dimensions: D-List The D-List is the basic building block of the model. In Analyst, dimensions are referred to as D-Lists. Each item in a D-List represents an attribute of the data. In a D-List, we decide what data to include in the model and how the data will behave. The data could be something that will be entered by the planner; it could be pre-populated, or it could be calculated. For example, to build a model of your personal expenses, you may have a list of expense categories (travel, food, and entertainment), you may want to track your spending over time (month, quarter, and year), and you may want to compare different versions of spending (actual and planned). Each of these lists of items could be a D-List. In the Spending Category D-List, you might include a Total that sums up Travel, Food, and Entertainment (see the following screenshot). In the Versions D-List, you may want a "Variance" between actual and planned values. There is virtually no restriction to the type of data that you can include. However there are certain principles to adhere to when creating D-Lists. The first step in constructing a model is to identify the dimensions that will be used. There are many sources of information that will give you an idea of the dimensions that you need. Data entry templates from the organization's existing planning systems or Excel spreadsheets can suggest many ways in which data is gathered. The spreadsheet can also reveal the calculations used. Performance reports can be used to determine what the model outputs will be. Often, simply inquiring about the business can be a good start. Consider that you're working on a project that requires you to design and build a revenue forecasting model for a Fortune 100 global consumer electronics retailer. One approach to determining the dimensions of this forecasting model is to ask the following questions: What does the company sell? The dimensions could contain a list of consumer electronics products, such as MP3 players and laptops, product categories such as audio and computers, or even brands. Who is the company selling to? The retailer's customer list could be a dimension. Where does the company operate? Dimensions may contain a list stores, states, cities, countries, global regions, or market segments. What is the forecasting timeline? The timeline dimensions may be weeks, months, quarters, or years. The words "D-List" and "dimension" are often used interchangeably. When used in the context of a cube, "dimension" is often more appropriate. Building the datastore: D-Cubes Whereas the D-List is where the data is defined, the D-Cube is where the data is stored. After you have decided what data will be included in the model, you determine how the data will be stored. The D-Cube is formed by two or more D-Lists. A typical planning model consists of several cubes. The cubes store a particular set of data and perform a specific function. For example, an Employee cube may store data about employees. A P&L cube may contain revenue and expense data. D-Cubes can be functionally classified as either an input cube that allows data entry, a calculation cube that processes data, or an output cube that displays the result. The Employee cube can be broken into an Employee Input cube (see the following example), Employee Calculation cube, and Employee Summary cube. The words "D-Cube" and "cube" are often used interchangeably. Except for the terminology, there is no distinction between the two. "D-Cubes" are usually used in an Analyst setting, but "cubes" can work as well. The key to building D-Cubes is to understand their primary function. Is the cube a place where planners will enter data? Will it be used simply to stage data? Will it be used to calculate inputs and feed the result somewhere else? Will it be used to present data in a report format for reviewers? These important questions must be answered before building the cube. Another factor to think about is data. Data is stored in a cube. Consequently, the cube structure needs to follow the format of the data source that will be feeding it. As a modeler, you need to understand what type of data will be going into the model. For instance, planners need data to compare and analyze planning and actual information. They would like to see actual year-to-date sales compared to next-year projections. During the initial design process, you may decide to work with the data provider to review the source data and develop a process to extract, load, and validate data in planning models. Perhaps the most important consideration is size. In a multi-dimensional data structure, size is always a constraint. Size has a direct impact on performance; the greater the size, the more time it will take to process data and transmit it over the web. In fact, performance can be such a tremendous constraint that it affects the way the model is designed. Controlling data flow: D-Links In a model that shares data among several cubes, data must flow from one cube to another. The D-link is an object that moves data. Similar to a data transformation or ETL tool, the D-Link maps dimension items in the source to dimension items in the target, enabling you to control the flow of data within the model. For multi-dimensional cubes where data sparseness can be a problem, the D-Link has a practical purpose. The D-Link allows you to break a large cube into smaller, specialized cubes while still making the same data available. Most models use function-specific cubes, where outputs from one cube are inputs to another. The D-Link connects input, calculation, and output cubes, bringing them together to allow the seamless movement of data. Any cube that requires data in order to perform its function can retrieve data without going outside of the model. Because data can be reused, it only needs to enter the model once, thereby simplifying the data import process. The D-Link's ability to transport data is not limited to cubes. D-links can import data from a database, an ASCII file, an Excel spreadsheet, or a Contributor application. The words "D-Link" and "link" are often used interchangeably. Except for the terminology, there is no distinction between the two. "D-Link" is usually used in the context of Analyst. What makes an optimal model? The saying goes: "There is more than one way to skin a cat." The same can be said about model building. There are myriad ways to create the same output by using a combination of inputs, assumptions, and calculations. IBM Cognos Planning allows you to create highly complex models using its advanced forecasting algorithms and scenario planning facilities. With this capability at your disposal, you may be tempted to build a model that "does everything at the push of the button". While such automation can appear impressive, it is often accompanied with many problems. Complex models make ownership and maintenance difficult. A highly-customized model can become so inflexible that when it's time to enhance it, starting from scratch is an easier option, rather than building on its current form. Support and maintenance can also become a nightmare when you need to go through a laundry list of tasks to prepare for the next cycle. The tendency towards over-automation and over-customization, must be tempered with caution. More often than not, the model that "does everything" also requires everything to support and maintain it. So what is an optimal model? The answer is one that delivers planning information in a timely manner at the lowest possible cost. Although delivering better information has always been at the forefront of every planning project, the cost of delivering it tends to be elusive. To be sure, the financial cost of the system is closely monitored, but there are costs hidden within the system's inner workings that cannot be quantified and are often left to persist. The cost can take many forms: What is the cost of a poorly designed model? What is the cost of a Contributor application taking twice as long to process? What is the cost of thousands of users waiting an extra 10 seconds each time they can download a planning model? These costs must be taken into consideration when building the model. You, as a Modeler, must not only build a model that does its job, you must do so without placing an undue burden on these cost factors. Principles of model building If you ask ten people what makes an optimal model, you are likely to get ten different answers. This is not surprising. The quest for the one-size-fits-all formula has been a long one, owing mostly to the differences in the ways that organizations plan, but also to the openness of the tool and the absence of a shared body of knowledge. Although there are no hard and fast rules, there are three guiding principles that can help lead you down the correct path. Efficiency Performance Maintenance Efficiency An optimal model must be built with an eye towards efficiency. An efficient model is one that takes the shortest path to performing its task. Usually this means fewer objects in the model. But it could mean other things: Data flows in one direction, D-Cubes perform clear and specific functions, calculations are more intuitive and easy to understand, D-Lists contain as few dimension items as possible, redundancies are non-existent, and data is organized in a logical fashion. Efficiency and simplicity go hand-in-hand. Simplicity eliminates clutter. It begs the question: Is this absolutely necessary? To a savvy Modeler, the concept of simplicity may be counter-intuitive and run contrary to his nature. Yet the ability to take complex processes and re-engineer them down to a few moving parts is indispensable to model building. Indeed, it is a higher skill, one that compels you to abandon conventional wisdom, think out of the box, and explore unfamiliar territories. Performance An optimal model is one that performs its task faster using the same resources. Performance combines effectiveness with timeliness. This means delivering the right information at the right time. The model must be able to process data and respond to user requests within reasonable time and without unnecessary delays. Although not everyone will agree on what "reasonable time" means, everyone can agree on what constitutes "unnecessary delays". It is the difference between how the model performs and how it should perform. A model that is built on a weak foundation almost always bears extra processing overhead that takes additional time. There are essentially three areas where performance is most visible: Application processing Web client access Web client processing Application processing refers to the server batch process that implements changes to the model, or loads data. Web client access is the point where users connect to the database to retrieve or save their plans. Web client processing is where users actually work with their planning templates, entering data and switching from cube to cube. All of these areas have a direct impact on user productivity, so that any lag in performance creates cost in some form. Maintenance An optimal model is one that requires the least amount of effort to set up and maintain. In a constantly-changing business landscape, organizations must be able to adapt to new environments quickly. Competitive pressures may push organizations to shorten their planning cycles or drive them to a new strategic direction. Planning models must reflect new realities in order to accurately project the future. They must therefore be flexible and easy to maintain. An optimal model is built on the premise that change is constant. The model must allow for its assumptions and calculations to change without a complete overhaul. It must use standards and share objects so that changes can cascade rapidly throughout its various parts. The model should enable a non-developer to easily take ownership of it without the need for advanced training. These principles can be self-reinforcing. For instance, an efficient model usually performs faster and is easier to maintain. However, they are not exclusive and trade-offs can occur. When two good approaches contradict, you must weigh the benefit of one over the other and accept the trade-off. In a way, modeling is an art. No strict rules govern how a model should be built, lending the entire exercise to one's own creativity. As a modeler, you should look to these principles for guidance, while keeping a close watch on other factors. In the final analysis, the planning system, like any other system, must be viewed in the light of its benefits, as well as its cost.  
Read more
  • 0
  • 0
  • 5771
Modal Close icon
Modal Close icon