Programming 101: How to Create Groupings

If you are new to programming, there may be certain solutions that escape you completely, depending on the problem you are trying to solve.  Sometimes it’s as simple as not knowing of a function or syntax.  Other times, it’s a little more complex because it involves logic.

What is Programming Logic?

Before we dive into code, I want to briefly explain what I mean when I say logicProgramming is essentially using code to creatively solve a problem.  Throughout your code could be a logical set of instructions that determines when to execute certain pieces. This is conditional logic.

Many times, the logic to solve a problem is pretty simple:

<?php 
if ( x == 2 ){
    echo 'This is the second record';  
}
?>

Using this kind of conditional logic is essential when you are learning how to program and, over time, will allow you to perform more complex statements.

What is a Grouping?

A grouping is where you sort a set of data into logical sections.  A great example of this is when you see an events calendar that is sorted by date.  There is a single heading for the date and each record that matches that date is listed underneath.

December 10, 2011

  • 12/10/2011 10:00 am – Mary’s Recital
  • 12/10/2011 12:00 pm – Bob’s Cookout

December 11, 2011

  • 12/11/2011 2:00 pm – Computer Science Meetup
  • 12/11/2011 5:00 pm – Art Festival

This sort of breakdown continues on until you get to the end of your data.

How do I make a Grouping automatically?

The above list is easy to create manually, but what do you do when you have hundreds or even thousands of events in a database?  Of course, that’s where programming is going to help us.

Here’s our pseudo code:

  • Query our events database – get all records for the current week
  • Loop through each record and print our information out to the screen
  • If this event’s date is not the same as the previous event’s date, print out our new date heading and continue

Here’s our actual code:

<!--?php<br /-->/* Setup our query - assuming we've already connected to our database */
$query = 'SELECT Title, StartDate, StartTime
FROM events
WHERE WEEK(StartDate) = "12-11-2011"
ORDER BY StartDate ASC, StartTime ASC';

$result = mysql_query( $query );

echo '
<ul>';

/* Loop through our events data */
while ( $row = mysql_fetch_array( $result ) ) {

    /* Assign each row to a variable */
    $title = $row['Title'];
    $date = $row['StartDate'];
    $time = $row['StartTime'];

    /* Handles the date grouping */
    if ( $last != $date ) {
        echo '
	<li class="date_heading">' . date( 'D M d, Y', strtotime( $date ) ) . '</li>
';

        $last = $date;
    }

    /* Output the event name and time below */
    echo '
	<li>' . $title . '-' . $time . '</li>
';
}

echo ';
?>

As you can see, with very little code, we can group our data. What’s even better is that the method can apply to any kind of grouping you need, not just dates! For example, you could have a directory of people and want to group alphabetically by last name (if ( $last != $last_name )). Or, you could have a blog archive page with categories grouped by name and the posts underneath (if ( $last != $category )). There are tons of possibilities.

If you plan to work with a lot of data that needs to be grouped into common headers, save this little snippet of code because it could come in handy.

WordPress & PHP (CCW Part 3)

Working with UA’s WordPress Theme

UA’s WordPress theme makes use of an options panel which is located inside the WordPress dashboard. This allows for a more hands off the code type of customization. There are play by play instructions on how to use the theme located on UA’s Web Guide, http://webguide.ua.edu/wordpress.html, so we won’t be covering that.

What we will be discussing is what a WordPress Theme is composed of and how the system works to display information.

WordPress file organization/main editable pages

When you’re looking through WordPress files, you might want to know which are relatively safe to bring up and edit code wise.

WordPress takes a theme and chops it up so that it can mix and match- separating elements in a way that allows all pages to make use of common parts. (Think of it like a Mr. Potato Head.)

For example: Your header should be the same on every page- regardless of the content. Thus, WordPress takes the header and creates a file called header.php which should contain all your header elements. When you call up a page in your browser, the PHP in the content part of the page calls ‘get_header’ and so the header appears at the top of your page.

Main structural elements:

index.php                your main ‘blog’ page and default home

statichome.php     a homepage that does not have blog style content rotating on it (optional- you make it)

single.php                the base page for all your blog pages or ‘posts’

page.php
                  the base page for all your ‘pages’

sidebar.php            where your sidebar is located

header.php             where your primary horizontal navigation is located

footer.php               where your footer is located

