Search Results

Search found 775 results on 31 pages for 'a star'.

Page 12/31 | < Previous Page | 8 9 10 11 12 13 14 15 16 17 18 19  | Next Page >

  • Details on Oracle's Primavera P6 Reporting Database R2

    - by mark.kromer
    Below is a graphic screenshot of our detailed announcement for the new Oracle data warehouse product for Primavera P6 called P6 Reporting Database R2. This DW product includes the ETL, data warehouse star schemas and ODS that you'll need to build an enterprise reporting solution for your projects & portfolios. This product is included on a restricted license basis with the new Primavera P6 Analytics R1 product from Oracle because those Analytics are built in OBIEE based on this data warehouse product.

    Read the article

  • This Week's News From the Green Data Center Management Front

    Among this week's developments in green data center management: myriad federal and state tax credits are now available for Green IT projects related to data centers; the EPA is finalizing its Energy Star program for data centers; and Numara Software has a way to help you better green your data center.

    Read the article

  • Security Controls on data for P6 Analytics

    - by Jeffrey McDaniel
    The Star database and P6 Analytics calculates security based on P6 security using OBS, global, project, cost, and resource security considerations. If there is some concern that users are not seeing expected data in P6 Analytics here are some areas to review: 1. Determining if a user has cost security is based on the Project level security privileges - either View Project Costs/Financials or Edit EPS Financials. If expecting to see costs make sure one of these permissions are allocated.  2. User must have OBS access on a Project. Not WBS level. WBS level security is not supported. Make sure user has OBS on project level.  3. Resource Access is determined by what is granted in P6. Verify the resource access granted to this user in P6. Resource security is hierarchical. Project access will override Resource access based on the way security policies are applied. 4. Module access must be given to a P6 user for that user to come over into Star/P6 Analytics. For earlier version of RDB there was a report_user_flag on the Users table. This flag field is no longer used after P6 Reporting Database 2.1. 5. For P6 Reporting Database versions 2.2 and higher, the Extended Schema Security service must be run to calculate all security. Any changes to privileges or security this service must be rerun before any ETL. 6. In P6 Analytics 2.0 or higher, a Weblogic user must exist that matches the P6 username. For example user Tim must exist in P6 and Weblogic users for Tim to be able to log into P6 Analytics and access data based on  P6 security.  In earlier versions the username needed to exist in RPD. 7. Cache in OBI is another area that can sometimes make it seem a user isn't seeing the data they expect. While cache can be beneficial for performance in OBI. If the data is outdated it can retrieve older, stale data. Clearing or turning off cache when rerunning a query can determine if the returned result set was from cache or from the database.

    Read the article

  • How far is too far?

    - by David Dorf
    Previously I've talked about Safeway's personalized pricing as well as Target's use of analytics to learn about customers.  Then last week I read about Orbitz tailoring their hotel offers based on the browser used.  (Orbitz claims that Mac users are 40% more likely than PC users to book four- or five-star hotels.)  So just how far is too far when tailoring the retail experience? When most consumers read about these types of tactics, they tend to feel violated, as if someone was reading their personal diary.  Nobody wants to be tricked into buying things.  Walking into a grocery store and seeing crates of apples stacked high looks enticing, but the crates are just for display and the apples may be over a year old.  Even though its much cheaper to print markdown tags, many retailers manually write the price tags because consumers think they deal is better if the price is hand-written. The technology already exists to personalize prices and experiences for consumers.  People get upset thinking they paid more for something than a neighbor, but it already happens all the time with cars, flights, and the use of loyalty programs and coupons. There are many variables at play for any purchase.  They only difference is that the customer segments are getting smaller, sometimes reaching a size of one. There's two ways to look at this.  Retailers have always manipulated the environment to get consumers to buy more -- or -- Retailers are getting better at tuning the shopping experience for consumers.  I choose the latter, and so do most consumers by spending their money in the stores they like.  Consumers like to see fresh flowers at the entrance to the grocery store, and they like to see specials scrawled on chalkboards. The key is making sure that consumers benefit from the experience as well.  I'm willing to give up some personal information in exchange for discounts and more relevant marketing, and the next-generation of shoppers are even less concerned about privacy.  Retailers need to use all the tools available to differentiate their offers and connect with their customers. So if Orbitz wants to put three-star hotels at the top of the list for me because I'm using a PC, that's fine by me.

    Read the article

  • Tag Cloud with jQuery Effect

    Tag Cloud WebControl built on the Star Field jQuery plug-in...Did you know that DotNetSlackers also publishes .net articles written by top known .net Authors? We already have over 80 articles in several categories including Silverlight. Take a look: here.

    Read the article

  • Florida Hospital Takes Charge of Their Destiny with Drupal

    <b>CMS Wire:</b> "In August 2007, Florida hospital hired a "rock star" physician. With this hire, a series of events was triggered that would end up with Drupal (news, site) hosting over 125 department and team intranet sites, over 40 externally-facing marketing sites and a growing number of other applications."

    Read the article

  • This Week on the Green Data Center Management Front

    Among the big news this week for those looking to make their data center more environmentally friendly: Two IBM POWER7-based servers become the first four-processor systems in the industry to qualify for Energy Star status; NetApp announces plans to have execs, and other on hand to discuss green computing at SNW Spring 2010; and the feds are examining how cloud will save money and energy.

    Read the article

  • Ethics of soliciting App store app reviews?

    - by hotpaw2
    I see more than a few developers soliciting 5-star ratings and good reviews for their App store apps, in their blogs, websites, app store descriptions, even dialogs that pop-up in the app after you've used them for awhile. What do people consider to be the ethical guidelines regarding such review and ratings solicitations? What's over the line? (Besides obviously evil stuff, such as paying to have someone forge multiple negative reviews about your competitor's apps, etc.)

    Read the article

  • Windows 8.1 : les images ISO sont également disponibles, la Preview peut désormais être installée sans passer par le Windows Store

    Windows 8.1 Preview disponible sur le Windows Store et gomme les erreurs de jeunesse de Windows 8La Build de San Francisco, l'événement majeur de Microsoft destiné aux développeurs, professionnels de l'IT, Designers et Geeks bat son plein.La star de cette première journée a été Windows 8.1, dont Microsoft a annoncé la sortie de la Preview. La société y a placé l'espoir de percer sur le marché des tablettes et de réconcilier certains utilisateurs avec leur PC. Retour du bouton Démarrer...

    Read the article

  • Windows 8.1 Preview disponible sur le Windows Store et gomme les erreurs de jeunesse de Windows 8

    Windows 8.1 Preview disponible sur le Windows Store et gomme les erreurs de jeunesse de Windows 8La Build de San Francisco, l'événement majeur de Microsoft destiné aux développeurs, professionnels de l'IT, Designers et Geeks bat son plein.La star de cette première journée a été Windows 8.1, dont Microsoft a annoncé la sortie de la Preview. La société y a placé l'espoir de percer sur le marché des tablettes et de réconcilier certains utilisateurs avec leur PC. Retour du bouton Démarrer...

    Read the article

  • Intel to Unleash Atom-ic Power at Computex

    <b>Hardware Central:</b> "Intel plans to introduce a series of new Atom processors at the opening of the giant Computex show in Taipei this week, as well as offer a preview a number of other offerings. But Atom will be the star of the show."

    Read the article

  • Showplan Operator of the Week – BookMark/Key Lookup

    Fabiano continues in his mission to describe the major Showplan Operators used by SQL Server's Query Optimiser. This week he meets a star, the Key Lookup, a stalwart performer, but most famous for its role in ill-performing queries where an index does not 'cover' the data required to execute the query. If you understand why, and in what circumstances, key lookups are slow, it helps greatly with optimising query performance.

    Read the article

  • A crowded Extra-Solar system

    - by TATWORTH
    The orbiting Kepler telescope has found another unusual alien solar system. The Kepler telescope monitors star for changes in their brightness. The light resulting curves can be seen at http://www.planethunters.org.Recently an extra-solar system with 4 stars (planets orbiting two of the stars with the other two stars orbiting as a distant binary pair) was discovered using by two "arm-chair" astronomers using the above web site. Source SPACE.com: All about our solar system, outer space and exploration

    Read the article

  • Virtual Lan on the Cloud -- Help Confirm my understanding?

    - by marfarma
    [Note: Tried to post this over at ServerFault, but I don't have enough 'points' for more than one link. Powers that be, move this question over there.] Please give this a quick read and let me know if I'm missing something before I start trying to make this work. I'm not a systems admin professional, and I'd hate to end up banging my head into the wall if I can avoid it. Goals: Create a 'road-warrior' capable star shaped virtual LAN for consultants who spend the majority of their time on client sites, and who's firm has no physical network or servers. Enable CIFS access to a cloud-server based installation of Alfresco Allow Eventual implementation of some form of single-sign-on ( OpenLDAP server ) access to Alfresco and other server applications implemented in the future Given: All Servers will live in the public internet cloud (Rackspace Cloud Servers) OpenVPN Server will be a Linux disto, probably Ubuntu 9.x, installed on same server as Alfresco (at least to start) Staff will access server applications and resources from client sites, hotels, trains, planes, coffee shops or their homes over various ISP, using their company laptops or personal home desktops. Based on my Research thus far, to accomplish this, I'll need: OpenVPN with Bridging Enabled to create a star shaped "virtual" LAN http://openvpn.net/index.php/open-source/documentation/miscellaneous/76-ethernet-bridging.html A Road Warrior Network Configuration, as described in this Shorewall article (lower down the page) http://www.shorewall.net/OPENVPN.html Configure bridge addressesing (probably DHCP) http://openvpn.net/index.php/open-source/faq.html#bridge-addressing Configure CIFS / Samba to accept VPN IP address http://serverfault.com/questions/137933/howto-access-samba-share-over-vpn-tunnel Set up Client software, with keys configured for access (potentially through a OpenVPN-Sa client portal) http://www.openvpn.net/index.php/access-server/download-openvpn-as/221-installation-overview.html

    Read the article

  • Five stars of open data - example and review

    - by Joe
    (there may be a more suited SE site for this question so feel free to shift) I have some data I'd like to make open to the public - It's synatesis of some related data retrived from freedom of infomation requests over the last year. The data itself is at http://www.cs.rhul.ac.uk/home/joseph/domesday/Domesday-Scotland.csv or for fans of Excel, at http://www.cs.rhul.ac.uk/home/joseph/domesday/Domesday-Scotland.xlsx . It's no more than a table with about five columns. I'd like to make this properly open data, so I was looking at the 5 star deployment scheme for Open Data. Much of which is fine but I'm confused towards the end and I could do with an explenation from people who know the answers. So to get achieve the star levels I need: "make your stuff available on the Web (whatever format) under an open license" trival - all I have to do is put the notes up on the page that will give the provance of the data. "make it available as structured data (e.g., Excel instead of image scan of a table)"… done… "use non-proprietary formats (e.g., CSV instead of Excel)" - done… "use URIs to identify things, so that people can point at your stuff" - this is where I start to get a bit hazy - does this mean there should be an URI for every line in the table? "link your data to other data to provide context" - this isn't massively clear to me - does this mean to give the provence of the data? One column of the data I've put out is a link to where the data came from - is that the sort of thing we're looking at? Any and all information and answers welcome… EDIT - or if anyone wants to recommend a place SE or other place to ask the question - that would be cool...

    Read the article

  • 2 javascripts problem

    - by pradeep
    <?php global $user; $userId = $user->uid; /* start with default */ $myresult = ""; /* All Includes - start */ include_once('db.php'); include_once('valid-scripts/validateData.php'); /* All Includes - end */ /* Build All required Variables - start */ $alias = $_GET['alias']; $product = $_GET['product']; $product = strtolower(substr($product,0,-1)); $master_table = $product.'_master'; $rating_master_table = $product.'_rating_master'; $rating_table = $product.'_rating'; $numProperties = 15; /* Build All required Variables - end */ /* Add all Styles required - start */ $myresult .= '<link href="/jquery.rating.css" type="text/css" rel="stylesheet"/>'; /* Add all Styles required - end */ /* Show Hide Variables/parameters - start */ include_once('all_include_files/show_hide.php'); /* Show Hide Variables/parameters - end */ /* All Javascript - start */ //$myresult .= '<script src="/jquery.rating.js" type="text/javascript" language="javascript"></script>'; ?> <style> #tabs { //font-size: 90%; //margin: 20px 0; margin: 2px 0; } #tabs ul { float: right; background: #E3FEFA; width: 600px; //padding-top: 4px; } #tabs li { margin-left: 8px; list-style: none; } * html #tabs li { display: inline; /* ie6 double float margin bug */ } #tabs li, #tabs li a { float: left; } #tabs ul li a { text-decoration: none; //padding: 8px; color: #0073BF; font-weight: bold; } #tabs ul li.active { background: #CEE1EF url(/all_include_files/img/nav-right.gif) no-repeat right top; } #tabs ul li.active a { background: url(/all_include_files/img/nav-left.gif) no-repeat left top; color: #333333; } #tabs div { //background: #CEE1EF; clear: both; //padding: 20px; min-height: 200px; } #tabs div h3 { text-transform: uppercase; margin-bottom: 10px; letter-spacing: 1px; #tabs div p { line-height: 150%; } </style> <script src="/jquery.rating.js" type="text/javascript" language="javascript"></script> <script src="/jquery.metadata.js" type="text/javascript" language="javascript"></script> <script type='text/javascript'> function openComment(number) { alert('working'); $('#comment'+number).css('display',''); } $('.star').rating({ callback: function(value, link){ alert(value); } }); $(document).ready(function() { //$('#tabs div').hide(); //$('#tabs div:first').show(); $('#tabs ul li:first').addClass('active'); $('#tabs ul li a').click(function() { $('#tabs ul li').removeClass('active'); $(this).parent().addClass('active'); var currentTab = $(this).attr('href'); $('#tabs div').hide(); $(currentTab).show(); return false; }); $("#clickit").click(function() { $.post("/mobile/tablechange.php",{ p1:'<?php echo $brand ?>',p2:'<?php echo $model ?>',userid:'<?php echo $userid ?>' } ,function(data){ $("#changetable").html(data); }); }); $('div.expandable p').expander({ slicePoint: 200, // default is 100 expandText: 'more &raquo;', // default is 'read more...' collapseTimer: 0, // re-collapses after 5 seconds; default is 0, so no re-collapsing userCollapseText: '[^]' // default is '[collapse expanded text]' }); }); </script> <?php /* All Javascript - end */ /* Form Processing after submit - start */ /* Form Processing after submit - end */ /* Actual Form or Page - start */ /*fetch all data needed */ /* initial query */ $result_product = query_product_table($product,$alias); /*fetch property names of product */ $product_properties = master_table($master_table); /*rating table query */ $master_rating_properties = master_rating_table($rating_master_table); /*get user ratings*/ $user_ratings = user_ratings($userId,$alias,$rating_table); $myresult .= '<div class=\'Services\'>'; //$myresult .="<form name ='form1' id='form1' method = 'POST' action='".$_SERVER['php_self'] ."'>"; if(!$result_product) { header('Location: /page-not-found'); } else { $row_product = mysql_fetch_array($result_product); $myresult .= "<h3 class='newstyle'>".$row_product['alias']." <a style='float:right;padding-right:20px;color:white;text-decoration:underline;' href='/'>Back</a> </h3>"; /* start actual product display - start*/ $myresult .= "<div class=\"product\">"; /* start table 1*/ $myresult .= '<table border=\'0\' cellspacing=\'0\' cellpadding=\'0\' style=\'width:580px; table-layout:fixed;\'>'; $myresult .= '<tr>'; $myresult .='<td valign=\'top\'>'; /* start table 2*/ $myresult .='<table width=\'100%\' border=\'0\' cellspacing=\'0\' cellpadding=\'0\'>'; $myresult .= '<tr>'; $myresult .= '<td valign=\'top\' style=\'width:164px;\'>'; /* start table 3*/ $myresult .= '<table style=\'width:164px;\' border=\'0\' cellspacing=\'0\' cellpadding=\'0\'>'; $myresult .= "<tr>"; /* start of the pic row */ $myresult .= '<td align=\'center\' class=\'various_product\'>'; if($row_product['pic'] != "") { $myresult .= '<ul id=\'mycarousel\' style=\'display:\';>'; $myresult .= '<li><a href=\'/all_image_scripts/origpicdisplay.php?product='.rawurlencode($product).'&alias='.rawurlencode($alias).'&picid=pic&p= \'rel=\'lightbox[roadtrip]\'><img src=\'/all_image_scripts/picdisplay1.php?product='.rawurlencode($product).'&alias='.rawurlencode($alias).'\'></img></a></li>'; for($p = 1; $p <= 4; $p++) { if($row_product['pic'.$p] != "") { $myresult .= '<li><a href=\'/all_image_scripts/origpicdisplay.php?product='.rawurlencode($product).'&alias='.rawurlencode($alias).'&picid=pic'.rawurlencode($p).'&p='.rawurlencode($p).'\' rel=\'lightbox[roadtrip]\'><img src=\'/all_image_scripts/thumbpicdisplay.php?product='.rawurlencode($product).'&alias='.rawurlencode($alias).'&picid=pic'.rawurlencode($p).'\'></img></a></li>'; } } $myresult .= '</ul>'; } else { $myresult .= "<img width='50' height='70' src='/images/no-image.gif'></img>"; } jcarousel_add('#mycarousel', array('horizontal' => TRUE,'scroll' => 1,'visible' => 1)); $myresult .= "</td>"; /* end display of pic td*/ $myresult .= "</tr>"; /* end display of pic tr*/ $myresult .= "</table></td>"; /* end display of pic table and earlier td - Still 1 open TR td table tr -hint*/ $myresult .= '<td style=\'width:450px;\'>'; /*table - 4*/ $myresult .= '<table width=\'100%\' border=\'0\' cellspacing=\'0\' cellpadding=\'0\' style=\'display:block;\'>'; /* Start showing property and values */ $myresult .= '<tr>'; $myresult .= '<td class=\'tick\'><img src=\'/images/ul_li_bg.gif\' width=\'12\' height=\'12\' /></td>'; $myresult .= '<td class=\'leftText\'>'.ucfirst($product).':</td>'; $myresult .= '<td class=\'rightText\'>'.$row_product['alias'] .'</td>'; $myresult .= "</tr>"; for($j = 3; $j <= 5 ; $j++){ if($product_properties['property'.$j.'_name'] != "") { if($row_product['property'.$j] != "") { $myresult .= '<tr>'; $myresult .= '<td class=\'tick\'><img src=\'/images/ul_li_bg.gif\' width=\'12\' height=\'12\' /></td>'; $myresult .= '<td class=\'leftText\'>'.$product_properties['property'.$j.'_name'].':</td>'; $myresult .= '<td class=\'rightText\'>'.$row_product['property'.$j] .'</td>'; $myresult .= '</tr>'; } /* end if*/ } /* end if*/ } /* end for*/ /* show hide block */ $myresult .= '<tbody id=\'extra_properties\' style=\'display: none;\'>'; for($j = 6; $j <= 15 ; $j++){ if($product_properties['property'.$j.'_name'] != "") { if($row_product['property'.$j] != "") { $myresult .= '<tr>'; $myresult .= '<td class=\'tick\'><img src=\'/images/ul_li_bg.gif\' width=\'12\' height=\'12\' /></td>'; $myresult .= '<td class=\'leftText\'>'.$produtc_properties['property'.$j.'_name'].':</td>'; $myresult .= '<td class=\'rightText\'>'.$row_product['property'.$j] .'</td>'; $myresult .= '</tr>'; } /* end if*/ } /* end if*/ } /* end for */ $myresult .= '</tbody>'; /* end show/hide tbody */ $myresult .= '<tr>'; $myresult .= '<td>'; $myresult .= '&nbsp;'; $myresult .= '</td>'; $myresult .= '<td>'; $myresult .= '&nbsp;'; $myresult .= '</td>'; $myresult .= '<td align=\'right\' style=\'text-align:right;text-decoration:underline;\'>'; $myresult .= '<a class=\'right_link\' href=\'javascript:showMore()\'>Show Additional Details...</a>'; $myresult .= '</td>'; $myresult .= '</tr>'; /* End showing property and values */ $showreview = 'display:'; /* review show hide */ /*$myresult .= '<tbody '.$showreview.'>'; $myresult .= '<tr>'; $myresult .= '<td colspan=\'2\'><span class=\'reviews\'>'; //check //$numreviews = getreviewcount($brand,$model,'mobile_user_reviews'); if($numreviews > 0) { $myresult .= '<a href=\'mobilereviews?alias='.rawurlencode($alias).'\'> <span>$numreviews Reviews</span></a>'; } else { $myresult .= " $numreviews Reviews"; } $myresult .= "</span></td>"; $myresult .= "</tr>"; */ $myresult .= "</tbody>"; /* review show hide - end */ /* count show hide */ $myresult .= '<tbody '.$showcount.'>'; $myresult .= '<tr>'; $myresult .= '<td colspan=\'2\'><span class=\'reviews\'>'; //check //$totalvotes = gettotalvotes($row['property1'],$row['property2'],'mobile_rating'); $myresult .= "</td>"; $myresult .= "</tr>"; $myresult .= "</tbody>"; /* count show hide - end */ $myresult .= "</table></td>"; /* end table 4 */ $myresult .= '</tr>'; /* end 1 row and remaining tr , td ,table */ $myresult .= '</table></td>'; $myresult .= '</tr>'; /* remianing only 1 table */ /* ratings - positive last section starts here */ $max= array(); for ($l = 1 ; $l < 15; $l++){ if($row_product['property'.$l.'_avg']){ $maxarray = 0; $maxarray = $row_product['property'.$l.'_avg']; $max['rating'.$l.'_name'] = $maxarray; } } if(count($max) >0 ) { include('all_include_files/min_max_properties.php'); } if(($row_product['freshness'] <= strtotime("-3 month"))) { $image_type= 'old'; } else if(($row_product['freshness'] <= strtotime("-2 month"))) { $image_type= 'bitold'; } else if(($row_product['freshness'] <= strtotime("-1 month")) || ($row_product['freshness'] > strtotime("-1 month"))) { $image_type= 'new'; } $img_name = $image_type; $myresult .= "<tr>"; $myresult .= "<td>"; $myresult .= "<table width='100%' border='0'>"; $myresult .= "<tr>"; $myresult .= "<td width='170' class=\"ratingz\"><span><u>Overall rating</u></span></td>"; $myresult .= "<td width='150' class=\"ratingz\"><span><u>Positive</u></span></td>"; $myresult .= "<td width='150' class=\"ratingz\"><span><u>Negative</u></span></td>"; if($img_name == 'new'){ $images = "<img src='/sites/default/files/battery-discharging-100.png' width='40' height='40'></img>"; } else if($img_name == 'bitold'){ $images = "<img src='/sites/default/files/battery-discharging-80.png' width='40' height='40'></img>"; } else if($img_name == 'old'){ $images = "<img src='/sites/default/files/battery-discharging-0.png' width='40' height='40'></img>"; } else { $images = ""; } $myresult .= "<td rowspan='2'><p ".$showbattery.">". $images ."</p></td>"; $myresult .= "</tr>"; $myresult .= "<tr>"; $myresult .= "<td>"; $i++; for($k = 0.5; $k <= 10.0; $k+=0.5) { $overall = roundOff($row_product['overall_rating']); if($overall == $k) { $chk ="checked"; } else { $chk = ""; } $myresult .= '<input class=\'star {split:2}\' type=\'radio\' value=\''. $k .'\' '.$chk.' title=\''. $k.' out of 10 \' disabled />'; } $myresult .= '</td>'; $myresult .= '<td ><span>'.$positive.'</span></td>'; $myresult .= '<td ><span>'.$negative.'</span></td>'; $myresult .= '</tr>'; $myresult .= '</table></td>'; $myresult .= '</tr>'; /* ratings - positive last section ends here */ $myresult .= '<tr>'; if($row_product['description'] != ""){ if(words_count($row_product['description']) > 8){ $myresult .= '<td><p><span class=\'description\'><strong><u>Description</u>:</strong></span>&nbsp;&nbsp; <div class=\'expandable\'><p>'.$row_product['description'].'</div></p></p></td>'; } else { $myresult .= '<td><p><span class=\'description\'><strong><u>Description</u>:</strong></span>&nbsp;&nbsp;'. $row_product['description'] .'</p></td>'; } } $myresult .= '</tr>'; $myresult .= '</table>'; /* end 1st table */ $myresult .= '</div>'; /* start actual product display - end*/ /*start the form to take ratings */ $myresult .= '<div id=\'tabs\'>'; $myresult .= '<ul>'; $myresult .= '<li><a href=\'#tab-1\'>Ratings</a></li>'; $myresult .= '<li><a href=\'#tab-2\'>Click here to rate</a></li>'; $myresult .= '</ul>'; $myresult .= '<div id=\'tab-1\'>'; /* actual rating table - start - jsut display ratings */ $myresult .= '<table id=\'rounded-corner\'>'; /* thead - start */ $myresult .= '<thead>'; $myresult .= '<tr>'; $myresult .= '<th width=\'30%\' class=\'rounded-company\' scope=\'col\'><span style=\'font: normal 18px Arial, Helvetica, sans-serif; color:#FFF;\'>Ratings</span></th>'; $myresult .= '<th width=\'70%\' colspan=\'2\'class=\'rounded-q4\' scope=\'col\'><a href=\'#rounded-corner\' id=\'clickit\' style=\'color:white;text-decoration:underline;\' $disabled ></a></th> '; /*$myresult .= '<th width=\'70%\' colspan=\'2\'class=\'rounded-q4\' scope=\'col\'><a href=\'#rounded-corner\' id=\'clickit\' style=\'color:white;text-decoration:underline;\' $disabled >Click here to rate</a></th> ';*/ $myresult .= '</tr>'; $myresult .= '</thead>'; /* thead - end */ /* tbody - start */ $myresult .= '<tbody>'; /*start printing the table wth feature and ratings */ for ($i = 1 ; $i < $numProperties; $i++){ if($master_rating_properties['rating'.$i.'_name']){ $myresult .= '<tr>'; $myresult .= '<td width=\'22%\'>'; $indfeature = 0; $indfeature = $row_product['property'.$i.'_avg']; $myresult .= $master_rating_properties['rating'.$i.'_name'].' ( '.$indfeature .')'; $myresult .= '</td>'; $myresult .= '<td colspan=\'0\' width=\'38%\' >'; $tocheck = $indfeature; for($k = 0.5; $k <= 10.0; $k+=0.5){ $tocheck = roundOff($tocheck); if(($tocheck) == $k) { $chk = "checked"; } else { $chk = ""; } $myresult .= '<input class=\'star {split:2}\' type=\'radio\' name=\'drating'.$i.'\' id=\'drating'.$i.''.$k.'\' value=\''. $k .'\' '.$chk.' title=\''. $k.' out of 10 \' disabled \'/>'; } /* for k loop end */ $myresult .= '</tr>'; } /* end if loop */ } /* end i for loop */ $myresult .= '</tbody>'; /* end tbody */ /* footer round corner start */ $myresult .= '<tfoot>'; $myresult .= '<tr>'; $myresult .= '<td class=\'rounded-foot-left\'>&nbsp;</td>'; $myresult .= '<td class=\'rounded-foot-right\' colspan=\'4\' >'; $myresult .= '</td>'; $myresult .= '</tr>'; $myresult .= '</tfoot>'; $myresult .= '</table>'; /*round corner table end */ $myresult .= '</div>'; /*end 1st tab */ /*start 2nd tab */ $myresult .= '<div id=\'tab-2\'>'; $myresult .= '<form name =\'form1\' id=\'form1\' method = \'POST\' action=\''.$_SERVER['php_self'] .'\'>'; /* actual rating table - start - actual rate/update */ $myresult .= '<table id=\'rounded-corner\'>'; /* thead - start */ $myresult .= '<thead>'; $myresult .= '<tr>'; $myresult .= '<th width=\'30%\' class=\'rounded-company\' scope=\'col\'><span style=\'font: normal 18px Arial, Helvetica, sans-serif; color:#FFF;\'>Ratings</span></th>'; $myresult .= '<th width=\'70%\' colspan=\'2\'class=\'rounded-q4\' scope=\'col\'></th>'; $myresult .= '</tr>'; $myresult .= '</thead>'; /* thead - end */ /* tbody - start */ $myresult .= '<tbody>'; unset($i); /*start printing the table wth feature and ratings */ for ($i = 1 ; $i < $numProperties; $i++){ if($master_rating_properties['rating'.$i.'_name']){ $myresult .= '<tr>'; /*fetch ratings and comments - 1st make it to null */ $indfeature = 0; $comment = ''; $indfeature = $user_ratings['rating'.$i]; if($indfeature == NULL){ $indfeature = 0; } $comment = $user_ratings['rating'.$i.'_comment']; $myresult .= '<td width=\'22%\'>'; $myresult .= $master_rating_properties['rating'.$i.'_name'].' ( '.$indfeature.' )'; $myresult .= '</td>'; $myresult .= '<td colspan=\'0\' width=\'38%\' >'; if(($userId != '0') && (is_array($user_ratings))) { $tocheck = $indfeature; } else { $tocheck = '0'; } for($k = 0.5; $k <= 10.0; $k+=0.5){ $tocheck = roundOff($tocheck); if(($tocheck) == $k) { $chk = "checked"; } else { $chk = ""; } $myresult .= '<input class=\'star {split:2}\' type=\'radio\' name=\'rating'.$i.'\' id=\'rating'.$i.''.$k.'\' value=\''. $k .'\' '.$chk.' title=\''. $k.' out of 10 \' '.$disabled.' \' />'; } /* for k loop end */ $myresult .= '</td>'; $myresult .= '<td width=\'40%\'>'; $myresult .= '<input title=\'Reason for this Rating.. \'type=\'text\' size=\'25\' name=\'comment'.$i.'\' id=\'comment'.$i.'\' style=\'display:;\' maxlength=\'255\' value="'.$comment.'">'; $myresult .= '</td>'; $myresult .= '</tr>'; } /* end if loop */ } /* end i for loop */ $myresult .= '</tbody>'; /* end tbody */ /* footer round corner start */ $myresult .= '<tfoot>'; $myresult .= '<tr>'; $myresult .= '<td class=\'rounded-foot-left\'>&nbsp;</td>'; $myresult .= '<td class=\'rounded-foot-right\' colspan=\'4\' >'; if(($userId != '0') && (is_array($user_ratings))) { $myresult .= '<input type=\'button\' id=\'update_form\' value=\'Update\'>'; } else { $myresult .= '<input type=\'button\' id=\'save_form\' value=\'Save\'>'; } $myresult .= '</td>'; $myresult .= '</tr>'; $myresult .= '</tfoot>'; $myresult .= '</table>'; /*round corner table end */ $myresult .= '</form>'; /*end the form to take ratings */ $myresult .= '</div>'; /*end 2nd tab */ $myresult .= '</div>'; /*end tabs div */ /* actual rating table - end */ /* 1st form ends here id- ratings_form */ } /* end of if loop result_product loop */ /* start table 3 - overall comment*/ $myresult .= '<table border=\'0\' cellspacing=\'0\' cellpadding=\'0\' style=\'width:580px; table-layout:fixed;\' id=\'rounded-corner\'>'; $myresult .= '<tbody>'; /* thead - start */ $myresult .= '<thead>'; $myresult .= '<tr>'; $myresult .= '<th width=\'100%\' colspan=\'2\' class=\'rounded-company\' scope=\'col\'><span style=\'font: normal 18px Arial, Helvetica, sans-serif; color:#FFF;\'>Overall Comments</span></th>'; $myresult .= '<th colspan=\'3\' class=\'rounded-q4\' scope=\'col\'></th>'; $myresult .= '</tr>'; $myresult .= '</thead>'; /* thead - end */ $myresult .= '<tr>'; $myresult .= '<td colspan=\'4\'>'; $myresult .= '<textarea title=\'OverAll Comment\' name=\'overall_comment\' cols=\'65\'></textarea>'; $myresult .= '</td>'; $myresult .= '</tr>'; $myresult .= '<tbody>'; $myresult .= '</table>'; /* end table 3 - overall comment*/ /* start table 4 - summary*/ $myresult .= '<table border=\'0\' cellspacing=\'0\' cellpadding=\'0\' style=\'width:580px; table-layout:fixed;\' id=\'rounded-corner\'>'; $myresult .= '<tbody>'; /* thead - start */ $myresult .= '<thead>'; $myresult .= '<tr>'; $myresult .= '<th colspan=\'2\' class=\'rounded-company\' scope=\'col\'><span style=\'font: normal 18px Arial, Helvetica, sans-serif; color:#FFF;\'>Your Opinion</span></th>'; $myresult .= '<th colspan=\'2\'class=\'rounded-q4\' scope=\'col\'></th>'; $myresult .= '</tr>'; $myresult .= '</thead>'; /* thead - end */ $myresult .= '<tr>'; $myresult .= '<td colspan=\'2\'>'; $myresult .= 'Do you Agree with the Ratings'; $myresult .= '</td>'; $myresult .= '<td colspan=\'2\'>'; $myresult .= 'Was the Information Helpful'; $myresult .= '</td>'; $myresult .= '</tr>'; $myresult .= '<tr>'; $myresult .= '<form name=\'form2\' id=\'form2\' method=\'post\'>'; $myresult .= '<td>'; $myresult .= '<input type=\'button\' class=\'agree\' value=\'agree\'>'; $myresult .= '</td>'; $myresult .= '<td>'; $myresult .= '<input type=\'button\' class=\'disagree\' value=\'disagree\'>'; $myresult .= '</td>'; $myresult .= '<input type=\'hidden\' name=\'agree_disagree\' id=\'agree_disagree\'>'; $myresult .= '</form>'; $myresult .= '<form name=\'form3\' id=\'form3\' method=\'post\'>'; $myresult .= '<td>'; $myresult .= '<input type=\'button\' class=\'helpful\' value=\'Helpful\'>'; $myresult .= '</td>'; $myresult .= '<td>'; $myresult .= '<input type=\'button\' class=\'nothelpful\' value=\'Not Helpful\'>'; $myresult .= '</td>'; $myresult .= '<input type=\'hidden\' name=\'help_nohelp\' id=\'help_nohelp\'>'; $myresult .= '</form>'; $myresult .= '</tr>'; $myresult .= '</tbody>'; $myresult .= '</table>'; /*end table 4 summary table */ $myresult .= '</div>'; /* Actual Form or Page - end */ echo $myresult; //echo 'Product: '.$product; //echo '<br/>Alias: '.$alias; ?> hey this code is working fine for me . as required. the star class code is taken from http://www.fyneworks.com/jquery/star-rating/ ... it works well.. but when i insert code to add tabs for content ,the starts is not visible at all. but when i check source code. the stars are actually there . dono whats the prob. any suggestions on this this is the tabs code $('#tabs div').hide(); ('#tabs div:first').show(); $('#tabs ul li:first').addClass('active'); $('#tabs ul li a').click(function() { $('#tabs ul li').removeClass('active'); $(this).parent().addClass('active'); var currentTab = $(this).attr('href'); $('#tabs div').hide(); $(currentTab).show(); return false; });

    Read the article

  • Introduction to the ASP.NET Web API

    - by Stephen.Walther
    I am a huge fan of Ajax. If you want to create a great experience for the users of your website – regardless of whether you are building an ASP.NET MVC or an ASP.NET Web Forms site — then you need to use Ajax. Otherwise, you are just being cruel to your customers. We use Ajax extensively in several of the ASP.NET applications that my company, Superexpert.com, builds. We expose data from the server as JSON and use jQuery to retrieve and update that data from the browser. One challenge, when building an ASP.NET website, is deciding on which technology to use to expose JSON data from the server. For example, how do you expose a list of products from the server as JSON so you can retrieve the list of products with jQuery? You have a number of options (too many options) including ASMX Web services, WCF Web Services, ASHX Generic Handlers, WCF Data Services, and MVC controller actions. Fortunately, the world has just been simplified. With the release of ASP.NET 4 Beta, Microsoft has introduced a new technology for exposing JSON from the server named the ASP.NET Web API. You can use the ASP.NET Web API with both ASP.NET MVC and ASP.NET Web Forms applications. The goal of this blog post is to provide you with a brief overview of the features of the new ASP.NET Web API. You learn how to use the ASP.NET Web API to retrieve, insert, update, and delete database records with jQuery. We also discuss how you can perform form validation when using the Web API and use OData when using the Web API. Creating an ASP.NET Web API Controller The ASP.NET Web API exposes JSON data through a new type of controller called an API controller. You can add an API controller to an existing ASP.NET MVC 4 project through the standard Add Controller dialog box. Right-click your Controllers folder and select Add, Controller. In the dialog box, name your controller MovieController and select the Empty API controller template: A brand new API controller looks like this: using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Web.Http; namespace MyWebAPIApp.Controllers { public class MovieController : ApiController { } } An API controller, unlike a standard MVC controller, derives from the base ApiController class instead of the base Controller class. Using jQuery to Retrieve, Insert, Update, and Delete Data Let’s create an Ajaxified Movie Database application. We’ll retrieve, insert, update, and delete movies using jQuery with the MovieController which we just created. Our Movie model class looks like this: namespace MyWebAPIApp.Models { public class Movie { public int Id { get; set; } public string Title { get; set; } public string Director { get; set; } } } Our application will consist of a single HTML page named Movies.html. We’ll place all of our jQuery code in the Movies.html page. Getting a Single Record with the ASP.NET Web API To support retrieving a single movie from the server, we need to add a Get method to our API controller: using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; using MyWebAPIApp.Models; namespace MyWebAPIApp.Controllers { public class MovieController : ApiController { public Movie GetMovie(int id) { // Return movie by id if (id == 1) { return new Movie { Id = 1, Title = "Star Wars", Director = "Lucas" }; } // Otherwise, movie was not found throw new HttpResponseException(HttpStatusCode.NotFound); } } } In the code above, the GetMovie() method accepts the Id of a movie. If the Id has the value 1 then the method returns the movie Star Wars. Otherwise, the method throws an exception and returns 404 Not Found HTTP status code. After building your project, you can invoke the MovieController.GetMovie() method by entering the following URL in your web browser address bar: http://localhost:[port]/api/movie/1 (You’ll need to enter the correct randomly generated port). In the URL api/movie/1, the first “api” segment indicates that this is a Web API route. The “movie” segment indicates that the MovieController should be invoked. You do not specify the name of the action. Instead, the HTTP method used to make the request – GET, POST, PUT, DELETE — is used to identify the action to invoke. The ASP.NET Web API uses different routing conventions than normal ASP.NET MVC controllers. When you make an HTTP GET request then any API controller method with a name that starts with “GET” is invoked. So, we could have called our API controller action GetPopcorn() instead of GetMovie() and it would still be invoked by the URL api/movie/1. The default route for the Web API is defined in the Global.asax file and it looks like this: routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); We can invoke our GetMovie() controller action with the jQuery code in the following HTML page: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Get Movie</title> </head> <body> <div> Title: <span id="title"></span> </div> <div> Director: <span id="director"></span> </div> <script type="text/javascript" src="Scripts/jquery-1.6.2.min.js"></script> <script type="text/javascript"> getMovie(1, function (movie) { $("#title").html(movie.Title); $("#director").html(movie.Director); }); function getMovie(id, callback) { $.ajax({ url: "/api/Movie", data: { id: id }, type: "GET", contentType: "application/json;charset=utf-8", statusCode: { 200: function (movie) { callback(movie); }, 404: function () { alert("Not Found!"); } } }); } </script> </body> </html> In the code above, the jQuery $.ajax() method is used to invoke the GetMovie() method. Notice that the Ajax call handles two HTTP response codes. When the GetMove() method successfully returns a movie, the method returns a 200 status code. In that case, the details of the movie are displayed in the HTML page. Otherwise, if the movie is not found, the GetMovie() method returns a 404 status code. In that case, the page simply displays an alert box indicating that the movie was not found (hopefully, you would implement something more graceful in an actual application). You can use your browser’s Developer Tools to see what is going on in the background when you open the HTML page (hit F12 in the most recent version of most browsers). For example, you can use the Network tab in Google Chrome to see the Ajax request which invokes the GetMovie() method: Getting a Set of Records with the ASP.NET Web API Let’s modify our Movie API controller so that it returns a collection of movies. The following Movie controller has a new ListMovies() method which returns a (hard-coded) collection of movies: using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; using MyWebAPIApp.Models; namespace MyWebAPIApp.Controllers { public class MovieController : ApiController { public IEnumerable<Movie> ListMovies() { return new List<Movie> { new Movie {Id=1, Title="Star Wars", Director="Lucas"}, new Movie {Id=1, Title="King Kong", Director="Jackson"}, new Movie {Id=1, Title="Memento", Director="Nolan"} }; } } } Because we named our action ListMovies(), the default Web API route will never match it. Therefore, we need to add the following custom route to our Global.asax file (at the top of the RegisterRoutes() method): routes.MapHttpRoute( name: "ActionApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); This route enables us to invoke the ListMovies() method with the URL /api/movie/listmovies. Now that we have exposed our collection of movies from the server, we can retrieve and display the list of movies using jQuery in our HTML page: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>List Movies</title> </head> <body> <div id="movies"></div> <script type="text/javascript" src="Scripts/jquery-1.6.2.min.js"></script> <script type="text/javascript"> listMovies(function (movies) { var strMovies=""; $.each(movies, function (index, movie) { strMovies += "<div>" + movie.Title + "</div>"; }); $("#movies").html(strMovies); }); function listMovies(callback) { $.ajax({ url: "/api/Movie/ListMovies", data: {}, type: "GET", contentType: "application/json;charset=utf-8", }).then(function(movies){ callback(movies); }); } </script> </body> </html>     Inserting a Record with the ASP.NET Web API Now let’s modify our Movie API controller so it supports creating new records: public HttpResponseMessage<Movie> PostMovie(Movie movieToCreate) { // Add movieToCreate to the database and update primary key movieToCreate.Id = 23; // Build a response that contains the location of the new movie var response = new HttpResponseMessage<Movie>(movieToCreate, HttpStatusCode.Created); var relativePath = "/api/movie/" + movieToCreate.Id; response.Headers.Location = new Uri(Request.RequestUri, relativePath); return response; } The PostMovie() method in the code above accepts a movieToCreate parameter. We don’t actually store the new movie anywhere. In real life, you will want to call a service method to store the new movie in a database. When you create a new resource, such as a new movie, you should return the location of the new resource. In the code above, the URL where the new movie can be retrieved is assigned to the Location header returned in the PostMovie() response. Because the name of our method starts with “Post”, we don’t need to create a custom route. The PostMovie() method can be invoked with the URL /Movie/PostMovie – just as long as the method is invoked within the context of a HTTP POST request. The following HTML page invokes the PostMovie() method. <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Create Movie</title> </head> <body> <script type="text/javascript" src="Scripts/jquery-1.6.2.min.js"></script> <script type="text/javascript"> var movieToCreate = { title: "The Hobbit", director: "Jackson" }; createMovie(movieToCreate, function (newMovie) { alert("New movie created with an Id of " + newMovie.Id); }); function createMovie(movieToCreate, callback) { $.ajax({ url: "/api/Movie", data: JSON.stringify( movieToCreate ), type: "POST", contentType: "application/json;charset=utf-8", statusCode: { 201: function (newMovie) { callback(newMovie); } } }); } </script> </body> </html> This page creates a new movie (the Hobbit) by calling the createMovie() method. The page simply displays the Id of the new movie: The HTTP Post operation is performed with the following call to the jQuery $.ajax() method: $.ajax({ url: "/api/Movie", data: JSON.stringify( movieToCreate ), type: "POST", contentType: "application/json;charset=utf-8", statusCode: { 201: function (newMovie) { callback(newMovie); } } }); Notice that the type of Ajax request is a POST request. This is required to match the PostMovie() method. Notice, furthermore, that the new movie is converted into JSON using JSON.stringify(). The JSON.stringify() method takes a JavaScript object and converts it into a JSON string. Finally, notice that success is represented with a 201 status code. The HttpStatusCode.Created value returned from the PostMovie() method returns a 201 status code. Updating a Record with the ASP.NET Web API Here’s how we can modify the Movie API controller to support updating an existing record. In this case, we need to create a PUT method to handle an HTTP PUT request: public void PutMovie(Movie movieToUpdate) { if (movieToUpdate.Id == 1) { // Update the movie in the database return; } // If you can't find the movie to update throw new HttpResponseException(HttpStatusCode.NotFound); } Unlike our PostMovie() method, the PutMovie() method does not return a result. The action either updates the database or, if the movie cannot be found, returns an HTTP Status code of 404. The following HTML page illustrates how you can invoke the PutMovie() method: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Put Movie</title> </head> <body> <script type="text/javascript" src="Scripts/jquery-1.6.2.min.js"></script> <script type="text/javascript"> var movieToUpdate = { id: 1, title: "The Hobbit", director: "Jackson" }; updateMovie(movieToUpdate, function () { alert("Movie updated!"); }); function updateMovie(movieToUpdate, callback) { $.ajax({ url: "/api/Movie", data: JSON.stringify(movieToUpdate), type: "PUT", contentType: "application/json;charset=utf-8", statusCode: { 200: function () { callback(); }, 404: function () { alert("Movie not found!"); } } }); } </script> </body> </html> Deleting a Record with the ASP.NET Web API Here’s the code for deleting a movie: public HttpResponseMessage DeleteMovie(int id) { // Delete the movie from the database // Return status code return new HttpResponseMessage(HttpStatusCode.NoContent); } This method simply deletes the movie (well, not really, but pretend that it does) and returns a No Content status code (204). The following page illustrates how you can invoke the DeleteMovie() action: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Delete Movie</title> </head> <body> <script type="text/javascript" src="Scripts/jquery-1.6.2.min.js"></script> <script type="text/javascript"> deleteMovie(1, function () { alert("Movie deleted!"); }); function deleteMovie(id, callback) { $.ajax({ url: "/api/Movie", data: JSON.stringify({id:id}), type: "DELETE", contentType: "application/json;charset=utf-8", statusCode: { 204: function () { callback(); } } }); } </script> </body> </html> Performing Validation How do you perform form validation when using the ASP.NET Web API? Because validation in ASP.NET MVC is driven by the Default Model Binder, and because the Web API uses the Default Model Binder, you get validation for free. Let’s modify our Movie class so it includes some of the standard validation attributes: using System.ComponentModel.DataAnnotations; namespace MyWebAPIApp.Models { public class Movie { public int Id { get; set; } [Required(ErrorMessage="Title is required!")] [StringLength(5, ErrorMessage="Title cannot be more than 5 characters!")] public string Title { get; set; } [Required(ErrorMessage="Director is required!")] public string Director { get; set; } } } In the code above, the Required validation attribute is used to make both the Title and Director properties required. The StringLength attribute is used to require the length of the movie title to be no more than 5 characters. Now let’s modify our PostMovie() action to validate a movie before adding the movie to the database: public HttpResponseMessage PostMovie(Movie movieToCreate) { // Validate movie if (!ModelState.IsValid) { var errors = new JsonArray(); foreach (var prop in ModelState.Values) { if (prop.Errors.Any()) { errors.Add(prop.Errors.First().ErrorMessage); } } return new HttpResponseMessage<JsonValue>(errors, HttpStatusCode.BadRequest); } // Add movieToCreate to the database and update primary key movieToCreate.Id = 23; // Build a response that contains the location of the new movie var response = new HttpResponseMessage<Movie>(movieToCreate, HttpStatusCode.Created); var relativePath = "/api/movie/" + movieToCreate.Id; response.Headers.Location = new Uri(Request.RequestUri, relativePath); return response; } If ModelState.IsValid has the value false then the errors in model state are copied to a new JSON array. Each property – such as the Title and Director property — can have multiple errors. In the code above, only the first error message is copied over. The JSON array is returned with a Bad Request status code (400 status code). The following HTML page illustrates how you can invoke our modified PostMovie() action and display any error messages: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Create Movie</title> </head> <body> <script type="text/javascript" src="Scripts/jquery-1.6.2.min.js"></script> <script type="text/javascript"> var movieToCreate = { title: "The Hobbit", director: "" }; createMovie(movieToCreate, function (newMovie) { alert("New movie created with an Id of " + newMovie.Id); }, function (errors) { var strErrors = ""; $.each(errors, function(index, err) { strErrors += "*" + err + "\n"; }); alert(strErrors); } ); function createMovie(movieToCreate, success, fail) { $.ajax({ url: "/api/Movie", data: JSON.stringify(movieToCreate), type: "POST", contentType: "application/json;charset=utf-8", statusCode: { 201: function (newMovie) { success(newMovie); }, 400: function (xhr) { var errors = JSON.parse(xhr.responseText); fail(errors); } } }); } </script> </body> </html> The createMovie() function performs an Ajax request and handles either a 201 or a 400 status code from the response. If a 201 status code is returned then there were no validation errors and the new movie was created. If, on the other hand, a 400 status code is returned then there was a validation error. The validation errors are retrieved from the XmlHttpRequest responseText property. The error messages are displayed in an alert: (Please don’t use JavaScript alert dialogs to display validation errors, I just did it this way out of pure laziness) This validation code in our PostMovie() method is pretty generic. There is nothing specific about this code to the PostMovie() method. In the following video, Jon Galloway demonstrates how to create a global Validation filter which can be used with any API controller action: http://www.asp.net/web-api/overview/web-api-routing-and-actions/video-custom-validation His validation filter looks like this: using System.Json; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http.Controllers; using System.Web.Http.Filters; namespace MyWebAPIApp.Filters { public class ValidationActionFilter:ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { var modelState = actionContext.ModelState; if (!modelState.IsValid) { dynamic errors = new JsonObject(); foreach (var key in modelState.Keys) { var state = modelState[key]; if (state.Errors.Any()) { errors[key] = state.Errors.First().ErrorMessage; } } actionContext.Response = new HttpResponseMessage<JsonValue>(errors, HttpStatusCode.BadRequest); } } } } And you can register the validation filter in the Application_Start() method in the Global.asax file like this: GlobalConfiguration.Configuration.Filters.Add(new ValidationActionFilter()); After you register the Validation filter, validation error messages are returned from any API controller action method automatically when validation fails. You don’t need to add any special logic to any of your API controller actions to take advantage of the filter. Querying using OData The OData protocol is an open protocol created by Microsoft which enables you to perform queries over the web. The official website for OData is located here: http://odata.org For example, here are some of the query options which you can use with OData: · $orderby – Enables you to retrieve results in a certain order. · $top – Enables you to retrieve a certain number of results. · $skip – Enables you to skip over a certain number of results (use with $top for paging). · $filter – Enables you to filter the results returned. The ASP.NET Web API supports a subset of the OData protocol. You can use all of the query options listed above when interacting with an API controller. The only requirement is that the API controller action returns its data as IQueryable. For example, the following Movie controller has an action named GetMovies() which returns an IQueryable of movies: public IQueryable<Movie> GetMovies() { return new List<Movie> { new Movie {Id=1, Title="Star Wars", Director="Lucas"}, new Movie {Id=2, Title="King Kong", Director="Jackson"}, new Movie {Id=3, Title="Willow", Director="Lucas"}, new Movie {Id=4, Title="Shrek", Director="Smith"}, new Movie {Id=5, Title="Memento", Director="Nolan"} }.AsQueryable(); } If you enter the following URL in your browser: /api/movie?$top=2&$orderby=Title Then you will limit the movies returned to the top 2 in order of the movie Title. You will get the following results: By using the $top option in combination with the $skip option, you can enable client-side paging. For example, you can use $top and $skip to page through thousands of products, 10 products at a time. The $filter query option is very powerful. You can use this option to filter the results from a query. Here are some examples: Return every movie directed by Lucas: /api/movie?$filter=Director eq ‘Lucas’ Return every movie which has a title which starts with ‘S’: /api/movie?$filter=startswith(Title,’S') Return every movie which has an Id greater than 2: /api/movie?$filter=Id gt 2 The complete documentation for the $filter option is located here: http://www.odata.org/developers/protocols/uri-conventions#FilterSystemQueryOption Summary The goal of this blog entry was to provide you with an overview of the new ASP.NET Web API introduced with the Beta release of ASP.NET 4. In this post, I discussed how you can retrieve, insert, update, and delete data by using jQuery with the Web API. I also discussed how you can use the standard validation attributes with the Web API. You learned how to return validation error messages to the client and display the error messages using jQuery. Finally, we briefly discussed how the ASP.NET Web API supports the OData protocol. For example, you learned how to filter records returned from an API controller action by using the $filter query option. I’m excited about the new Web API. This is a feature which I expect to use with almost every ASP.NET application which I build in the future.

    Read the article

  • Introduction to the ASP.NET Web API

    - by Stephen.Walther
    I am a huge fan of Ajax. If you want to create a great experience for the users of your website – regardless of whether you are building an ASP.NET MVC or an ASP.NET Web Forms site — then you need to use Ajax. Otherwise, you are just being cruel to your customers. We use Ajax extensively in several of the ASP.NET applications that my company, Superexpert.com, builds. We expose data from the server as JSON and use jQuery to retrieve and update that data from the browser. One challenge, when building an ASP.NET website, is deciding on which technology to use to expose JSON data from the server. For example, how do you expose a list of products from the server as JSON so you can retrieve the list of products with jQuery? You have a number of options (too many options) including ASMX Web services, WCF Web Services, ASHX Generic Handlers, WCF Data Services, and MVC controller actions. Fortunately, the world has just been simplified. With the release of ASP.NET 4 Beta, Microsoft has introduced a new technology for exposing JSON from the server named the ASP.NET Web API. You can use the ASP.NET Web API with both ASP.NET MVC and ASP.NET Web Forms applications. The goal of this blog post is to provide you with a brief overview of the features of the new ASP.NET Web API. You learn how to use the ASP.NET Web API to retrieve, insert, update, and delete database records with jQuery. We also discuss how you can perform form validation when using the Web API and use OData when using the Web API. Creating an ASP.NET Web API Controller The ASP.NET Web API exposes JSON data through a new type of controller called an API controller. You can add an API controller to an existing ASP.NET MVC 4 project through the standard Add Controller dialog box. Right-click your Controllers folder and select Add, Controller. In the dialog box, name your controller MovieController and select the Empty API controller template: A brand new API controller looks like this: using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Web.Http; namespace MyWebAPIApp.Controllers { public class MovieController : ApiController { } } An API controller, unlike a standard MVC controller, derives from the base ApiController class instead of the base Controller class. Using jQuery to Retrieve, Insert, Update, and Delete Data Let’s create an Ajaxified Movie Database application. We’ll retrieve, insert, update, and delete movies using jQuery with the MovieController which we just created. Our Movie model class looks like this: namespace MyWebAPIApp.Models { public class Movie { public int Id { get; set; } public string Title { get; set; } public string Director { get; set; } } } Our application will consist of a single HTML page named Movies.html. We’ll place all of our jQuery code in the Movies.html page. Getting a Single Record with the ASP.NET Web API To support retrieving a single movie from the server, we need to add a Get method to our API controller: using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; using MyWebAPIApp.Models; namespace MyWebAPIApp.Controllers { public class MovieController : ApiController { public Movie GetMovie(int id) { // Return movie by id if (id == 1) { return new Movie { Id = 1, Title = "Star Wars", Director = "Lucas" }; } // Otherwise, movie was not found throw new HttpResponseException(HttpStatusCode.NotFound); } } } In the code above, the GetMovie() method accepts the Id of a movie. If the Id has the value 1 then the method returns the movie Star Wars. Otherwise, the method throws an exception and returns 404 Not Found HTTP status code. After building your project, you can invoke the MovieController.GetMovie() method by entering the following URL in your web browser address bar: http://localhost:[port]/api/movie/1 (You’ll need to enter the correct randomly generated port). In the URL api/movie/1, the first “api” segment indicates that this is a Web API route. The “movie” segment indicates that the MovieController should be invoked. You do not specify the name of the action. Instead, the HTTP method used to make the request – GET, POST, PUT, DELETE — is used to identify the action to invoke. The ASP.NET Web API uses different routing conventions than normal ASP.NET MVC controllers. When you make an HTTP GET request then any API controller method with a name that starts with “GET” is invoked. So, we could have called our API controller action GetPopcorn() instead of GetMovie() and it would still be invoked by the URL api/movie/1. The default route for the Web API is defined in the Global.asax file and it looks like this: routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); We can invoke our GetMovie() controller action with the jQuery code in the following HTML page: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Get Movie</title> </head> <body> <div> Title: <span id="title"></span> </div> <div> Director: <span id="director"></span> </div> <script type="text/javascript" src="Scripts/jquery-1.6.2.min.js"></script> <script type="text/javascript"> getMovie(1, function (movie) { $("#title").html(movie.Title); $("#director").html(movie.Director); }); function getMovie(id, callback) { $.ajax({ url: "/api/Movie", data: { id: id }, type: "GET", contentType: "application/json;charset=utf-8", statusCode: { 200: function (movie) { callback(movie); }, 404: function () { alert("Not Found!"); } } }); } </script> </body> </html> In the code above, the jQuery $.ajax() method is used to invoke the GetMovie() method. Notice that the Ajax call handles two HTTP response codes. When the GetMove() method successfully returns a movie, the method returns a 200 status code. In that case, the details of the movie are displayed in the HTML page. Otherwise, if the movie is not found, the GetMovie() method returns a 404 status code. In that case, the page simply displays an alert box indicating that the movie was not found (hopefully, you would implement something more graceful in an actual application). You can use your browser’s Developer Tools to see what is going on in the background when you open the HTML page (hit F12 in the most recent version of most browsers). For example, you can use the Network tab in Google Chrome to see the Ajax request which invokes the GetMovie() method: Getting a Set of Records with the ASP.NET Web API Let’s modify our Movie API controller so that it returns a collection of movies. The following Movie controller has a new ListMovies() method which returns a (hard-coded) collection of movies: using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; using MyWebAPIApp.Models; namespace MyWebAPIApp.Controllers { public class MovieController : ApiController { public IEnumerable<Movie> ListMovies() { return new List<Movie> { new Movie {Id=1, Title="Star Wars", Director="Lucas"}, new Movie {Id=1, Title="King Kong", Director="Jackson"}, new Movie {Id=1, Title="Memento", Director="Nolan"} }; } } } Because we named our action ListMovies(), the default Web API route will never match it. Therefore, we need to add the following custom route to our Global.asax file (at the top of the RegisterRoutes() method): routes.MapHttpRoute( name: "ActionApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); This route enables us to invoke the ListMovies() method with the URL /api/movie/listmovies. Now that we have exposed our collection of movies from the server, we can retrieve and display the list of movies using jQuery in our HTML page: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>List Movies</title> </head> <body> <div id="movies"></div> <script type="text/javascript" src="Scripts/jquery-1.6.2.min.js"></script> <script type="text/javascript"> listMovies(function (movies) { var strMovies=""; $.each(movies, function (index, movie) { strMovies += "<div>" + movie.Title + "</div>"; }); $("#movies").html(strMovies); }); function listMovies(callback) { $.ajax({ url: "/api/Movie/ListMovies", data: {}, type: "GET", contentType: "application/json;charset=utf-8", }).then(function(movies){ callback(movies); }); } </script> </body> </html>     Inserting a Record with the ASP.NET Web API Now let’s modify our Movie API controller so it supports creating new records: public HttpResponseMessage<Movie> PostMovie(Movie movieToCreate) { // Add movieToCreate to the database and update primary key movieToCreate.Id = 23; // Build a response that contains the location of the new movie var response = new HttpResponseMessage<Movie>(movieToCreate, HttpStatusCode.Created); var relativePath = "/api/movie/" + movieToCreate.Id; response.Headers.Location = new Uri(Request.RequestUri, relativePath); return response; } The PostMovie() method in the code above accepts a movieToCreate parameter. We don’t actually store the new movie anywhere. In real life, you will want to call a service method to store the new movie in a database. When you create a new resource, such as a new movie, you should return the location of the new resource. In the code above, the URL where the new movie can be retrieved is assigned to the Location header returned in the PostMovie() response. Because the name of our method starts with “Post”, we don’t need to create a custom route. The PostMovie() method can be invoked with the URL /Movie/PostMovie – just as long as the method is invoked within the context of a HTTP POST request. The following HTML page invokes the PostMovie() method. <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Create Movie</title> </head> <body> <script type="text/javascript" src="Scripts/jquery-1.6.2.min.js"></script> <script type="text/javascript"> var movieToCreate = { title: "The Hobbit", director: "Jackson" }; createMovie(movieToCreate, function (newMovie) { alert("New movie created with an Id of " + newMovie.Id); }); function createMovie(movieToCreate, callback) { $.ajax({ url: "/api/Movie", data: JSON.stringify( movieToCreate ), type: "POST", contentType: "application/json;charset=utf-8", statusCode: { 201: function (newMovie) { callback(newMovie); } } }); } </script> </body> </html> This page creates a new movie (the Hobbit) by calling the createMovie() method. The page simply displays the Id of the new movie: The HTTP Post operation is performed with the following call to the jQuery $.ajax() method: $.ajax({ url: "/api/Movie", data: JSON.stringify( movieToCreate ), type: "POST", contentType: "application/json;charset=utf-8", statusCode: { 201: function (newMovie) { callback(newMovie); } } }); Notice that the type of Ajax request is a POST request. This is required to match the PostMovie() method. Notice, furthermore, that the new movie is converted into JSON using JSON.stringify(). The JSON.stringify() method takes a JavaScript object and converts it into a JSON string. Finally, notice that success is represented with a 201 status code. The HttpStatusCode.Created value returned from the PostMovie() method returns a 201 status code. Updating a Record with the ASP.NET Web API Here’s how we can modify the Movie API controller to support updating an existing record. In this case, we need to create a PUT method to handle an HTTP PUT request: public void PutMovie(Movie movieToUpdate) { if (movieToUpdate.Id == 1) { // Update the movie in the database return; } // If you can't find the movie to update throw new HttpResponseException(HttpStatusCode.NotFound); } Unlike our PostMovie() method, the PutMovie() method does not return a result. The action either updates the database or, if the movie cannot be found, returns an HTTP Status code of 404. The following HTML page illustrates how you can invoke the PutMovie() method: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Put Movie</title> </head> <body> <script type="text/javascript" src="Scripts/jquery-1.6.2.min.js"></script> <script type="text/javascript"> var movieToUpdate = { id: 1, title: "The Hobbit", director: "Jackson" }; updateMovie(movieToUpdate, function () { alert("Movie updated!"); }); function updateMovie(movieToUpdate, callback) { $.ajax({ url: "/api/Movie", data: JSON.stringify(movieToUpdate), type: "PUT", contentType: "application/json;charset=utf-8", statusCode: { 200: function () { callback(); }, 404: function () { alert("Movie not found!"); } } }); } </script> </body> </html> Deleting a Record with the ASP.NET Web API Here’s the code for deleting a movie: public HttpResponseMessage DeleteMovie(int id) { // Delete the movie from the database // Return status code return new HttpResponseMessage(HttpStatusCode.NoContent); } This method simply deletes the movie (well, not really, but pretend that it does) and returns a No Content status code (204). The following page illustrates how you can invoke the DeleteMovie() action: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Delete Movie</title> </head> <body> <script type="text/javascript" src="Scripts/jquery-1.6.2.min.js"></script> <script type="text/javascript"> deleteMovie(1, function () { alert("Movie deleted!"); }); function deleteMovie(id, callback) { $.ajax({ url: "/api/Movie", data: JSON.stringify({id:id}), type: "DELETE", contentType: "application/json;charset=utf-8", statusCode: { 204: function () { callback(); } } }); } </script> </body> </html> Performing Validation How do you perform form validation when using the ASP.NET Web API? Because validation in ASP.NET MVC is driven by the Default Model Binder, and because the Web API uses the Default Model Binder, you get validation for free. Let’s modify our Movie class so it includes some of the standard validation attributes: using System.ComponentModel.DataAnnotations; namespace MyWebAPIApp.Models { public class Movie { public int Id { get; set; } [Required(ErrorMessage="Title is required!")] [StringLength(5, ErrorMessage="Title cannot be more than 5 characters!")] public string Title { get; set; } [Required(ErrorMessage="Director is required!")] public string Director { get; set; } } } In the code above, the Required validation attribute is used to make both the Title and Director properties required. The StringLength attribute is used to require the length of the movie title to be no more than 5 characters. Now let’s modify our PostMovie() action to validate a movie before adding the movie to the database: public HttpResponseMessage PostMovie(Movie movieToCreate) { // Validate movie if (!ModelState.IsValid) { var errors = new JsonArray(); foreach (var prop in ModelState.Values) { if (prop.Errors.Any()) { errors.Add(prop.Errors.First().ErrorMessage); } } return new HttpResponseMessage<JsonValue>(errors, HttpStatusCode.BadRequest); } // Add movieToCreate to the database and update primary key movieToCreate.Id = 23; // Build a response that contains the location of the new movie var response = new HttpResponseMessage<Movie>(movieToCreate, HttpStatusCode.Created); var relativePath = "/api/movie/" + movieToCreate.Id; response.Headers.Location = new Uri(Request.RequestUri, relativePath); return response; } If ModelState.IsValid has the value false then the errors in model state are copied to a new JSON array. Each property – such as the Title and Director property — can have multiple errors. In the code above, only the first error message is copied over. The JSON array is returned with a Bad Request status code (400 status code). The following HTML page illustrates how you can invoke our modified PostMovie() action and display any error messages: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Create Movie</title> </head> <body> <script type="text/javascript" src="Scripts/jquery-1.6.2.min.js"></script> <script type="text/javascript"> var movieToCreate = { title: "The Hobbit", director: "" }; createMovie(movieToCreate, function (newMovie) { alert("New movie created with an Id of " + newMovie.Id); }, function (errors) { var strErrors = ""; $.each(errors, function(index, err) { strErrors += "*" + err + "n"; }); alert(strErrors); } ); function createMovie(movieToCreate, success, fail) { $.ajax({ url: "/api/Movie", data: JSON.stringify(movieToCreate), type: "POST", contentType: "application/json;charset=utf-8", statusCode: { 201: function (newMovie) { success(newMovie); }, 400: function (xhr) { var errors = JSON.parse(xhr.responseText); fail(errors); } } }); } </script> </body> </html> The createMovie() function performs an Ajax request and handles either a 201 or a 400 status code from the response. If a 201 status code is returned then there were no validation errors and the new movie was created. If, on the other hand, a 400 status code is returned then there was a validation error. The validation errors are retrieved from the XmlHttpRequest responseText property. The error messages are displayed in an alert: (Please don’t use JavaScript alert dialogs to display validation errors, I just did it this way out of pure laziness) This validation code in our PostMovie() method is pretty generic. There is nothing specific about this code to the PostMovie() method. In the following video, Jon Galloway demonstrates how to create a global Validation filter which can be used with any API controller action: http://www.asp.net/web-api/overview/web-api-routing-and-actions/video-custom-validation His validation filter looks like this: using System.Json; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http.Controllers; using System.Web.Http.Filters; namespace MyWebAPIApp.Filters { public class ValidationActionFilter:ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { var modelState = actionContext.ModelState; if (!modelState.IsValid) { dynamic errors = new JsonObject(); foreach (var key in modelState.Keys) { var state = modelState[key]; if (state.Errors.Any()) { errors[key] = state.Errors.First().ErrorMessage; } } actionContext.Response = new HttpResponseMessage<JsonValue>(errors, HttpStatusCode.BadRequest); } } } } And you can register the validation filter in the Application_Start() method in the Global.asax file like this: GlobalConfiguration.Configuration.Filters.Add(new ValidationActionFilter()); After you register the Validation filter, validation error messages are returned from any API controller action method automatically when validation fails. You don’t need to add any special logic to any of your API controller actions to take advantage of the filter. Querying using OData The OData protocol is an open protocol created by Microsoft which enables you to perform queries over the web. The official website for OData is located here: http://odata.org For example, here are some of the query options which you can use with OData: · $orderby – Enables you to retrieve results in a certain order. · $top – Enables you to retrieve a certain number of results. · $skip – Enables you to skip over a certain number of results (use with $top for paging). · $filter – Enables you to filter the results returned. The ASP.NET Web API supports a subset of the OData protocol. You can use all of the query options listed above when interacting with an API controller. The only requirement is that the API controller action returns its data as IQueryable. For example, the following Movie controller has an action named GetMovies() which returns an IQueryable of movies: public IQueryable<Movie> GetMovies() { return new List<Movie> { new Movie {Id=1, Title="Star Wars", Director="Lucas"}, new Movie {Id=2, Title="King Kong", Director="Jackson"}, new Movie {Id=3, Title="Willow", Director="Lucas"}, new Movie {Id=4, Title="Shrek", Director="Smith"}, new Movie {Id=5, Title="Memento", Director="Nolan"} }.AsQueryable(); } If you enter the following URL in your browser: /api/movie?$top=2&$orderby=Title Then you will limit the movies returned to the top 2 in order of the movie Title. You will get the following results: By using the $top option in combination with the $skip option, you can enable client-side paging. For example, you can use $top and $skip to page through thousands of products, 10 products at a time. The $filter query option is very powerful. You can use this option to filter the results from a query. Here are some examples: Return every movie directed by Lucas: /api/movie?$filter=Director eq ‘Lucas’ Return every movie which has a title which starts with ‘S’: /api/movie?$filter=startswith(Title,’S') Return every movie which has an Id greater than 2: /api/movie?$filter=Id gt 2 The complete documentation for the $filter option is located here: http://www.odata.org/developers/protocols/uri-conventions#FilterSystemQueryOption Summary The goal of this blog entry was to provide you with an overview of the new ASP.NET Web API introduced with the Beta release of ASP.NET 4. In this post, I discussed how you can retrieve, insert, update, and delete data by using jQuery with the Web API. I also discussed how you can use the standard validation attributes with the Web API. You learned how to return validation error messages to the client and display the error messages using jQuery. Finally, we briefly discussed how the ASP.NET Web API supports the OData protocol. For example, you learned how to filter records returned from an API controller action by using the $filter query option. I’m excited about the new Web API. This is a feature which I expect to use with almost every ASP.NET application which I build in the future.

    Read the article

  • CodePlex Daily Summary for Friday, March 05, 2010

    CodePlex Daily Summary for Friday, March 05, 2010New Projects.svn Folders Cleanup Tool: dotSVN Cleanup is a tool that allows you to remove the .svn folders . Just click, browse, say abracadabra ...and the magic is done. Have fun with...Accord: The Accord framework creates an easy we to integrate any Dependency Injection framework into your project, while abstracting the details of your im...Asp.net MVC Lab: Try asp.net mvc outASP.NET Themes management with Webforms: The provided source is an example for how to use themes in ASP.NET Webforms. this source is the "up to date" support for the article I wroteB&W Port Scanner: B&W Port Scanner (formerly Net Inspector) is a fast TCP Port scan utility. The main idea is support of customizable operations to be performed f...BizTalk SWAT - Simple Web Activity Tracker: This is a web based version of BizTalk HAT. The concept is designed to be able to share and enable sharing of orchestration info easily. Some of th...C# Linear Hash Table: A C# dictionary-like implementation of a linear hash table. It is more memory efficiant than the .NET dictionary, and also almost as fast. NOTE: On...DBF Import Export Wizard: DBF Import Export Wizard is a tool for anyone needing to import DBF files into SQL Server or to export SQL Server tables to a DBF file. This proje...Domain as XML - Driven Development: Visual Studio Code Samples: Domain as XML - Driven Development: Visual Studio Code SamplesEasyDownload: This application allows to manage downloads handling an stack of files and several useful configurationsEos2: .FlightTickets: This application allows to buy flight ticketsFotofly PhotoViewer: A Silverlight control that uses the Fotofly metadata library to show the people in a photo (using Windows Live Photo Gallery People metadata) and a...Fujiy source code: Source code examplesGameSet: This application allows to play games with distributed users.Injectivity (Dependency Injection): Injectivity is a dependency injection framework (written in C#) with a strong focus on the ease of configuration and performance. Having been writt...Inventory: Keep track of inputs, materias and salesLoanTin.Com Source Code: LoanTin.Com - a Social Networking Website as same as Tumblr.com, based on source code of Loantiner Project, allow anyone can share anything to anyo...mysln: my solutions.NumTextBox: TextBox控件重写 之NumTextBox,主要实现的功能是,只允许输入数字,或String,Numeric,Currency,Decimal,Float,Double,Short,Int,Long 修改自:http://www.codeproject.com/KB/edit/num...Quick Performance Monitor: This small utility helps to monitor performance counters without using the full blown perfmon tool from Windows. It supports a number of command li...Runo: Runo ResearchSales: This application allows to manage a hardware storeScrewWiki Form Auth Provider: Enables your ASP.NET site to use Forms Authentication to integrate with your ScrewWiki. User management is performed on a parent site, and cookie i...SDS: Scientific DataSet library and tools: The SDS library makes it easy for .Net developers to read, write and share scalars, vectors, matrices and multidimensional grids which are very com...ShapeSweeper: Minesweeper-like game for the Zune HD. Each hidden object has three properties to discover--location, color, and shape--and all three must be corre...SilverlightExcel: an Excel file viewer in Silverlight 4: SilverlightExcel is a Silverlight application allowing you to open and view Excel files and also create graphs.sPWadmin: pwAdmin is an Web Interface based on JSP that uses the PW-Java API to control an PW-Server.Video Player control in Silverlight: A control for playing video in Silverlight 4 with chapters on timeline control. This player will be easily skinnable and customizable. More Featur...XNA Light Pre Pass Renderer: A demo/sample that shows how to write a light pre pass renderer in XNA.Zimms: Collaboration Site for friends, a code depot, and scratch padNew Releases.svn Folders Cleanup Tool: dotSVN Cleanup Tool: dotSVN Cleanup Tool executableAccord: Alpha: Initial build of the Accord framework.AcPrac: AcPrac Ver 0.1: The first version of AcPrac. It is not fully functional, but rather a version to get the bugs out. Please report all bugs.ASP.NET: ASP.NET Browser Definition Files: This download contains: ASP.NET 4 Browser Definition Files -- You can use the new ASP.NET 4 browser definition files with earlier versions of ASP....B&W Port Scanner: Black`n`White Port Scanner 1.0: B&W Port Scanner 1.0 Final Release Date: 03.03.2010 Black`n`WhiteBizTalk SWAT - Simple Web Activity Tracker: BizTalk SWAT: This is a web based version of BizTalk HAT. The concept is designed to be able to share and enable sharing of orchestration info easily. It uses th...BTP Tools: CSB+CUV+HCSB dict files 2010-03-04: 5. is now missing a space between the Strong’s number and the Count: >CSB Translation: 圣所 7, 至圣所G39+G394 it should be: CSB Translation: 圣所 7, 至圣所G...C# Linear Hash Table: Linear Hash Table: First working version of the Linear Hash Table.Cassiopeia: WinTools 1.0 beta: First ReleaseComposure: Caliburn-44007-trunk-vs2010.net40: This is a very simple conversion of the Caliburn trunk (rev 44007) for use in Visual Studio 2010 RC1 built against .NET40. Because the conversion w...Cover Creator: CoverCreator 1.3.0: English and Polish version. Functionality to add image to the front page. Load / save covers.DBF Import Export Wizard: DBF Import Export Wizard Source Code: Version 0.1.0.3DBF Import Export Wizard: DBF_Import_Export_Wizard Setup 0.1.0.3: Zip file contains Setup.exeESB Toolkit Extensions: Tellago BizTalk ESB 2.0 Toolkit Extensions v0.2: Windows Installer file that installs Library on a BizTalk ESB 2.0 system. This Install automatically configures the esb.config to use the new compo...Fotofly PhotoViewer: Fotofly Photoview v0.1: The first public release. Based on a Silverlight application I have been using for over a year at www.tassography.com. This version uses Fotofly v0...HPC with GPUs applied to CG: Cuda Soft Bodies simulation: Cuda src for soft bodiesHPC with GPUs applied to CG: Full Soft Bodies src: full src code for soft bodies simulationInjectivity (Dependency Injection): 2.8.166.2135: Release 2.8.166.2135 of the Injectivity dependency injection framework.Line Counter: 1.5 (Code Outline Preview): This version contains preview of the code outline feature, you can now view C# code outline within Line Counter. Note that the code outline now onl...Micajah Mindtouch Deki Wiki Copier: MicajahWikiCopier: You should use the following line arguments: WikiCopier.exe "http://oldwikiwithdata.wik.is/@api/deki" "login" "password" "http://newwiki.somename.l...ncontrols: Alpha 0.4.0.1: Added some example on the Console Project.NumTextBox: NumTextBox初始版本: TextBox控件重写 之NumTextBox,主要实现的功能是,只允许输入数字,或String,Numeric,Currency,Decimal,Float,Double,Short,Int,Long 此为初始版本PSCodeplex: PS CodePlex 0.2: PS CodePlex 0.2 has some breaking changes to the parameters. A few of the parameters are renamed and a few are made as switch parameters. Add-Rele...Quick Performance Monitor: QPerfMon First release - Version 1.0.0: The first release of the utility.RapidWebDev - .NET Enterprise Software Development Infrastructure: ProductManagement Quick Sample 0.2: This is a sample product management application to demonstrate how to develop enterprise software in RapidWebDev. The glossary of the system are ro...ScrewWiki Form Auth Provider: ScrewWiki Forms Authentication: Initial ReleaseSee.Sharper: See.Sharper.Docs-1.10.3.4: HTML documentation (including Doxygen project)See.Sharper: See.Sharper-1.10.3.4: Solution (Source files, debug and release binaries)Solar.Generic: Solar.Generic 0.8.0.0 Beta (Revised, Renamed): Solar.Generic 0.8.0.0 (Revised & Renamed) Renamed project from Solar.Commons to Solar.Generic. Project solution file is now in format of Visual ...Solar.Security: Solar.Security 1.1.0.0: Performed several major refactorings of code base. Stripped In-Memory implementation of IConfiguration interface of transactional behavior due to...sPWadmin: pwAdmin v0.7: -Star System Simulator: Star System Simulator 2.3: Changes in this release: Fixed several localisation issues. Features in this release: Model star systems in 3D. Euler-Cromer method. Improved...SysI: sysi, stable and ready: This time for sure.TheWhiteAmbit: TheWhiteAmbit - Demo: Two little demos demonstrating: - fast realtime raytracing - generating bent normals for shading (CUDA capable GPU needed = nVidia GeForce >8x00)VsTortoise - a TortoiseSVN add-in for Microsoft Visual Studio: VsTortoise Build 22 Beta: Build 22 (beta) New: Visual Studio 2010 RC support (VsTortoise for Visual Studio 2010 RC screenshots) New: VsTortoise integrates in to Solution E...WinMergeFS: WinMergeFS 0.1.42128alpha: WinMergeFS provides AuFS functionality for windows. With WinMergeFS users can mount multiple directories into a virtual drive. Plugin based root se...WSDLGenerator: WSDLGenerator 0.0.0.2: - Bugs fixed - Code refactored - Added support for custom typesXNA Light Pre Pass Renderer: LightPrePassRendererXNA: Zipped source code for the light pre pass renderer made with XNA.Most Popular ProjectsMetaSharpRawrWBFS ManagerAJAX Control ToolkitMicrosoft SQL Server Product Samples: DatabaseSilverlight ToolkitWindows Presentation Foundation (WPF)LiveUpload to FacebookASP.NETMicrosoft SQL Server Community & SamplesMost Active ProjectsUmbraco CMSRawrBlogEngine.NETSDS: Scientific DataSet library and toolsMapWindow GISpatterns & practices – Enterprise LibraryjQuery Library for SharePoint Web ServicesIonics Isapi Rewrite FilterMDT Web FrontEndDiffPlex - a .NET Diff Generator

    Read the article

  • OWB 11gR2 - Early Arriving Facts

    - by Dawei Sun
    A common challenge when building ETL components for a data warehouse is how to handle early arriving facts. OWB 11gR2 introduced a new feature to address this for dimensional objects entitled Orphan Management. An orphan record is one that does not have a corresponding existing parent record. Orphan management automates the process of handling source rows that do not meet the requirements necessary to form a valid dimension or cube record. In this article, a simple example will be provided to show you how to use Orphan Management in OWB. We first import a sample MDL file that contains all the objects we need. Then we take some time to examine all the objects. After that, we prepare the source data, deploy the target table and dimension/cube loading map. Finally, we run the loading maps, and check the data in target dimension/cube tables. OK, let’s start… 1. Import MDL file and examine sample project First, download zip file from here, which includes a MDL file and three source data files. Then we open OWB design center, import orphan_management.mdl by using the menu File->Import->Warehouse Builder Metadata. Now we have several objects in BI_DEMO project as below: Mapping LOAD_CHANNELS_OM: The mapping for dimension loading. Mapping LOAD_SALES_OM: The mapping for cube loading. Dimension CHANNELS_OM: The dimension that contains channels data. Cube SALES_OM: The cube that contains sales data. Table CHANNELS_OM: The star implementation table of dimension CHANNELS_OM. Table SALES_OM: The star implementation table of cube SALES_OM. Table SRC_CHANNELS: The source table of channels data, that will be loaded into dimension CHANNELS_OM. Table SRC_ORDERS and SRC_ORDER_ITEMS: The source tables of sales data that will be loaded into cube SALES_OM. Sequence CLASS_OM_DIM_SEQ: The sequence used for loading dimension CHANNELS_OM. Dimension CHANNELS_OM This dimension has a hierarchy with three levels: TOTAL, CLASS and CHANNEL. Each level has three attributes: ID (surrogate key), NAME and SOURCE_ID (business key). It has a standard star implementation. The orphan management policy and the default parent setting are shown in the following screenshots: The orphan management policy options that you can set for loading are: Reject Orphan: The record is not inserted. Default Parent: You can specify a default parent record. This default record is used as the parent record for any record that does not have an existing parent record. If the default parent record does not exist, Warehouse Builder creates the default parent record. You specify the attribute values of the default parent record at the time of defining the dimensional object. If any ancestor of the default parent does not exist, Warehouse Builder also creates this record. No Maintenance: This is the default behavior. Warehouse Builder does not actively detect, reject, or fix orphan records. While removing data from a dimension, you can select one of the following orphan management policies: Reject Removal: Warehouse Builder does not allow you to delete the record if it has existing child records. No Maintenance: This is the default behavior. Warehouse Builder does not actively detect, reject, or fix orphan records. (More details are at http://download.oracle.com/docs/cd/E11882_01/owb.112/e10935/dim_objects.htm#insertedID1) Cube SALES_OM This cube is references to dimension CHANNELS_OM. It has three measures: AMOUNT, QUANTITY and COST. The orphan management policy setting are shown as following screenshot: The orphan management policy options that you can set for loading are: No Maintenance: Warehouse Builder does not actively detect, reject, or fix orphan rows. Default Dimension Record: Warehouse Builder assigns a default dimension record for any row that has an invalid or null dimension key value. Use the Settings button to define the default parent row. Reject Orphan: Warehouse Builder does not insert the row if it does not have an existing dimension record. (More details are at http://download.oracle.com/docs/cd/E11882_01/owb.112/e10935/dim_objects.htm#BABEACDG) Mapping LOAD_CHANNELS_OM This mapping loads source data from table SRC_CHANNELS to dimension CHANNELS_OM. The operator CHANNELS_IN is bound to table SRC_CHANNELS; CHANNELS_OUT is bound to dimension CHANNELS_OM. The TOTALS operator is used for generating a constant value for the top level in the dimension. The CLASS_FILTER operator is used to filter out the “invalid” class name, so then we can see what will happen when those channel records with an “invalid” parent are loading into dimension. Some properties of the dimension operator in this mapping are important to orphan management. See the screenshot below: Create Default Level Records: If YES, then default level records will be created. This property must be set to YES for dimensions and cubes if one of their orphan management policies is “Default Parent” or “Default Dimension Record”. This property is set to NO by default, so the user may need to set this to YES manually. LOAD policy for INVALID keys/ LOAD policy for NULL keys: These two properties have the same meaning as in the dimension editor. The values are set to the same as the dimension value when user drops the dimension into the mapping. The user does not need to modify these properties. Record Error Rows: If YES, error rows will be inserted into error table when loading the dimension. REMOVE Orphan Policy: This property is used when removing data from a dimension. Since the dimension loading type is set to LOAD in this example, this property is disabled. Mapping LOAD_SALES_OM This mapping loads source data from table SRC_ORDERS and SRC_ORDER_ITEMS to cube SALES_OM. This mapping seems a little bit complicated, but operators in the red rectangle are used to filter out and generate the records with “invalid” or “null” dimension keys. Some properties of the cube operator in a mapping are important to orphan management. See the screenshot below: Enable Source Aggregation: Should be checked in this example. If the default dimension record orphan policy is set for the cube operator, then it is recommended that source aggregation also be enabled. Otherwise, the orphan management processing may produce multiple fact rows with the same default dimension references, which will cause an “unstable rowset” execution error in the database, since the dimension refs are used as update match attributes for updating the fact table. LOAD policy for INVALID keys/ LOAD policy for NULL keys: These two properties have the same meaning as in the cube editor. The values are set to the same as in the cube editor when the user drops the cube into the mapping. The user does not need to modify these properties. Record Error Rows: If YES, error rows will be inserted into error table when loading the cube. 2. Deploy objects and mappings We now can deploy the objects. First, make sure location SALES_WH_LOCAL has been correctly configured. Then open Control Center Manager by using the menu Tools->Control Center Manager. Expand BI_DEMO->SALES_WH_LOCAL, click SALES_WH node on the project tree. We can see the following objects: Deploy all the objects in the following order: Sequence CLASS_OM_DIM_SEQ Table CHANNELS_OM, SALES_OM, SRC_CHANNELS, SRC_ORDERS, SRC_ORDER_ITEMS Dimension CHANNELS_OM Cube SALES_OM Mapping LOAD_CHANNELS_OM, LOAD_SALES_OM Note that we deployed source tables as well. Normally, we import source table from database instead of deploying them to target schema. However, in this example, we designed the source tables in OWB and deployed them to database for the purpose of this demonstration. 3. Prepare and examine source data Before running the mappings, we need to populate and examine the source data first. Run SRC_CHANNELS.sql, SRC_ORDERS.sql and SRC_ORDER_ITEMS.sql as target user. Then we check the data in these three tables. Table SRC_CHANNELS SQL> select rownum, id, class, name from src_channels; Records 1~5 are correct; they should be loaded into dimension without error. Records 6,7 and 8 have null parents; they should be loaded into dimension with a default parent value, and should be inserted into error table at the same time. Records 9, 10 and 11 have “invalid” parents; they should be rejected by dimension, and inserted into error table. Table SRC_ORDERS and SRC_ORDER_ITEMS SQL> select rownum, a.id, a.channel, b.amount, b.quantity, b.cost from src_orders a, src_order_items b where a.id = b.order_id; Record 178 has null dimension reference; it should be loaded into cube with a default dimension reference, and should be inserted into error table at the same time. Record 179 has “invalid” dimension reference; it should be rejected by cube, and inserted into error table. Other records should be aggregated and loaded into cube correctly. 4. Run the mappings and examine the target data In the Control Center Manager, expand BI_DEMO-> SALES_WH_LOCAL-> SALES_WH-> Mappings, right click on LOAD_CHANNELS_OM node, click Start. Use the same way to run mapping LOAD_SALES_OM. When they successfully finished, we can check the data in target tables. Table CHANNELS_OM SQL> select rownum, total_id, total_name, total_source_id, class_id,class_name, class_source_id, channel_id, channel_name,channel_source_id from channels_om order by abs(dimension_key); Records 1,2 and 3 are the default dimension records for the three levels. Records 8, 10 and 15 are the loaded records that originally have null parents. We see their parents name (class_name) is set to DEF_CLASS_NAME. Those records whose CHANNEL_NAME are Special_4, Special_5 and Special_6 are not loaded to this table because of the invalid parent. Error Table CHANNELS_OM_ERR SQL> select rownum, class_source_id, channel_id, channel_name,channel_source_id, err$$$_error_reason from channels_om_err order by channel_name; We can see all the record with null parent or invalid parent are inserted into this error table. Error reason is “Default parent used for record” for the first three records, and “No parent found for record” for the last three. Table SALES_OM SQL> select a.*, b.channel_name from sales_om a, channels_om b where a.channels=b.channel_id; We can see the order record with null channel_name has been loaded into target table with a default channel_name. The one with “invalid” channel_name are not loaded. Error Table SALES_OM_ERR SQL> select a.amount, a.cost, a.quantity, a.channels, b.channel_name, a.err$$$_error_reason from sales_om_err a, channels_om b where a.channels=b.channel_id(+); We can see the order records with null or invalid channel_name are inserted into error table. If the dimension reference column is null, the error reason is “Default dimension record used for fact”. If it is invalid, the error reason is “Dimension record not found for fact”. Summary In summary, this article illustrated the Orphan Management feature in OWB 11gR2. Automated orphan management policies improve ETL developer and administrator productivity by addressing an important cause of cube and dimension load failures, without requiring developers to explicitly build logic to handle these orphan rows.

    Read the article

  • How to animate an non-closed path with CAShapeLayer?

    - by mystify
    On GitHub you can find an example for CAShapeLayer which animates an path. It animates a pentagon turning into a star. First: This works only in the iPhone simulator. OS 3.0 on the device shows serious bugs with this code. But I can't find anything wrong in there. However, I tried to animate an path which is not closed. To put it simply: A few straight lines. Is there anything special I must do to get this work properly on the device? - (void)loadView { UIView *appView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; appView.backgroundColor = [UIColor blackColor]; self.view = appView; [appView release]; rootLayer = [CALayer layer]; rootLayer.frame = self.view.bounds; [self.view.layer addSublayer:rootLayer]; //Pentagon Path pentagonPath = CGPathCreateMutable(); CGPathMoveToPoint(pentagonPath, nil, 10.0f, 270.0f); CGPathAddLineToPoint(pentagonPath, nil, 100.0f, 270.0f); CGPathAddLineToPoint(pentagonPath, nil, 110.0f, 270.0f); CGPathAddLineToPoint(pentagonPath, nil, 120.0f, 270.0f); CGPathAddLineToPoint(pentagonPath, nil, 130.0f, 270.0f); CGPathAddLineToPoint(pentagonPath, nil, 310.0f, 270.0f); //CGPathCloseSubpath(pentagonPath); //Star Path starPath = CGPathCreateMutable(); CGPathMoveToPoint(starPath, nil, 10.0f, 270.0f); CGPathAddLineToPoint(starPath, nil, 100.0f, 270.0f); CGPathAddLineToPoint(starPath, nil, 210.0f, 270.0f); CGPathAddLineToPoint(starPath, nil, 220.0f, 260.0f); CGPathAddLineToPoint(starPath, nil, 230.0f, 270.0f); CGPathAddLineToPoint(starPath, nil, 310.0f, 270.0f); //CGPathCloseSubpath(starPath); //Create Shape shapeLayer = [CAShapeLayer layer]; //shapeLayer.path = pentagonPath; UIColor *col = [UIColor colorWithWhite:0.9 alpha:1.0]; //shapeLayer.fillColor = col.CGColor; shapeLayer.strokeColor = col.CGColor; shapeLayer.lineWidth = 3.0f; // shapeLayer.contents = [UIImage imageNamed:@"test.png"]; shapeLayer.fillRule = kCAFillRuleEvenOdd; [rootLayer addSublayer:shapeLayer]; [self performSelector:@selector(startAnimation) withObject:nil afterDelay:1.0]; } -(void)startAnimation { CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"]; animation.duration = 2.0; animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; animation.repeatCount = 1e100f; animation.autoreverses = YES; animation.fromValue = (id)pentagonPath; animation.toValue = (id)starPath; [shapeLayer addAnimation:animation forKey:@"animatePath"]; } Note this lines, where I just make straight lines with a small peak which is animated: //Pentagon Path pentagonPath = CGPathCreateMutable(); CGPathMoveToPoint(pentagonPath, nil, 10.0f, 270.0f); CGPathAddLineToPoint(pentagonPath, nil, 100.0f, 270.0f); CGPathAddLineToPoint(pentagonPath, nil, 110.0f, 270.0f); CGPathAddLineToPoint(pentagonPath, nil, 120.0f, 270.0f); CGPathAddLineToPoint(pentagonPath, nil, 130.0f, 270.0f); CGPathAddLineToPoint(pentagonPath, nil, 310.0f, 270.0f); //CGPathCloseSubpath(pentagonPath); //Star Path starPath = CGPathCreateMutable(); CGPathMoveToPoint(starPath, nil, 10.0f, 270.0f); CGPathAddLineToPoint(starPath, nil, 100.0f, 270.0f); CGPathAddLineToPoint(starPath, nil, 210.0f, 270.0f); CGPathAddLineToPoint(starPath, nil, 220.0f, 260.0f); CGPathAddLineToPoint(starPath, nil, 230.0f, 270.0f); CGPathAddLineToPoint(starPath, nil, 310.0f, 270.0f); I don't want a closed and filled path, but only simple lines with some color and thickness. The nasty thing on the device is, that the first point seems to move towards the right side of the screen for no reason. On the simulator though, it works perfectly fine. Maybe something is wrong with this setup?

    Read the article

  • Building a Data Mart with Pentaho Data Integration Video Review by Diethard Steiner, Packt Publishing

    - by Compudicted
    Originally posted on: http://geekswithblogs.net/Compudicted/archive/2014/06/01/building-a-data-mart-with-pentaho-data-integration-video-review-again.aspx The Building a Data Mart with Pentaho Data Integration Video by Diethard Steiner from Packt Publishing is more than just a course on how to use Pentaho Data Integration, it also implements and uses the principals of the Data Warehousing (and I even heard the name of Ralph Kimball in the video). Indeed, a video watcher should be familiar with its concepts as the Star Schema, Slowly Changing Dimension types, etc. so I suggest prior to watching this course to consider skimming through the Data Warehouse concepts (if unfamiliar) or even better, read the excellent Ralph’s The Data Warehouse Tooolkit. By the way, the author expands beyond using Pentaho along to MySQL and MonetDB which is a real icing on the cake! Indeed, I even suggest the name of the course should be ‘Building a Data Warehouse with Pentaho’. To successfully complete the course one needs to know some Linux (Ubuntu used in the course), the VI editor and the Bash command shell, but it seems that similar requirements would also apply to the Windows OS. Additionally, knowing some basic SQL would not hurt. As I had said, MonetDB is used in this course several times which seems to be not anymore complex than say MySQL, but based on what I read is very well suited for fast querying big volumes of data thanks to having a columnstore (vertical data storage). I don’t see what else can be a barrier, the material is very digestible. On this note, I must add that the author does not cover how to acquire the software, so here is what I found may help: Pentaho: the free Community Edition must be more than anyone needs to learn it. Or even go into a POC. MonetDB can be downloaded (exists for both, Linux and Windows) from http://goo.gl/FYxMy0 (just see the appropriate link on the left). The author seems to be using Eclipse to run SQL code, one can get it from http://goo.gl/5CcuN. To create, or edit database entities and/or schema otherwise one can use a universal tool called SQuirreL, get it from http://squirrel-sql.sourceforge.net.   Next, I must confess Diethard is very knowledgeable in what he does and beyond. However, there will be some accent heard to the user of the course especially if one’s mother tongue language is English, but it I got over it in a few chapters. I liked the rate at which the material is being presented, it makes me feel I paid for every second Eventually, my impressions are: Pentaho is an awesome ETL offering, it is worth learning it very much (I am an ETL fan and a heavy user of SSIS) MonetDB is nice, it tickles my fancy to know it more Data Warehousing, despite all the BigData tool offerings (Hive, Scoop, Pig on Hadoop), using the traditional tools still rocks Chapters 2 to 6 were the most fun to me with chapter 8 being the most difficult.   In terms of closing, I highly recommend this video to anyone who needs to grasp Pentaho concepts quick, likewise, the course is very well suited for any developer on a “supposed to be done yesterday” type of a project. It is for a beginner to intermediate level ETL/DW developer. But one would need to learn more on Data Warehousing and Pentaho, for such I recommend the 5 star Pentaho Data Integration 4 Cookbook. Enjoy it! Disclaimer: I received this video from the publisher for the purpose of a public review.

    Read the article

< Previous Page | 8 9 10 11 12 13 14 15 16 17 18 19  | Next Page >