The footer, header, and sidebar will generally have your links and navigational elements. The index, statichome, single, and page will have your content. 

Content structure/hierarchy is shown below.

Structure of a completely built WordPress page is shown below.

The header will contain all your CSS, just like normal as well as your horizontal navigation.

The content page will have php linking it to the header, sidebar, and footer. The content page shown here happens to be the blog index page.

The sidebar contains your secondary links and can be placed within your content page where ever you want it to appear.

The footer will contain all your animation scripts such as JavaScript and its libraries.

PHP in WordPress

This is not a programming course, so we’re not going to dive into the proverbial PHP pool. However, that being said, I do want to give you a few helpful scripts and explain what they do. Why? Well, if you choose to have a ‘statichome.php’ that will do some things in connection with WordPress’ database- well, it just won’t fly the HTML way.

This is where PHP template tags come in. For a complete list, please refer to the WordPress Codex: http://codex.wordpress.org/Template_Tags

Template tags are used within your blog’s .php template pages to display information dynamically or otherwise customize your site. What most tags will do is pull information out of the database. Other tags arrange structure- such as the “get_header” or “get_footer” tags that attach those elements to a page.php or single.php.

Referencing

WordPress has its own database for managing content and information. In order to access the information, a PHP script is needed to make the browser load the info from the database.

In order to reference things housed in the database without knowing the entire location of the object, we use:<?php bloginfo(); ?>

This PHP gets information from the WordPress database.

A practical example and most likely the only time you’ll really use this is for images:

<img src="<?php bloginfo("template_url"); ?>/images/name.jpg" />

Elements you might like to customize display on

Some elements you might want to customize display on would be the date and time.

<?php the_date (); ?>                             <?php the_time(); ?>

You might want something short like “Thu, 21 Dec 2034” or a little longer as in “Thursday 21, December 2034”. So where are the above two examples used? They can be used anywhere- but mostly you’ll see them as ‘date posted’ in blog posts or news releases.

How to use:

<?php the_date (‘m-d-Y‘); ?>        displays:    month-day-year   ex:  08-03-2034

<?php the_date (‘M  d, Y‘); ?>     displays:    month day, year   ex:  Aug 03, 2034

<?php the_date (‘F j, Y‘); ?>       displays:    month day, year   ex:  August  3, 2034

<?php the_time(‘D, g:i a’);  ?>    displays:    day, hour:minutes am/pm  ex: Tue, 9:45 am

<?php the_time(‘l, G:i’);  ?>        displays:    day, hour:minutes  ex: Tuesday, 17:45

For more information on formatting date and time, see: http://codex.wordpress.org/Formatting_Date_and_Time

Within WordPress’ Control Panel

Most organizational customization can be easily achieved within the control panel. One of the major adjustments you’ll make in the control panel is deciding your site’s style.

Site Styles

There are 3 kinds of website homepages available: Blog Style, Static Homepage, or a combination of the two.

Blog Style
By default, WordPress will display the homepage of your website as a blog. For many themes the default will be to use a blog-style homepage.

Static Homepage
If you would like to use a static homepage to give your website a traditional website feel, there are several steps you must take:

  1. Login to your WordPress account and create a new page called ‘statichome’. Only fill in the title box. Leave the rest of the page blank.
  2. To the right is a section called ‘Attributes’. Under ‘Template’ select ‘Static Home Page’ and publish the page.
  3. Make a new Page called ‘blog’ and publish. (Once again, only fill in the title box, and this time do not make any changes in the ‘Attributes’ section.)
  4. Under ‘Settings’ on the main left toolbar, select ‘Reading’.
  5. Select ‘static page’ and set the front page as ‘statichome’ and the posts page as ‘blog’. Then save the changes.

Now when you visit the actual site, your static homepage will show up as the index instead of the blog page.

Static Homepage with Blog Page
If you decide to use a static homepage, but you still want to have a blog on your site elsewhere, all you need to do is include an absolute link to your blog within your main or side navigation. You can find this link by going to the ‘blog’ page that you created above.

UA WordPress Theme: Contact Form Shortcode

A minor update has been pushed out to the UA WordPress Theme that adds a bit of new functionality as well as an update to the form HTML/CSS.

The first major difference is the addition of two new shortcodes: [linksbox] and [uaform].  If you are unfamiliar with shortcodes, they are custom WordPress tags that allow you to add things which normally require lots of code.  Please refer to the UA WordPress Theme page on WebGuide for more information on the [linksbox] shortcode.

The shortcode I want to focus on today is [uaform].  By adding [uaform] to your post/page, you will have a fully functional contact form.

Here are some of the features:

  • Shortcode attributes to control form name/email subject and email(s) it sends to
  • JS validation using the jQuery Form Validation plugin
  • Logic verification question
  • SPAM honey pot field

The main reasons I chose to write my own shortcode and not use a plugin to process my data is twofold:

  1. I wanted an integrated shortcode to ship with our UA WordPress Theme
  2. I scoured the Internet in search of a similar solution and was never able to find anything

With that in mind and before we get to the code, here is how to customize the shortcode, should you want to.

Customization Options

Option Description Choices Default Setting
form_name The name of the form and subject of email Any string of text Contact Us
to Email(s) the message will be sent to. Single or Multiple emails. If using multiple emails, separate each with a comma Administrator’s email

Here are several examples how you would use some of those attributes:

[uaform to="nottheadmin@test.com"]

[uaform form_name="Website Feedback"]

[uaform form_name="Ask Us a Question" to="firstperson@test.com,secondperson@test.com"]

PHP

Before you can use the shortcode, you will need to add the following PHP to your functions.php file.  If you are using the UA WordPress Theme, you do not have to do this.

<?php

/************************************
Smart Jquery Inclusion
************************************/
if(!is_admin()){
wp_deregister_script('jquery');
wp_register_script('jquery', ("http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"), false, '1.4.2');
wp_enqueue_script('jquery');
wp_enqueue_script('jquery-form-validation', 'http://ajax.microsoft.com/ajax/jquery.validate/1.7/jquery.validate.pack.js', '' , '1.7', true);
}

/************************************
Contact Form shortcode

form_name - name of form, also used as subject of email. DEFAULT is Contact Us
to - email(s) the message will be sent to.  Multiple emails can be used; separate each email with a comma. DEFAULT is the Administrator's email address
************************************/
function ua_form($atts){
if(($_SESSION['contact_form_success'])){
$contact_form_success = '<p id="form_success">Thank you for your inquiry. We will contact you shortly to answer your questions.</p>';
unset($_SESSION['contact_form_success']);
}

$admin_email = get_bloginfo('admin_email');

extract(shortcode_atts(array(
'form_name' => 'Contact Us',
'to' => $admin_email
), $atts));

$_SESSION['ua_form_subject'] = $form_name;
$_SESSION['ua_form_to'] = $to;

$output .= $contact_form_success . '<form method="post" action="' . get_permalink() . '" id="contactform">
<fieldset>
<div>
<h3>' . $form_name . '</h3>
</div>
<ul>
<li>
<label>Name <span>*</span></label>
<div>
<input type="text" name="name" maxlength="100" id="name" />
</div>
</li>
<li>
<label>Department/Organization</label>
<div>
<input type="text" name="department" maxlength="150" id="dept" />
</div>
</li>
<li>
<label>Telephone Number</label>
<div>
<input type="text" name="phone" maxlength="50" id="phone" />
</div>
</li>
<li>
<label>E-mail Address <span>*</span></label>
<div>
<input type="text" name="email" maxlength="150" id="email" />
</div>
</li>
<li>
<label>Enter your question, comment, or issue report <span>*</span></label>
<div>
<textarea name="question" cols="50" rows="10" id="question"></textarea>
</div>
</li>
<li>
<label>Please enter any two digits with <strong>no</strong> spaces (Example: 12) <span>*</span></label>
<div>
<input type="text" name="secret" id="secret" />
</div>
</li>
<div style="display:none;">
<li>
<label for="spam">This box is for spam protection - <strong>please leave it blank</strong>:</label>
<div>
<input name="spam" id="spam" />
</div>
</li>
</div>
<li>
<input type="submit" name="submit" value="Submit" id="sendmail" />
</li>
<input type="hidden" name="contact_form_submitted" value="true">
</ul>
</fieldset>
</form>';
return $output;
}
add_shortcode('uaform', 'ua_form');

function ua_form_process() {
session_start();

if(!isset($_POST['contact_form_submitted'])) return;

foreach($_POST as $key=>$value){
$key = strtolower(str_replace('_', ' ', $key));
$form_fields[$key] = $value;

$value = strip_tags(htmlentities($value));

if($key == "spam" || $key == "secret" || $key == "submit" || $key == "contact form submitted"){
//do nothing
}
else{
$message .= ucwords($key) . ": $value\n";
}
}

//Test for spam and verification, then email
//"secret" is a REQUIRED field name in order for this script to work
if($form_fields["spam"] == '' && is_numeric($form_fields["secret"]) && strlen($form_fields["secret"]) == 2){
$to = $_SESSION['ua_form_to'];
$subject = $_SESSION['ua_form_subject'];

$mail_sent = mail($to, $subject, $message, "From: " . $form_fields["name"] . "<" . $form_fields["email"] . ">");
}

if(!$mail_sent) wp_die("Error: <strong>verification failed</strong>.  Your form was not submitted due to an incorrect answer for the verification question. Please be sure to enter the answer carefully.", "Verification Failed");

$_SESSION['contact_form_success'] = 1;

header('Location: ' . $_SERVER['HTTP_REFERER']);
exit();
}
add_action('init', 'ua_form_process');

function ua_form_validation(){
echo '<script>
jQuery(document).ready(function(){
jQuery("#contactform").validate({
rules:{
secret:{
maxlength:2
}
},
errorPlacement: function(error, element) {
if(element.is(":radio") || element.is(":checkbox")){
error.appendTo(element.parent().parent());
}
else{
error.insertAfter(element);
}
}
});
});
</script>';
}
add_action('wp_footer', 'ua_form_validation');

?>

CSS

Here is the CSS that we use to get a nice looking form (thanks to WuFoo for their rock solid form CSS/HTML).

/*********************************************************
 Form Styles
 *********************************************************/
 form.uaform{
 font-family:"Lucida Sans",Lucida Sans Unicode,Verdana,Arial,sans-serif;
 margin:20px 0;
 }
 form.uaform li{width:auto !important;}
 .uaform ul{
 list-style:none;
 margin:0 14px;
 padding:0;
 font-size:1.2em;
 }
 .uaform li{
 clear:both;
 margin:0;
 padding:6px 1% 9px;
 width:64%;
 }
 .uaform li div span, span.full input, span.full select{
 display:block;
 float:left;
 width:100%;
 }
 .uaform span.left{
 float:left;
 width:48%;
 }
 .uaform span.right{
 float:right;
 width:48%;
 }
 .uaform span.right input, .uaform span.right select, .uaform span.left input, .uaform span.left select{width:100%;}
 .uaform li div label, .uaform li span label{font-size:90%;}
 .uaform fieldset{
 background-color:#eeeeee;
 -webkit-box-shadow:2px 2px 10px #ADADAD;
 -moz-box-shadow:2px 2px 10px #ADADAD;
 box-shadow:2px 2px 10px #ADADAD;
 margin:15px 0;
 clear:both;
 }
 .uaform legend{
 font-size:1.4em;
 font-weight:bold;
 color:#990000;
 margin-left:5px;
 }
 .uaform .legend{
 margin:5px 14px;
 padding:0 6px;
 color:#990000;
 border-bottom:1px dotted #CCCCCC;
 }
 .uaform label, label.desc{
 display:block;
 margin:0;
 padding-bottom:3px;
 color:#000;
 }
 label.desc{font-weight:bold;}
 .uaform label.choice{
 font-size:100%;
 line-height:150%;
 margin:-17px 0 0 23px;
 padding:0 0 5px;
 width:88%;
 }
 .uaform label span{
 color:#BC1212;
 vertical-align:middle;
 }
 input.text, textarea.textarea, select.select{
 font-size:100%;
 font-family:"Lucida Sans",Lucida Sans Unicode,Verdana,Arial,sans-serif;
 margin:0;
 padding:2px 0;
 }
 input.medium, select.medium{width:50%;}
 input.large, select.large, textarea.textarea{width:100%;}
 textarea.medium{height:10em;}
 .submit{font-size:1.1em;}
 input.checkbox, input.radio{
 font-size:1.1em;
 display:block;
 height:13px;
 width:13px;
 margin:4px 0 0;
 }
 label.error{
 color:red;
 font-weight:bold;
 }
 input.error, select.error, textarea.error{border:1px solid red;}
 p#form_success{
 color:green;
 font-weight:bold;
 }

After adding all of that code to your theme and inserting the [uaform] shortcode into a post or page, you should see something like this:

I hope this proves useful to those who just need a simple contact form.  If you have any feedback, suggestions, problems with the code, or spot any bugs please let me know!

UA Mobile Web Templates

As mentioned in our announcement of UA Mobile Web, resources on how to get started designing and developing your own mobile site are now available on UA Web Guide.  Currently, this documentation provides themes for the iPhone and Blackberry devices.  As UA Mobile Web expands functionality to other devices, so too will Web Guide’s resources.

The documentation provides code and instructions for:

  1. Automatically detecting mobile devices and forward to a mobile theme
  2. Setting a PHP cookie which allows the user to get back to the full website
  3. Different themes for each targeted device

Click here to download the UA Mobile Web Templates

We believe providing these resources will speed up development time for others on-campus and push forward mobile accessibility at UA.  If you have any questions or comments, please let us know.

Commenting on Code in Code

commentimage

Ever wonder how web designers keep everything in order when they’re typing out their code? Well, commenting helps a lot in organizing. By using comments, you can also signal out things you want to fix, make note of, or even just keep track of. So how do you keep the comments from messing up the 18 hours of coding you just did? Well, there are different options for different languages.

HTML

Below is the style for your basic html web page which really shouldn’t have too many comments- just nice clean code.

<!-- Comment Here -->

CSS

For organizing your styles and your main boxes- or whatever else you need- this commenting style works for single line or block quotes.

/* Comment Here */

JavaScript or jQuery

For JavaScript or jQuery, this method comments out the entire line starting from behind the back slashes. It is used as an end of line comment. CSS style is used as a short single line comment.

// Comment Here

/* Comment Here */

For block comments the code looks like CSS, but remember to keep an asterisk on each line.

/*
* Comment Here
*/

PHP

PHP can use the JavaScript method, or the pound symbol to comment out a line.

// Comment Here

# Comment Here

For multiple lines, the comment code is like the CSS code but unlike the JavaScript, no further asterisks are needed.

/* Comment
Here */

Ajax

To comment in Ajax, use the same method as in JavaScript.

// Comment Here

ActionScript

When working with flash, you might want to use these to comment on your action script. The first works for multiple lines and single lines while the second is just used for single lined short comments.

/* Comment Here */

// Comment Here

Display Tags in 3 Columns

UPDATE: I’ve developed a plugin, Multi-Column Taxonomy List, that solves the problem mentioned below.

If you’re tired of all of the tag clouds you see out there and just want a simple list that you can browse through, then this bit of code is for you. In WordPress, there are convenient functions to list all tags (and categories) outside of The Loop in an unordered list. However, this doesn’t make good use of horizontal space and can get out of hand quickly if you have a lot of tags. But, the advantages of having an alphabetical listing is worth the extra effort.

For this particular example, let’s assume we want to list our tags on the archives index page.

<?php
$tags = get_tags();
$tags_count = count($tags);
$percolumn = ceil($tags_count / 3);

for ($i = 0;$i < $tags_count;$i++):
if ($i < $percolumn):
$tag_left .= '
	<li><a href="'. get_tag_link($tags[$i]->term_id) . '"rel="tag">' . $tags[$i]->name .'</a></li>
' . "\n";
elseif ($i >= $percolumn && $i < $percolumn*2):
$tag_mid .= '
	<li><a href="'. get_tag_link($tags[$i]->term_id) . '"rel="tag">' . $tags[$i]->name .'</a></li>
' . "\n";
elseif ($i >= $percolumn*2):
$tag_right .= '
	<li><a href="'. get_tag_link($tags[$i]->term_id) . '"rel="tag">' . $tags[$i]->name .'</a></li>
' . "\n";
endif;
endfor;
?>
<ul>
<?php echo $tag_left; ?>
</ul>

<ul>
<?php echo $tag_mid; ?>
</ul>

<ul>
<?php echo $tag_right; ?>
</ul>

The majority of this code was modified from a two column version I found on the WordPress Forums, but since I needed three columns I had to take it one step further. The great thing about this code is that you can adapt it to output the tag RSS feeds by simply adding feed before the rel tag. For example:

$tag_left .= '<li><a href="'. get_tag_link($tags[$i]->term_id) . 'feed "rel="tag">' . $tags[$i]->name .'</a></li>' . "\n";

Here’s the code in practice.

If, for some reason, you really really love tag clouds and you think this code is a waste of time, you may want to check out some best practices for using tag clouds.

Automatically add links to WordPress image captions

As I mentioned in my previous post, the UA News sites have a few custom functions that improve upon certain things WordPress does (or does not do) by default.  One such function is automatically adding a link to the captions for a high quality image. When a user decides to link the thumbnail of an image to the full sized version, WordPress does not store that information in the database. This makes it particularly difficult to determine what’s going on with that image since things are being done on the front-end.

I have seen some solutions such as using the HTML editor to manually add a link to the caption shortcode, but this is messy, complicated, and at risk of being wiped out when switching back to the Visual editor. I have also seen a solution that adds a link below each picture, but it was just to a general URL and not the larger version of that image.

After coming up empty, I managed to come up with my own solution by:

  1. Overwriting the caption shortcode with a custom function
  2. Using Regular Expressions

If you haven’t already created a functions.php file for your theme, you will need to do so now.  Once you have created that file, add this code.

function nwp_caption_shortcode($attr, $content=null){	

	if ( defined('CAPTIONS_OFF') ){
		return $content;
	}

	extract(shortcode_atts(array(
		'id'	=&gt; '',
		'align'	=&gt; 'alignnone',
		'width'	=&gt; '',
		'caption' =&gt; ''
	), $attr));

	if ( 1 &gt; (int) $width || empty($caption) ){
		return $content;
	}

	$hq_url = preg_match('/<a>]+href="([^"]+(png|jpeg|jpg|gif))"[^&gt;]*&gt;/', $content, $matches);
	if($hq_url) $hq_output = "<a href=".$matches[1]." class="photo">High Quality Photo</a>";

	if ( $id ) $id = 'id="' . $id . '" ';

	$output = '
<div style="width:' . ((int) $width) . 'px;">'
	. $content . '
' . $caption . '
' . $hq_output . '</div>
';

	return apply_filters('nwp_caption_shortcode',$output);
}

add_shortcode('caption','nwp_caption_shortcode');
add_shortcode('wp_caption','nwp_caption_shortcode');

Basically, we are creating a new function called “nwp_caption_shortcode” then searching through the caption to find an href that points to an image and if found, output a High Quality Photo link.

The important bit is this regular expression search and replace.

	$hq_url = preg_match('/<a>]+href="([^"]+(png|jpeg|jpg|gif))"[^&gt;]*&gt;/', $content, $matches);
	if($hq_url) $hq_output = "<a href=".$matches[1]." class="photo">High Quality Photo</a>";

I am by no means a RegEx expert so if anyone sees room for improvement, feel free to comment.

Here is an example of the final result.

How to Transition to a CMS

For many web developers, the idea of transitioning to a content management system (CMS) is both appealing and frightening. It’s appealing because of how easy it would be to manage once everything is converted. It’s frightening because when you have a large, mostly static site, transitioning to a database-driven CMS requires a lot of work, specifically doing data migration.

Here’s a quick tip on making the transition easier: build a web form that parses static files and allows users to manage content online.

Let me explain. Let’s say you have a static files that call a simple header and footer, so that the source of your typical page looks like this:

<?php include(“_templates/header.php”); ?><h1>Here’s the title</h1>

<p>Here’s the content. Blah, blah, blah.</p>

<?php include(“_templates/footer.php”); ?>

From this code, it’s very obvious what the user would have access to manage. If your pages follow some sort of pattern (the above one is just an example), you can easily parse the content out of that page. Once you have the content, you can drop that content into a form that allows a user to edit it.

But why do this? For (at least) two reasons:

  1. Once you have users accustomed to the idea of managing content using an online form, it’s much easier to get them using a standard CMS, such as WordPress, Drupal or Joomla.
  2. It’s a relatively simply process to tie a parsing script into an existing CMS. The idea would be to make the parser check to see if the requested page content is already in the database. If it is, then it edits the database content. If it’s not, then it parses the page and updates the database. This effectively transfers the work of migrating data to the current content managers.

We’re currently implementing something like this at the business school. If anyone is interested, I’ll post some code and examples.