Quantcast
Channel: Paul's Cognos Blog
Viewing all 135 articles
Browse latest View live

Secondary Cell Suppression on OLAP

$
0
0

I recently had the great pleasure of working with the Department of Health and Human Services in New Hampshire. They have employed a company called Abacus Service Corporation to develop a wonderful dashboarding system in order to assist them in their goals of greater transparency (which I hope to review on here eventually, it’s a combination of Metric Studio and Workspace that is significantly easier for end users). Their team is extremely skilled, and they only needed a few days of my time to get them past a few difficult problems. They’ve agreed to let me publish the solution two of those problems.

One of their goals is to publish reports, directly to the public, on various health related issues. While transparency is to be commended, smaller data sets present possible privacy law violations. If data was sparse enough, people could theoretically back calculate in order to determine who specific people are from the data. In order to prevent people from being able to back calculate, the need to suppress additional data. They were able to accomplish their goal, but at a cost of a runtime of around 15 minutes. For a simple dataset, and one is supposed to be consumable by end users on the fly, any run time of more than a few seconds is unacceptable.

Let’s reproduce a sample using the Sales and Marketing cube. In this example we’ll say that any value below 20,000 and above 0 is sensitive and must be suppressed.

unsuppressed

In that screenshot we can see the quantity sold for each product line for each quarter. Here we can see that not a single value is below 20,000. However, what happens if we slice by a specific country?

italy unsuppressed

Here we see the same data set sliced by Italy. We can instantly see many instances of sensitive data being displayed (remember, anything below 20,000 and above 0 is sensitive). For ease of understanding, I’m going to call rename Quantity as “Check Measure”.
Suppressing those values is a simple matter of:

if([Check Measure] not between 1 and 20000) then ([Check Measure]) else (null)

Save that expression in a new data item called Pass 1.

Pass 1

Now we can see sensitive cells are suppressed. Unfortunately it is trivial to recalculate those values where only one cell is suppressed in a column, especially considering that we’re showing a totals row. Each column and row must have either >1 or 0 suppressed cells. To make it even easier to understand, I’ll rename Years to Columns and Product Line to Rows.
First thing to do, create a two new items that finds the next minimum value in the columns. We will want to suppress those values in order to secure the suppressed value. The expression is written to use the memberUniqueName in the rows in order to avoid issues with the next value being a tie.

Columns Min
#/*
This finds the minimum value of Check Measure after the values have been filtered out. 
If there are any values suppressed in the first pass, the second pass will filter by values greater than what this returns, effectively suppressing a minimum of 1 more cell than are suppressed.
roleValue(
  '_memberUniqueName'
  , item(
    bottomCount(
      [Columns]
      , 2
      , [Check Measure] 
      )
    , 1
  )
)

Next, the second pass checks if the current row has one suppressed cell, and if so, it will suppress the cell where the column matches the result from Columns Min

#/*
2nd Pass
This will count the number of cells in the columns, and deduct the number of cells remaining. If the value is greater than 0, then a cell is being suppressed - suppress any cells which are equal to the minimum value remaining.
*/#

member(if([Pass 1] is null) then ([null]) else (
if(
  total([One] within set [Columns]) - total([Pass 1] within set [Columns])=1) 
then (
  if(roleValue('_memberUniqueName',[Columns]) =[Columns Min]) then ([null]) else ([One])
) 
else ([One])
))
Pass 2

Now the same basic idea for rows.

Rows Min:

#/*
This finds the minimum value of Check Measure after the values have been filtered out. 
If there are any values suppressed in the first pass, the third pass will filter by values greater than what this returns, effectively suppressing a minimum of 1 more cell than are suppressed.
*/#

roleValue(
  '_memberUniqueName'
  , item(
    bottomCount(
        [Rows]
      , 2
      , [Check Measure] 
    )
    , 1
  )
)

and Pass 3:

#/*
3rd Pass
This will count the number of cells in the rows, and deduct the number of cells remaining. If the value is greater than 0, then a cell is being suppressed - suppress any cells which are equal to the minimum value remaining.
*/#

if([Pass 2]  is null) then ([null]) else (
if(
  total([One] within set [Rows]) - total([Pass 1] within set [Rows])=1) 

then (
if(roleValue('_memberUniqueName',currentMember(hierarchy([Rows]))) =[Rows Min]) then ([null]) else ([One])
) 

else ([One]))

Again, first it finds all columns that have 1 suppressed cell in the rows then it suppressed the next lowest value:

Pass 3

In this case, there are no more instances of unsecured sensitive cells. However, what happens if we had a data set containing only one sensitive cell? It would suppress another cell in the same row and column, but those two cells would now be at risk. If we slice by the United States the third pass returns the following set:

Pass 3 unsecure

One more pass is needed to hide the remaining intersection:

if([Pass 3] is null) then (null) else (
if ([cc]  = 1) then(
if(roleValue('_memberUniqueName',currentMember(hierarchy([Rows]))) =
roleValue('_memberUniqueName',
item(head(
order(filter([Rows], ([cr] >0)and ( [Pass 2]  is not null) )  , [Check Measure] ,basc
),1),0)
) ) then (null) else ( [Final Measure])
)
else  ( [Final Measure])
)

cc is a very simple: total([One] within set [Rows]) – total([Pass 2] within set [Rows])
with cr being: total([One] within set [Columns]) – total([Pass 3] within set [Columns])

This is similar to pass 2. It will count the number of suppressed cells in the column. The big change is instead of looking for and suppressing the smallest value the column, we are now looking for a row that already has at least one suppressed cell. It will find the matching rows, order them ascending by number of suppressed cells, and take the last one in the list. Instead of returning a 1 or null, this will return the final measure, in this case revenue.

And the final results, for the United States:
Pass 4

The end result will always be a minimum of 2 rows hidden on each row or column, or none at all. This satisfies the demand for data security on a row level without having to run extremely complex calculations for each possible combination of data in the ETL.

At this point the run time is about 2 seconds (on my laptop), still a long time considering the original query, but far more manageable. It should be mentioned that this is useful for smaller data sets, additional columns and rows will increase the run time significantly. Nested nodes will cause additional complexity, and should probably be avoided.

Sample report can be found here.


Dynamic Time Groups in an OLAP Cube

$
0
0

One of the challenges presented to me while I was helping out at the DHHS in New Hampshire was to find a way to make user defined year groups in the report. While it’s trivial to create year groupings in a cube, it becomes impossible when you need to account for every possible combination reports require. Sometimes you may need sets of 5 years starting at 1991. Other times the requirement may be every 2 years starting at 1980. Sometimes the users may want to see each year, 1991-1995, 1992-1996, 1993-1997; while other times the overlap is unnecessary, 1991-1995, 1996-2000, 2001-2006. Each measure would have to be aggregated for each grouping, increasing the size of the cube.

At first glance my solution is a bit complex. It uses JavaScript to control the appearance of the prompt and OLAP functions to set up the groups. Finally report expressions are used to control the labels in the chart and crosstab. Since the Cognos PowerCube samples have a limited set of years, I’ve adapted the technique to work on months instead.

In this example, the user is presented with three prompts. The first and second prompts allow the users to select the months they want. The first prompt has no overlap, if the group size selected is 6, it will show Jan-Jun and Jul-Dec. The second prompt will show Jan-Jun, Feb-Jul, Mar-Aug and so on. The third prompt shows the group size, defaulting to 6.
Prompts

The non-overlapping month prompt takes some work to get working. It is, essentially, filtering the month level where mod(monthNumber,groupSize) is 0. It is a little more complex, as that alone won’t work. First, the mod function isn’t supported by the cube, and will result in local processing. Second, it should be monthNumber – 1:

(((total(
    [One] within set periodsToDate(
        [sales_and_marketing].[Time].[Time].[Time]
      , currentMember([sales_and_marketing].[Time].[Time])
    )
  )-1)
  / #prompt('Group Size','integer','6')#)
  -
  floor((( total(
    [One] within set periodsToDate(
        [sales_and_marketing].[Time].[Time].[Time]
      , currentMember([sales_and_marketing].[Time].[Time])
    )
  )-1)
   / #prompt('Group Size','integer','6')#)))
  * #prompt('Group Size','integer','6')#

If you want the group to have a different start month, change the -1.

That will give us a set of every sixth month. 2010/Jan, 2010/Feb, 2011/Jan, 2011/Feb. But now we need to modify the appearance of the prompt values. For that we need JavaScript.

This JS will loop through the prompt, convert the month name into a numeric value, add the selected group size, then convert that number back into a month and concatenate it onto the label again.

<script>
var fW = (typeof getFormWarpRequest == "function" ? getFormWarpRequest() : document.forms["formWarpRequest"]); 
if ( !fW || fW == undefined) 
   { fW = ( formWarpRequest_THIS_ ? formWarpRequest_THIS_ : formWarpRequest_NS_ );} 

function parseMonthName(name) {
  var Months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
  for (i=0;i<12;i++){ if(Months[i]==name) {return i+1; break;}}
}

function addMonths(month,add){
  add=add?add:0;
  month = (month + add)%12;
  month=month==0?12:month;
  return month;
}

function getMonthName(month) { 
  var Months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
  return Months[month-1];
}


function setMonthNames(startPrompt,endPrompt){

var Size
  , Start = startPrompt
  , End = endPrompt
  , Month , newMonth, newYear

// Loop through the groupSize list to set the size variable. Subtract 1 from the value since the value includes the current month.
  for(var i =0;i<fW._oLstChoices_groupSize.length;i++){if(fW._oLstChoices_groupSize[i].selected) Size=fW._oLstChoices_groupSize[i].value -1}

  for (var i = 0;i<Start.length;i++){
    if(!Start[i].getAttribute('Orig')) {Start[i].setAttribute('Orig' , Start[i].getAttribute('dv')); };
    Month = Start[i].getAttribute('Orig');

    // If the group size is set to 0, use the original label. This is for on the fly changes.
    if(Size==0) {
      Start[i].setAttribute('dv' , Month);
    }
    else {
      newMonth = parseMonthName(Month.substr(5,3)) ; 
      newYear = addMonths(newMonth,Size)<Size?parseInt(Month.substr(0,4))+1:Month.substr(0,4);
      Start[i].setAttribute('dv' , Month + '-' +  newYear + '/' + getMonthName(addMonths(newMonth,Size)));
    }
    Start[i].innerHTML= Start[i].getAttribute('dv') ;
    //if(i>=Size-1) {Start[i].display='none';} else {Start[i].display='';} //Really, IE? Really?!
  }
}
</script>

So far this has only served to make it easier for the end user to understand how he’s filtering his report. The prompts themselves are still passing single member unique names to the query. Another calculated data item will be needed to group the years.

member(
  total(
    currentMeasure 
    within set 
    lastPeriods(
      0-#prompt('Group Size','integer','5')#
      ,currentMember([sales_and_marketing].[Time].[Time])
    )
  )
  ,'Grouped Total'
  ,'Grouped Total'
  ,[sales_and_marketing].[Time].[Time])

The lastPeriods will return the next Group Size members on the same level. This calculated member can then be used as a tuple on any measure that needs to be grouped. In the attached report I simply added it as the default measure in the charts and crosstabs.

That will create the groupings, but the labels on the chart and crosstab will still only show a single month. To fix that we can use a report expression with the same logic as the JavaScript from the prompt page:

case 
  when ParamValue('Group Size') = '1' then [Report].[No Overlap] 
  else 
    [Report].[No Overlap]  + '-' 
    + number2string(
      string2int32(substring([Report].[No Overlap],1,4))
      + case 
        when mod (
          case substring([Report].[No Overlap],6,3)
            when 'Jan' then 1
            when 'Feb' then 2
            when 'Mar' then 3
            when 'Apr' then 4
            when 'May' then 5
            when 'Jun' then 6
            when 'Jul' then 7
            when 'Aug' then 8
            when 'Sep' then 9
            when 'Oct' then 10
            when 'Nov' then 11
            when 'Dec' then 12
          end 
          + string2int32(ParamValue('Group Size'))-1,12) between 1 and (string2int32(ParamValue('Group Size'))-1) 
        then 1 
        else 0 
      end
    )
    +'/'+
    case mod (
      case substring([Report].[No Overlap],6,3)
        when 'Jan' then 1
        when 'Feb' then 2
        when 'Mar' then 3
        when 'Apr' then 4
        when 'May' then 5
        when 'Jun' then 6
        when 'Jul' then 7
        when 'Aug' then 8
        when 'Sep' then 9
        when 'Oct' then 10
        when 'Nov' then 11
        when 'Dec' then 12
      end + string2int32(ParamValue('Group Size'))-1,12)
      when 1 then 'Jan'
      when 2 then 'Feb'
      when 3 then 'Mar'
      when 4 then 'Apr'
      when 5 then 'May'
      when 6 then 'Jun'
      when 7 then 'Jul'
      when 8 then 'Aug'
      when 9 then 'Sep'
      when 10 then 'Nov'
      when 11 then 'Oct'
      when 0 then 'Dec'
    end
end

Simply change the text source on the crosstab or chart node member to Report Expression and paste that in.

Charts and xtab

Report XML

Quickie: PDF Report in New Window

$
0
0

One of the biggest frustrations people have with Cognos is that it will use the same window to export a report to PDF. Excel will open a new page, but not PDF. Why? Who knows? (IBMers, please feel free to comment below.)

Fortunately we can use JavaScript to force Cognos to do our bidding.

Since the JavaScript API changed in 10.2 I have two implementations, one for 10.1.1 and lower and one for 10.2 and higher. Simply paste the correct JavaScript into an HTML item, and fix up the button to meet your needs.

10.1.1

<script>
var fW = (typeof getFormWarpRequest == "function" ? getFormWarpRequest() : document.forms["formWarpRequest"]);
if (!fW || fW == undefined) {
  fW = (formWarpRequest_THIS_ ? formWarpRequest_THIS_:formWarpRequest_NS_);
}
 
  var preFix = "";
  if (fW.elements["cv.id"]) { preFix = fW.elements["cv.id"].value;}
  var nameSpace = "oCV" + preFix;

CViewerManager.prototype.viewInPDF = function(){
                var oReq =new CCognosViewerRequest("render")
                oReq.addOption("run.outputFormat", "PDF");
                this.viewPDFInNewWindow(oReq);
}  
</script>
<input type="button" onclick="window[nameSpace].getRV().viewInPDF()" value="Export to PDF"/>

10.2 is a bit easier to work with:

<script>
CViewerManager.prototype.runPDF = function ()
{
  var oReq = new ViewerDispatcherEntry(this.getCV());
  oReq.addFormField("ui.action","render");
  oReq.addFormField("run.outputFormat","PDF");
  this.viewPDFInNewWindow(oReq);
};
</script>
<input type="button" onclick="window['oCV'+'_THIS_'].getRV().runPDF()" value="Export to PDF"/>

Remember, use only one of them. The 10.1.1 version won’t work in 10.2, but should work in previous versions. I don’t have access to the 8 versions any more, so I’d appreciate if someone could leave a comment saying if it works or not.

Export to PDF Report XML (8 downloads)

Animated dropdown checkboxes and creating custom on-hover events

$
0
0

For those who missed it, PerformanceG2 is sponsoring my trip to the IOD this year. In return, I’ve written a couple of articles for their blog.

The first is a fancy way of converting
needing-to-scroll-for-prompts-make-users-angry

To
sliders-are-awesome

This is a very easy technique to use, simply copy in the main script into an HTML item at the top of the page, and add another script at the bottom to call the functions. Since it doesn’t use the 10.2 Prompt API, you can implement it in every version since 8.4. To learn more about that technique, read the post here.

The next technique is a bit more interesting (at least for me). There have been many times where clients have asked for a way to add more insights to the tooltips in charts. For example, users may want to hover over a micro chart and see a magnified version:
Magnifying Microcharts

In that image each chart had the country ID hidden right next to it. Hovering over the chart would then unhide a div with the same ID and position it directly over the cursor. Moving away from the chart would then hide it.

The same fading functions were used for this next technique:
filtering a list

Each area in the map has an onhover event attached. There are some internal Cognos JS functions that will pull the contextual data of that area. So if you’re hovering over a dot, the functions would return the series, category, and measure of the dot. Hovering over a legend would return that specific series. Since this is referencing internal Cognos JS functions I can’t guarantee that it will work in previous (or future) versions.

Read up on that technique here.

The post Animated dropdown checkboxes and creating custom on-hover events appeared first on CognosPaul.

Checking an “All” option in a checkbox prompt

$
0
0

One of my readers sent me an interesting problem. They need a checkbox prompt in which the top option is “All” and checking on any other option would automatically uncheck the “All” choice. Similarly, checking “All” should uncheck the other choices. Taking it to the conclusion, when checking or unchecking all of the options, the “All” should be checked.

Since they are still on 10.1, I have not used the Prompt API, meaning this should work on all versions since 8.4. To begin, the prompt itself.
check this out

In this case, the prompt is based on the Retailers hierarchy in the Sales and Marketing cube. Other times you might want to add a static value.

The JavaScript itself is not that difficult. The JS will loop through the prompt each time an option is clicked. If the first option is clicked, it will check it and uncheck the other options. If any other option is click it will loop through the prompt, counting the number of checked options and act accordingly. If 0 or all of the options are checked, it will check the first option, otherwise it will simply uncheck it.

When working with Checkbox prompts in JavaScript, the thing to remember is that, for whatever reason, the checkboxes that we see are actually images. To show the prompt as checked, the input needs to have the class “dijitCheckBoxChecked”.

Now the JS:

<script>
/* 
  * Function: addEvent
  * Author: Dan Fruendel
  * Attachs an event or adds an event listener depending on the browser.
  */
var addEvent = function(element, event, func){
    if(element.addEventListener){
      addEvent = function(element, event, func) {
        element.addEventListener(event, func, false);
        return true;
      };
    }
    else if(element.attachEvent) {
      addEvent = function(element, event, func) {
        return element.attachEvent("on" + event, func);
      };
    }
    else {
      addEvent = function(element, event, func) {
        var oldEventHandler = element['on' + event];
        element['on' + event] = function() {
         //using .apply to pass on anything this function gets.
          if(typeof(oldEventHandler) === "function") {
            oldEventHandler.apply(element, arguments);
          }
          func.apply(element, arguments);
        }
        return true;
      };
    }
    addEvent(element, event, func);
  }


// Cognos form and namespace identifier. Don't touch.
var fW = (typeof getFormWarpRequest == "function" ? getFormWarpRequest() : document.forms["formWarpRequest"]); 
if ( !fW || fW == undefined)   {
       fW = ( formWarpRequest_THIS_ ? formWarpRequest_THIS_ : formWarpRequest_NS_ );
   } 
 var preFix = "";
 if (fW.elements["cv.id"]) {     preFix = fW.elements["cv.id"].value;   }
     var nameSpace = "oCV" + preFix;
 
function attacher(elm,prompt,clicked){
  var func = function() {
    //if all is selected, zero out everything else.
    if(clicked==0) {prompt[0].selected=true;prompt[0].checked=true;prompt[0].className="dijitInline dijitCheckBox dijitCheckBoxChecked";for(var i=1;i<prompt.length;++i){prompt[i].selected=false;prompt[i].checked=false;prompt[i].className="dijitInline dijitCheckBox"}}

    //if individual, count number of selected
    if(clicked>0) {var c=0;
      for(var i=1;i<prompt.length;++i){
        if(prompt[i].checked){++c}
      }
      //if the count of checked is 0, then set the all to checked
      if(c==0) {setter=false;prompt[0].selected=true;prompt[0].checked=true;prompt[0].className="dijitInline dijitCheckBox dijitCheckBoxChecked"}
      //if the count of checked is equal to the length of the prompt, then set the all to checked and uncheck everything else
      else if(c==prompt.length-1) {setter=false;prompt[0].selected=true;prompt[0].checked=true;prompt[0].className="dijitInline dijitCheckBox dijitCheckBoxChecked";        for(var i=1;i<prompt.length;++i){prompt[i].selected=false;prompt[i].checked=false;prompt[i].className="dijitInline dijitCheckBox"}}
      //if the count is one and less than the length of the prompt then just set all to unchecked;
      else if(c>0&&c<prompt.length-1){prompt[0].checked=false;prompt[0].selected=false;prompt[0].className="dijitInline dijitCheckBox"}
    }

    canSubmitPrompt();
    }
  addEvent(elm,'click',func)

}

var prompt=fW._oLstChoicesCountries;
for (var i=0;i<prompt.length;++i){
  attacher(prompt[i],prompt,i);
}

</script>
Checkbox Prompt - All option (40 downloads)

The post Checking an “All” option in a checkbox prompt appeared first on CognosPaul.

#IBMIOD Monday

$
0
0

The last few days have been completely exhausting, and there are still three more days of the conference. As part of my deal with PerformanceG2, I’ll be posting more details of the conference on their blog. They should be up soon here.

Like last year I’ve had a lot of fun going to the various booths at the expo and hearing what people have to offer. Pens and other toys are just bonus.

An extremely interesting technology is coming from Servergy. They make extremely cool running, low power servers. Their big selling point is the savings you’d get on electricity bills from powering the servers, to the air conditioners you wouldn’t need. Their demo unit, running at 100% CPU, showed 0.56 amps. I am by no means a hardware guy, but this all seemed very very impressive, and I suspect a few of my clients may be interested in learning more.

An Ernst and Young reps chatted with me about the importance of Forensice Data Analytics – fraud identification and prevention. http://www.ey.com/

Fusion-io is offering a flash adapter for System X. From what I understand, it will cache a database in memory, providing significant performance improvements. http://www.fusionio.com/

Esri was giving out their latest map book, and I was lucky enough to snag one of the last ones they had. GIS has always fascinated me, and the book shows their maps are as much art as informative.

I visited a few IBM booths. IBM consistently and regularly blows me away with the new tools they’re developing. End users now can build complex statistical models with only a few clicks, there is software that will send alerts when it detects imminent infrastructure failure, natural language recognition that will automatically search through data sets to try to answer your questions.

There were a few other technology vendors I spoke with, but unfortunately those guys didn’t have any documentation handy! Guys, with all the flashing lights of the Expo, make sure I have some papers to remind me what you’re all doing! (I did manage to score a hat from PerformanceG2′s arch nemesis, but I won’t mention their name since I don’t want to upset my wonderful hosts).

Did I miss anyone? Are there any groups I should make a special effort to visit? The expo is open until Thursday, so drop a comment and I’ll make a special visit.

The post #IBMIOD Monday appeared first on CognosPaul.

Advanced Select and Search Prompts

$
0
0

This solution was built on 10.2.1.1, but should work on all versions after 10.2. Versions prior to 10.2 will need some rewriting as this is based on the Prompt API.

One of the biggest complaints I get about search prompts is the amount of real estate they take from reports. The multiselect prompts are huge, and users hate them for it. So I was asked to find a way to shrink it down.
SnS hogging the page

Obviously the solution was to everything but the search input and button. The keyword and instruction text can be controlled by the properties, simply setting it to “Specified Text” is sufficient to hide them:
Hiding Keywords

That leaves the Options link and the search results. Personally I don’t believe the results list need to appear unless there are actually results. The options should be at the mercy of the report author, so my solution includes a way to choose a default value and to hide the options.

First a look at the JS

/* function paulScripts.advancedSnS - Paul Mendelson - 2013-09-16
 * Will convert a standard search and select. It will add a button to expand/collapse the 
 * are selection area. The button will display how many matches have been found, and how 
 * many selected. 
 * 
 * The Option param will control the default search method. 
 * 1 = Starts with any of these keywords **DEFAULT**
 * 2 = Starts with the first keyword and contains all of the remaining keywords
 * 3 = Contains any of these keywords
 * 4 = Contains all of these keywords
 *
 * Hide the options link by setting 1 in the hideOption param.
 */ 
paulScripts.advancedSnS = function(promptName,option,hideOption){
  var prompt = paulScripts.getControl(promptName)
    , elm = document.getElementsByName(prompt.getParameterName())[0].parentNode
    , selectTable = elm.getElementsByTagName('table')[4]
    , selectDiv = document.createElement('div')
    , selectOptions = cognos.Report.getReport("_THIS_").prompt.getControlByName(promptName).getSelectOptions()
    , selectChoices = cognos.Report.getReport("_THIS_").prompt.getControlByName(promptName).getSelectChoices()
    , tr = elm.getElementsByTagName('button')[0].parentNode.parentNode.parentNode.appendChild(document.createElement('tr'))
    , td= tr.insertCell(0)
    , slideDiv = document.createElement('div')
    , btn = document.createElement('input');


    if(option) elm.getElementsByTagName('input')[option+2].checked=true;
    if(hideOption) tr.parentNode.parentNode.parentNode.parentNode.nextSibling.style.display='none';
    td.setAttribute('colSpan',2);

//Hacky – Building a new dispatcher request to save the state of the SnS. Do any IBMers have any comments? 
  if(typeof oReq ==='undefined') oReq = new ViewerDispatcherEntry(window['oCV'+'_THIS_'].getRV().getCV());
  if(!oReq.getFormFields().m_aValues[promptName]) oReq.addFormField(promptName,'hidden')

  btn.type='button';
  btn.value='';

  if(!selectOptions&&!selectChoices) btn.value='click to open';
  if(selectOptions)  btn.value = selectOptions.length + ' found. ';
  if(selectChoices)  btn.value += selectChoices.c.length + ' selected.';

  selectTable.parentNode.insertBefore(selectDiv,selectTable);
  selectDiv.appendChild(selectTable);
  
  //the right side of the table is a bit ugly; not enough padding.
  selectDiv.style.paddingRight='5px';

  // Sets the table of the select options to position absolute. This will prevent the page from expanding vertically
  // when the table is visible;
  selectDiv.style.position='absolute';
  selectDiv.style.overflow='hidden';
  selectDiv.style.backgroundColor='white';

  btn.onclick = function() {
    if(selectDiv.style.visibility=='hidden')
      {slidedown(selectDiv);
oReq.addFormField(promptName,'visible');}
    else {slideup(selectDiv);oReq.addFormField(promptName,'hidden');}
      return true;

  }

  selectDiv.style.visibility=oReq.getFormFields().m_aValues[promptName];
  td.appendChild(btn);
  return true;
}

The JS itself is fairly straight forward. The variables define the DOM element, a JSON array of the found options, another JSON array of the selected objects, and a couple of generated elements.

If a default search option is selected, it will set that.

if(option) elm.getElementsByTagName('input')[option+2].checked=true;

If hideOption is set to true, it will hide the options link.

 if(hideOption) tr.parentNode.parentNode.parentNode.parentNode.nextSibling.style.display='none';

Then it will insert a button, and finally the “results” lists are moved into a generated div which can then be slid open or shut.

  td.appendChild(btn);

Whenever I create a solution that changes the appearance of the page, showing or hiding an element, the users demand that the change persist through a page reset. The easiest way would be to create a new parameter to store the display state. Possibly a hidden text box with box type set to none. But if we always did things the easy way, we’d never learn anything.

 //Hacky – Building a new dispatcher request to save the state of the SnS. Do any IBMers have any comments? 
  if(typeof oReq ==='undefined') oReq = new ViewerDispatcherEntry(window['oCV'+'_THIS_'].getRV().getCV());
  if(!oReq.getFormFields().m_aValues[promptName]) oReq.addFormField(promptName,'hidden')

I haven’t tested this on a wide scale, so I don’t know of any performance impact. To be honest, while I love figuring out little hacks like these, without a more in-depth understanding of what it’s doing, it may not be wise to push this to all reports. The attached report contains two functions, the first using the hacky dispatcher request, and the second using a secondary text box to retain the state. The disadvantage of using the text box is that you’ll need to remember to add that in.

Once the JS is in place, we can call the functions with a simple:

paulScripts.advancedSnS ('Retailers', 3,1);

It will look for the prompt named Retailers, set the option to “Contains any of these keywords”, and hide the options link.

And the final product:
Searchng and Selecting

Report XML:
Advanced SnS (20 downloads)

The post Advanced Select and Search Prompts appeared first on CognosPaul.

Tab Solution That’s Easy to Maintain Without Code – Guest Post

$
0
0

“How corrupting boredom is, everyone recognizes also with regard to children. As long as children are having a good time, they are always good. This can be said in the strictest sense, for if they at times become unmanageable even while playing, it is really because they are beginning to be bored[…]Adam was bored alone; then Adam and Eve were bored en famille. After that, the population of the world increased and the nations were bored en masse. To amuse themselves, they hit upon the notion of building a tower so high that it would reach the sky. This notion is just as boring as the tower was high and is a terrible demonstration of how boredom had gained the upper hand. Then they were dispersed around the world, just as people now travel abroad, but they continued to be bored” (S. Keirkegaard, the Rotation of Crops).

I like writing nifty solutions for Cognos, which look good, work well, and add a necessary functionality. Tabs for Cognos reports (Not Active Reports, where tabs exist out of box) are a great demonstration for such functionality: It’s a necessary functionality, and when done properly, they make a report look wonderful.

However, I get bored doing the same thing over and over. When writing a tabbing solution, the principal is always the same: There are the tabs themselves, which are essentially links to be clicked on, and when clicked, there are the contents which need to be either hidden or shown based on the tab that was clicked.

Every now and again a developer who may not be very well versed in HTML, JavaScript and/or CSS would ask me to add, remove or change a tab, or change the style of a tabbed menu, or any such thing. To me, this is boring, and as Kierkegaard noted, boredom is corrupting – indeed, it is the root of all evil.

What needed to be done, then, was to come up with a tabbing solution that allows developers to add, remove and edit tab contents and tab styles without needing to write a single letter of code. The scripted solution needed to be generalized so that developers would be able to use Cognos built-in features to control all aspects of tabs. In other words, I needed to write a tabbing solution that would be a piece of cake to maintain, leaving me with more free time to get bored productively in Cognoise forums.

POCT (=Piece of Cake Tabs) is just that solution. It requires no coding to add, remove, or edit the content a tab. It allows the user to style the tabs using nothing but Cognos built in features. Basically, once you set the solution up, you never have to open an HTML item again.

Let’s look at the page structure:

POCT

Under “Tab Headers” HTML Item, one would simply drop in text items one after the other, each containing the name of the tab (The text that would be written in the tab).

Under “Tab Content” HTML Item, one would create a block for each tab, and drop in the necessary objects for each tab. The uppermost block is the content for the leftmost tab header, and so on – tab headers from left to right, content blocks from top to bottom.

Under “Style” HTML Item there are 3 table cells. One can style them as one wish. The leftmost cell represents how a selected tab would look. The middle one represents the styling of a tab which isn’t currently selected. The rightmost cell controls how a tab looks on mouse over. You can also control the look of the entire tab row, by highlighting the blue table cell where the tab headers are and changing its design to modify the design of the tab row.

And that’s it.

Want to add a tab? Add a text item and a block accordingly. Want to change the content of a tab? Just change the content of a block. Want to remove a tab? Remove the header text item and the corresponding block. And styling is truly piece of cake.

Report XML (10.1) – you can either use that as base or copy the main block and anything in it to any report. This was tested on all Cognos 10.x versions, and should work fine on 8.4.x.

POCT-XML-101.txt (35 downloads)

Nimrod (Rod) Avissar is a BI Front-End Specialist, with a penchant for specialized UX solutions (LinkedIn).

The post Tab Solution That’s Easy to Maintain Without Code – Guest Post appeared first on CognosPaul.


Creating a data entry page in Cognos

$
0
0

Cognos is a wonderful BI platform, but it does not handle write-backs to the database very well. By no means should Cognos be considered a data entry platform, but there are times when you may want to store comments associated with a specific report. Other times you may want to give users the ability to enter and save targets for specific data. It is even possible to set up a system to store the prompt selections in a report in a table.

The solution presented here was created in 10.2.1, but will work in every version since 8.4.

At the most basic level, writing back data is very simple. You run a stored procedure which takes specific parameters and passes them to the database. A system for entering comments is a good example:
DE Adding a comment

Multiple comments:
DE Multiple Comments

To begin with, let’s take a look at the stored procedure:

ALTER PROCEDURE [dbo].[insertDateComment]
	@dateKey numeric(18,0)
	, @comment varchar(1000)
AS
BEGIN
	SET NOCOUNT ON;

	  INSERT dbo.datecomments (DateKey,comment)
	  VALUES (@dateKey, @comment) ;
	SELECT @@ROWCOUNT as "rowCount"
END

You can’t get much simpler than this. It accepts two values, dateKey as a numeric and comment as a string, and inserts them into a table. In real-world usage more fields would be necessary, such as the username running the procedure, or the report name, or any other metadata you would want tracked. Since we’re using this in a Cognos report, a value must be returned. Even a simple “select 1 as whatever” would be sufficient.

In Framework, import the SP and populate the input parameters with prompt macros:
DE importDateCommentSP

There are two reports shown, the first report is a simple list showing date and comment (if exists). That’s accomplished by joining the comments table and the time dimension.

The second report contains a conditional block, a singleton, and two input boxes. When the report runs, the conditional block checks if the comment parameter is populated. If not, it renders the first page containing a hidden input for the dateKey, and a visible textbox for the comment. The user enters a comment and presses the refresh button. Again, the report runs, checking if the comments parameter is populated. Since it is this time, it renders the singleton block. The singleton contains the reference to the procedure. Since the parameter names in the textboxes match the parameter names from the procedure, it runs those. As the return value from the procedure is useless to the end user I hide it by checking “rowCount” in the properties of the singleton, and dropping a text item with a descriptive “data entered” message.

So far this has all been simple. But what happens when you want to enter multiple values? One at a time simply won’t do. The trick here is to dynamically change the name of the parameter in the framework. This method is a little more complex, as it uses HTML items and a little bit of JavaScript.

In this method the stored procedure is upserting the value into the table. The SQL for the procedure is using the merge function, which is not the most efficient way of doing an upsert.

ALTER PROCEDURE [dbo].[upsertValue]
	@DateKey [numeric](18, 0)
	, @Value [numeric](18, 0)
AS
BEGIN
	SET NOCOUNT ON;

	MERGE dbo.DataEntry as t
	USING (select @DateKey as DateKey, @Value as Value) as n 
	  on t.DateKey = n.DateKey 
	WHEN MATCHED then update set t.Value = @Value 
	WHEN NOT MATCHED THEN 
	  INSERT (DateKey,Value)
	  VALUES (@DateKey, @Value) ;
	SELECT @@ROWCOUNT as "rowCount"
END

The reference to the procedure uses prompt macros, but with a slight twist.
DE framework upsert

The prompt for the macro is set to #prompt(prompt(‘DateKey’,'integer’,’0′)+’Value’,'integer’,’0′)#

The DateKey prompt will actually change the parameter name for the Value prompt. So for date 1100, the parameter for the value would be 1100Value.

In the report, a simple list of dates is entered, with an HTML item
DE datelist

The HTML item is a report expression with the expression:

'<input 
  type="text" 
  name="p_'+number2string([DataEntry].[Day Key])+'Value" 
  value="'
+case when [Value] is null then '' else number2string([DataEntry].[Value]) end
+'"
  onchange="updateDateArr('+number2string([DataEntry].[Day Key])+')"
/>'1

Each row will generate an input box, the name will be the dateKey + 'Value' (just like the parameter in Framework). Parameters are populated by inputs with a specific name. So an input with the name p_123Hello will populate the parameter 123Hello. You would be able to use that parameter in a query, or on the page with paramDisplayValue('123Hello'). 

When a change is made to the input, it will be added to a list of dateKeys, that list is to ensure the procedure is run on updated values only:

1
<script>
var fW = (typeof getFormWarpRequest == "function" ? getFormWarpRequest() : document.forms["formWarpRequest"]);
if ( !fW || fW == undefined) {fW = ( formWarpRequest_THIS_ ? formWarpRequest_THIS_ : formWarpRequest_NS_ );}
var preFix = "";
if (fW.elements["cv.id"]){preFix = fW.elements["cv.id"].value;}    
var nameSpace = "oCV" + preFix;


var dateArr = [];

Array.prototype.unique = function() {
    var o = {}, i, l = this.length, r = [];
    for(i=0; i<l;i+=1) o[this[i]] = this[i];
    for(i in o) r.push(o[i]);
    return r;
};

function updateDateArr(dateKey){
  dateArr.push(dateKey);
  dateArr=dateArr.unique();
  document.getElementById('p_UpdatedDates').value=dateArr.join(',');
}

</script>
<input type="hidden" name="p_UpdatedDates" id="p_UpdatedDates">
 

Whenever the updateDateArr is called, it will add the new dateKey into the array, make the array unique, and then push it into the p_UpdatedDates input.

In the previous method, the stored procedure was only called when the Comments parameter was populated. The same thing is possible here. Create a conditional block with the Boolean variable paramValue(‘UpdatedDates’) is not null.

Inside the yes block, drag in a new list, stick in the dateKey, and filter that query with

dateKey in (#prompt('UpdatedDates','token')#)

Make sure to set the pagination options of the list. Check “Repeat every page” and uncheck “Allow contents to break across pages” and “Allow horizontal pagination”. This will ensure that the entire list appears in one page. In the same thread, go to File -> Report Properties, and set “Page break by data container for interactive HTML” to Yes. Without setting this option, the next list would be pushed to the next page.

When the report is run with updated values, that list will generate only those rows with updated dates.
DE Only Updated

Put a list in that list, drag in the rowCount from the upsertValue procedure, and define a master detail connection from Day Key to the parameter DateKey:
DE Master detail

Now when you run it, it will update the values.
DE It works

Hiding the list is a simple as wrapping it with a hidden div:
<div style=”display:none”> to the left of it, </div> to the right.
Here it is:
DE Entering multiple values

This post is a bit unusual in that it has several files attached. Three reports, the framework model, and an SQL Server 2012 backup.

Reports:
Data-Entry-Reports.zip (13 downloads)

Model:
Data Entry - Model.zip (11 downloads)

Database backup (SQL Server 2012):
Data Entry Database (6 downloads)

The post Creating a data entry page in Cognos appeared first on CognosPaul.

Quick and painless way of accessing users’ folders

$
0
0

As part of my administrative duties for my various clients, I periodically trawl through the logs. Many times I’ll want to see exactly what the users are doing in the reports on my server. It becomes a headache when these reports are in the users’ “My Folders”. I need to go into the administration page, find the user, go into their “My Folders”, copy out the report, paste it into mine then run it. It’s a mess and I’m far too lazy for that.

Fortunately Cognos allows us to access objects through URL parameters. On my laptop, I’m using OpenDJ as my authentication provider, so the CAMID is slightly different than Active Directory. My CAMID here is CAMID(“OpenDJ:u:cn=administrator”). In AD, it might be CAMID(“AD:u:r7a1n7d8o8m3l1e4t9t2e2r4s01234567)

My user

I can just copy that CAMID and paste it into the URL as:
http://server/cognos/cgi-bin/cognosisapi.dll?b_action=xts.run&m=portal/cc.xts&m_path=CAMID(“OpenDJ:u:cn=administrator”)

2. Accessing my user

Obviously this is still predicated on the security in place. A user who doesn’t have permission to access another user’s folder will get an “Access Denied”

3. Thwarted again

The post Quick and painless way of accessing users’ folders appeared first on CognosPaul.

Review: IBM Cognos BI v10.2 Administration Essentials

$
0
0

Part of my job as an Admin is to understand all aspects of the Cognos environment, from configuring and tuning distributed systems to being able to decipher the cryptic error messages that occasionally plague the users. Obviously this book is not for me. This book is more geared for beginners, as it says in the beginning:

Who this book is for
This book is for beginners planning to learn IBM Cognos BI Administration 10.

So, with that in mind it’s important to remember that experienced admins can skip the book. It is the people with little or no administrative experience who will benefit most from the book.

My concern is the length, at 128 pages there is simply not enough room to go into detail on everything. While it gives descriptions on the various tabs and settings of the administration page, I would have preferred more explanations on the settings and their effects.

Despite the brevity it does cover, albeit briefly, the various elements that are involved in the administrative process. The chapters are split by area of interest, configuration, components, security, etc. It describes the what happens when Cognos gets a request and the path the request takes from the gateway through the dispatcher. It explains the authentication and security system fairly well. Most importantly it also provides advice for new admins on how to run the system.

Ultimately I believe the book succeeds in its goal, namely taking people to the point where they can keep a Cognos server up and running.

You can find the book at the PacktPub website here.

The post Review: IBM Cognos BI v10.2 Administration Essentials appeared first on CognosPaul.

Export all report XMLs to file system – Updated

$
0
0

2 years ago, I posted a method for exporting all of the reports to the file system, using the same folder path. I was never happy with that method, as it required adding a UDF to the content store, and large reports would fail. Since getting these reports was a requirement at one of my clients, I finally had the time to tweak it.

Unlike the previous version, I don’t have access to Oracle, so this is on SQL server. The connection string to the server is handled from inside the script (row 151), all you need to do is change the data source and catalog details to connect.

The reports will be saved under c:\temp\reports. You may want to change that as well (row 244), but don’t forget that windows has an absolute limit in the number of characters in a file path.

Unlike the old version, this will also pull reports from users’ My Folders, including orphaned reports from deleted users. The user reports will be saved under \users\<user name>\my folders\. This will also generate a log file including the sql query sent to the db, and all of the reports generated.

Due to security concerns, the file has been renamed to getreports.vbs.txt. Simply rename that to getreports.vbs to enable it.

I tested this on Cognos 10.2, on SQL Server 2005. If anyone has access to Oracle and wants to adapt the SQL, I’ll  gladly amend the post to include it.

 

getreports.vbs (30 downloads)

The post Export all report XMLs to file system – Updated appeared first on CognosPaul.

Passing parameters without refreshing the page

$
0
0

Recently a reader had an interesting problem. Her client needed a prompt page from which they could open different reports. As it stands now, the client needed to select their prompts, hit the finish button, and then click on the links. She wanted a way to skip the second step – select the prompts, and have those values pass in the drill through.

With the prompt API, and a bit of JS, this is incredibly easy.

The first step is to identify the target report. You can get the report search path through the properties. Click on the “View the search path, ID and URL Location” link, and a window will pop up with the path and other details.
1. Get search path

Notice the double quotes? That can potentially cause trouble with the JavaScript, so I recommend using a URL Encoder: /content/folder[@name='JavaScript Examples']/folder[@name='Drill Target']/report[@name='Target'] becomes %2Fcontent%2Ffolder%5B%40name%3D%27JavaScript%20Examples%27%5D%2Ffolder%5B%40name%3D%27Drill%20Target%27%5D%2Freport%5B%40name%3D%27Target%27%5D

The example I’m posting will be using the URL Encoded version.

The next step will be the JavaScript:

<script>

  var paulScripts = {}
    , oCR = cognos.Report.getReport("_THIS_")
    , gateway = window['oCV_THIS_'].getRV().getCV().sGateway
    , report1 = decodeURIComponent("%2Fcontent%2Ffolder%5B%40name%3D%27JavaScript%20Examples%27%5D%2Ffolder%5B%40name%3D%27Drill%20Target%27%5D%2Freport%5B%40name%3D%27Target%27%5D%0A%0A");
 

  /* function paulScripts.URLEncode - Paul Mendelson = 2013-10-21
   * Based on the JSONEncode function, this will return the use/display values of
   * a prompt in a format that can be based via POST or GET.
   * usage: 'p_Parameter1='+paulScripts.URLEncode(paulScripts.getControl('MyPrompt'))
   */
  paulScripts.URLEncode = function(promptControl){
    var urlData = '<selectChoices>'
      , aPromptValues = promptControl.getValues()
      , nonRange = []
      , range =[];

    if (aPromptValues.length == 0) {return false}
   
    for (var j=0; j< aPromptValues.length; j++) {
      var promptValue =  aPromptValues[j];
     
      if (promptValue.use) {// Non Range value
        nonRange.push("<selectOption useValue='"+promptValue.use + "' displayValue='"+ promptValue.display + "'/>");
        }
      else { // Range value   
        var rangeStart = promptValue.start
          , rangeEnd = promptValue.end
          , start, end, startDisp, endDisp;
        if (rangeStart && rangeEnd) { //has both Start and End (bounded)
          rangeStart.display?startDisp = " displayValue='"+ rangeStart.display+"'":"";
          rangeEnd.display?endDisp = " displayValue='"+ rangeEnd.display+"'":"";
          range.push("<selectBoundRange><start useValue='"+rangeStart.use +"'" + startDisp +"/><end useValue='"+rangeEnd.use +"'" + endDisp +"/></selectBoundRange>")
        }
        else if (rangeStart && !rangeEnd) {//unboundedEndRange
          rangeStart.display?startDisp = " displayValue='"+ rangeStart.display+"'":"";
          range.push("<selectUnboundedEndRange><start useValue='"+rangeStart.use +"'" + startDisp +"/></selectUnboundedEndRange>");
        }
        else if (!rangeStart && rangeEnd) {
          rangeEnd.display?endDisp = " displayValue='"+ rangeEnd.display+"'":"";
          range.push("<selectUnboundedStartRange><end useValue='"+rangeEnd.use +"'" + endDisp +"/></selectUnboundedStartRange>");
        }
        else {
          alert ("Range not set.");
        } // end if
      } // end if
    } // end for
    if(nonRange.length>0) urlData += nonRange.join();
    if(range.length>0) urlData += range.join();
    urlData+='</selectChoices>';
    return urlData;
  }

  /* function paulScripts.getPrompts
   * Paul Mendelson - 2013-10-21
   * Retrieves all the prompts on the page and returns the parameter values
   */
  paulScripts.getPrompts = function(){
  //find all of the controls and stick them in aPromptControls.
    var aPromptControls = oCR.prompt.getControls( ),
    prompts = [];

  //loop through the controls - finding the name and values and sticking them into the names array
    for(i=0;i<aPromptControls.length;i++)
    {
      if(aPromptControls[i].getValues().length == 0) continue;
      prompts.push(aPromptControls[i].getParameterName());
      prompts.push(paulScripts.URLEncode (aPromptControls[i]));
    }
   
  return  prompts;
  }

paulScripts.runReport = function(reportName,reportPath,gateway, prompts){
  var basicInfo = [
          reportName, "toolbar=no,height=200,width=400"
        , 'ui.gateway' , gateway
        , 'ui.tool' , 'CognosViewer'
        , 'ui.action' , 'run'
        , 'ui.object' , reportPath
        , "run.prompt" ,"false"
        , "cv.toolbar" ,"false"
        , "cv.header" ,"false"
        , "run.prompt", "false"
    ];

    basicInfo=basicInfo.concat(prompts);
  return cognosLaunchInWindow.apply(this,basicInfo);
  }



</script>
 

Let’s go through the functions.

var paulScripts = {}
, oCR = cognos.Report.getReport(“_THIS_”)
, gateway = window['oCV_THIS_'].getRV().getCV().sGateway
, report1 = decodeURIComponent(“%2Fcontent%2Ffolder%5B%40name%3D%27JavaScript%20Examples%27%5D%2Ffolder%5B%40name%3D%27Drill%20Target%27%5D%2Freport%5B%40name%3D%27Target%27%5D%0A%0A”);

We’re defining the variables on the page. Notice that I’m hardcoding the report search path into a variable here. There’s actually no reason to do that, we could put it directly into the function, or put it into another prompt, or even insert it into a table and build a list with each row calling another report.

The gateway variable is pulling the gateway from the report you’re running. Another gateway could be entered here, if needed.

The paulScripts.URLEncode will take a prompt control, process the selected values, and spit out a string that Cognos can use to populate parameters.

paulScripts.getPrompts will look for every prompt on the page, and create an array of the parameter names and the selected strings. This makes updating the report simple – you won’t need to modify and JavaScript when adding or removing prompts.

paulScripts.runReport is the last function. It uses the cognosLaunchInWindow function to run a report in the specified window, using the specified search path, on the specified gateway, with the results of the paulScripts.getPrompts function.

To use it, all you need to do is creating an onclick event like this:

<input type="button" onclick="paulScripts.runReport('_blank',report1,gateway, paulScripts.getPrompts())" value="Run Report 1"/>

And finally, we can test it:
passingPrompts

This report was built on 10.2.1, but should work on all versions 10.2 and up.
Passing Parameters Without Refresh (14 downloads)

The post Passing parameters without refreshing the page appeared first on CognosPaul.

Freezing headers in Cognos 10.2

$
0
0

Starting in Cognos 10.2, IBM released a way to freeze crosstab headers and rows. This method works in all major browsers, and doesn’t rely on dirty CSS hacks. To get it working, simply right-click on the list or crosstab, and select Freeze Headers. The report will even remember the state of the crosstab after the page refreshes (from a prompt, possibly).

right click action

While this method works well, there are many times where we’d want to have the lists or crosstab start off frozen; or maybe we want to give the user a button to freeze one or all of the crosstabs in one go. Somewhat surprisingly, the JavaScript is very easy to use.

First, let’s define the initial variables:

var paulScripts = {}
  , win=window['oCV'+'_THIS_'];

paulScripts.oCV = win.getRV().getCV();

Reports run from Report Studio need to use window['oCVRS'] while reports from the connection need window['oCV_NS_']. Cognos will automatically replace _THIS_ to the correct fragment. Most of the Cognos functions we need are found inside win.getRV().getCV(), so we’re aliasing that into “paulScripts.oCV”.

The first function I’ll define is:

paulScripts.freezeContainer = function(objectName){
  var pFMngr = paulScripts.oCV.getPinFreezeManager();
  pFMngr.freezeContainer(objectName,true,true);
  window.onResizeViewerEvent()
};

All of the freezing functions are found inside getPinFreezeManager. The function getPinFreezeManager().freezeContainer() takes the object name (“Crosstab1″), and a Boolean to freeze/unfreeze the headers, and another Boolean to freeze/unfreeze the rows.

The freezing mechanism seems to have a small bug in the way it handles resizing. In my tests, it always resizes to a much smaller window than I need. The window.onResizeViewerEvent() function tricks the browser into thinking the window has been resized, and Cognos will then correctly recalculate the size of the frozen crosstab.

The unfreezing function is simple:

paulScripts.unfreezeContainer = function(objectName){
  var pFMngr = paulScripts.oCV.getPinFreezeManager();
  pFMngr.freezeContainer(objectName,false,false);
};

These two functions will let us automatically freeze a crosstab as soon as the page loads. But say we want to toggle it on and off.

/* paulScripts.toggleContainer 
 * Paul Mendelson - 2014-03-25
 * This wil check if a container has frozen headers. If so, it unfreezes it, if not, it freezes the container. 
 */
paulScripts.toggleAll = function(objectName) {
  var pFMngr = paulScripts.oCV.getPinFreezeManager();
  if(pFMngr.hasFrozenColumnHeadings(objectName)) {
    paulScripts.unfreezeContainer (objectName);
  }
  else {
    paulScripts.freezeContainer (objectName);
    window.onResizeViewerEvent()
  }
}

The hasFrozenColumnHeadings function returns a Boolean, true or false, on the state of the column headers.

And finally let’s say that we want to freeze all the crosstabs on the page in one go.

/* paulScripts.toggleAll 
 * Paul Mendelson - 2014-03-25
 * in: type {string - crosstab or list}
 * This wil loop through every "type" on the page, and freezing or unfreezing, depending if the column header is frozen. 
 */

paulScripts.toggleAll = function(type) {
  setTimeout(function(){
    var xts = win._getContainers(type)
      , xtLen = xts.length
      , pFMngr = paulScripts.oCV.getPinFreezeManager();
      for(var i =0;i<xtLen;++i){
        var lid = pFMngr.removeNamespace(xts[i].getAttribute('lid'));
        if(i<xtLen-1 && lid==pFMngr.removeNamespace(xts[i+1].getAttribute('lid'))) continue; //when the panes are frozen the crosstab is split into four elements, all with the same lid. Without this hack, the xtab would toggle four times!
        if(pFMngr.hasFrozenColumnHeadings(lid)) {
          pFMngr.freezeContainer(lid,false,false);
        }
        else {
          pFMngr.freezeContainer(lid,true,true);
          window.onResizeViewerEvent()
        }
      }
    }
  ,200);
}

That was a little bit more complex than before. We can use the _getContainers functions to get an array of all the lists or crosstabs on the page. The lid of the object is the name, plus the namespace. We can use the removeNamespace function to get it back to the name the freezeContainer functions expect.

The toggleAll function should only be used in a button. As Cognos stores the state of the object; if the headers are locked, they will remain locked after refreshing the page. Toggling them will cause them to unlock. Instead, it’s best to use a freezeAll function when loading the page:

paulScripts.freezeAll = function(type){
  var xts = win._getContainers(type)
  , xtLen = xts.length
  , pFMngr = paulScripts.oCV.getPinFreezeManager();
  for(var i =0;i<xtLen;++i){
    var lid = pFMngr.removeNamespace(xts[i].getAttribute('lid'));
    if(pFMngr.hasFrozenColumnHeadings(lid)) continue; 
    paulScripts.freezeContainer (lid);
  }
};

Once everything is working, we can see how it works.
Freezing panes

The example report in using 10.2.1, against the sales and marketing cube.
Freezing Panes report XML (12 downloads)

The post Freezing headers in Cognos 10.2 appeared first on CognosPaul.

Quickie: Resizing a value prompt list

$
0
0

Another problem from a reader. Unlike checkbox or radio prompts, list prompts don’t expand and collapse to fit the number of options available to them.
This prompt is taking far too much room.

In the above image, we have a prompt that has too much space. Let’s shrink that down.
resizing lists

Now it shrinks to the number of rows displayed, or expands to a maximum of 15 items.

It’s actually a very easy script. The first step is to identify the prompt. We’ll use the old fW script (so this should work in every since 8.4).

var fW = (typeof getFormWarpRequest == "function" ? getFormWarpRequest() : document.forms["formWarpRequest"]);
if ( !fW || fW == undefined)
{
  fW = ( formWarpRequest_THIS_ ? formWarpRequest_THIS_ : formWarpRequest_NS_ );
}
var preFix = "";
if (fW.elements["cv.id"])
{
  preFix = fW.elements["cv.id"].value;
}
var nameSpace = "oCV" + preFix;

Next, we need to identify the prompt object:

var pr = fW._oLstChoicesPromptName;

The prompt itself is a standard SELECT element. We can set the size attribute to easily set the height.

This gives us:

if  (pr.options.length>15)
{
  pr.size=15
}
else 
{
  pr.size=pr.options.length
}

The following report XML is based on 10.2.1, but you can downgrade it easily by changing the schema number on the first line.
Resizing-Value-Prompt-List.txt (23 downloads)

The post Quickie: Resizing a value prompt list appeared first on CognosPaul.


Recent Java exploits and Cognos

$
0
0

Several new Java exploits have recently been uncovered. So far the all of the exploits that IBM has tested against their JDK and JREs have been unsuccessful. As my source in the upper echelons of IBM has said, “Thus, IBM products shipping the IBM JDK are not vulnerable to this exploit.”

Products that ship the Oracle JRE may be vulnerable to the exploits, and care should be taken until all of the fixes are released. Remember, nothing is sure until the fix is in.

Please read: Java Vulnerability Blog, from Tivoli AVP

In general it would be best to stay subscribed to the IBM Product Security Incident Response Blog to make sure you have the latest information on any security concerns with IBM products.


Cognos Mashup Services – a brief example

$
0
0

In a previous post I showed how to embed Cognos reports in other applications or reports by using iframes. Unfortunately there are many problems with using iframes, difficulty interacting with objects with JavaScript, security issues, even positioning objects well into a page.

Instead it might be better to use CMS. You can pull a specific object from the report, and it becomes an actual element of the page you’re working on. CMS also allows you to pull elements in a number of different formats. HTMLFragment will return the report object exactly as it appears in the report, while JSON will allow you to easily use the data from the report in a JS function. This will post will two examples, HTMLFragment and JSON.

We’ll start with a JSON example.

In this report, we’ll create a text box prompt and a list prompt. Typing anything into the text prompt will populate the list prompt, like a search and select, but without refreshing the page.

This example is using Cognos 10.2 and the sales and marketing cube. The JavaScript will not downgrade to previous versions as I’m using the new Prompt API. People using previous versions can get around it by attaching events to their prompts.

To begin, create a list report with a value and key. In my example I’m using Product and Product – Category Code from the Sales and Marketing cube.
1. Source list

The Product field is actually a filter expression:

filter(
  [sales_and_marketing].[Products].[Products].[Product]
  , upper([sales_and_marketing].[Products].[Products].[Product].[Product - Long Name]) contains upper(#prompt('SearchString','string')#)
    or [sales_and_marketing].[Products].[Products].[Product].[Product - Category Code]  contains (#prompt('SearchString','string')#)
)

As CMS allows us to reference objects directly, it’s important to remember to give each object a name that describes what it is, what it contains, while being short enough to be easily referenceable . In this case, I’m calling the list object “List”.

When you run the report, you’re prompted to enter a string, and any product that contains the caption or code will be returned.

Save it under /CMS/Source and create a new report.

This report should have a table with 3 rows, 1 column. In the first row, put a text box prompt. In the second, a multi select list prompt. Leave the third blank for now. Remember to name the text box and value prompts. Let’s call them Text and Select.

Drag in an HTML item in the bottom row of the table, and paste in the following code.

<script>
/*
 * Fake Namespace and prompt getters.
 */ 	
var paulScripts = {}
var oCR = cognos.Report.getReport("_THIS_");

paulScripts.getSource = function()
{
    var targ;
    if (!e) var e = window.event;
    if(!e) return false;
    if (e.target) targ = e.target;
    else if (e.srcElement) targ = e.srcElement;
    if (targ.nodeType == 3) // defeat Safari bug
      targ = targ.parentNode;
    return targ;
}

paulScripts.getControl = function(promptName) 
{
  return oCR.prompt.getControlByName(promptName);
}


paulScripts.setPromptValue = function ( promptName, value ) {
var 
  newOption = ''
  , selElm = document.getElementById('PRMT_SV_'+paulScripts.getControl ( promptName )._id_);
//  selElm.options.length=0;
  for(i=0;i<selElm.options.length;i++)
  {
    if(selElm.options[i].selected==true){
      for(x in value) {if(value[x].use == selElm.options[i].value) {value.splice(x,1); break;}}
    } else {selElm.remove(i);i--}
  }
  
  for(i=0;i<value.length;i++)
  {
    newOption = document.createElement( 'option');
    newOption.value=value [i].use ;
    newOption.innerHTML = value[i].display ;
    newOption.dv = value [i].display ;

    selElm.appendChild(newOption );

  }
}

/*
* This creates the XMLHttpRequest object used to communicate with CMS.
* The initialization of the object depends on what browser is being used. This
* code is compatible with IE 5.5, 6, 7, 8 and all versions of Firefox and Chrome
*
* For more information on the XMLHttpRequest object, see http://www.w3.org/TR/XMLHttpRequest/
*/
try  {
var objXHR = new XMLHttpRequest();
} catch (e) {
try {
var objXHR = new ActiveXObject('Msxml2.XMLHTTP');
} catch (e) {
try {
var objXHR = new ActiveXObject('Microsoft.XMLHTTP');
} catch (e) {
alert('XMLHttpRequest not supported'); }
}
}


paulScripts.getValues = function (searchString)
{
  var 
    searchString = searchString?searchString:'',
    url= '../ibmcognos/cgi-bin/cognos.cgi/rds/reportData/searchPath/%2fcontent%2ffolder%5b%40name%3d%27CMS%27%5d%2freport%5b%40name%3d%27Source%27%5d?fmt=JSON&async=off&selection=List&p_SearchString=' + searchString;
   objXHR.open("POST", url, false);
   objXHR.send(null);
   if (objXHR.status == 200)
   {
     dataCache = (eval('(' + objXHR.responseText + ')'));
     return paulScripts.parseJSON(dataCache);
   }
}

/*
 * Loop through tableData, extract the use and display fields, and dump them into 
 * a JS object.
 */
paulScripts.parseJSON = function(tableData)
{
  if(!tableData.filterResultSet.filterResult) return false;
  var 
      rows = tableData.filterResultSet.filterResult[0].reportElement[0].lst.group.row
    , JSONData = [];

  for (var i=0; i < rows.length; i++)
  {
    JSONData.push ( {use :  rows[i].cell[1].item[0].txt.fmtVal, display : rows[i].cell[0].item[0].txt.fmtVal  });
  }
return JSONData;
}


/*
 * function loadOptions. Paul Mendelson - 2013-01-15
 * When text is entered into the text box, this will be triggered. It will wait for further input
 * before loading the select box with values.
 */
paulScripts.loadOptions= (function () {
  var timer;
  return function (){
    var name = this.getName()
    , search = this.getValue();
    clearTimeout(timer);
    timer = window.setTimeout(function() {  
      if(this.oldValue==search) {return true} else {this.oldValue=search}
      paulScripts.setPromptValue( 'Select', paulScripts.getValues(search));
    },1000);
    return true;
    };
})();

paulScripts.getControl('Text').setValidator(paulScripts.loadOptions);

</script>

When you run the report the select box will be empty. Start typing into the textbox. The JS will wait 1 second after the last keystroke, then pass the value to the Source report, retrieve data in JSON format, parse it and populate the select.

I’m not going to get into all of the JS here, just what is salient to CMS.

The paulScripts.getValues first coalesces the search string into nothing. You can make prompts optional by making your filters “this = ?searchString? or ‘-1′ = ?searchstring?”, and having the searchString set to ‘-1′. The URL in this example uses the search path of the report. While longer, I find it preferable over using the storeID. Just remember to URL Encode it. Notice the search string is appended to the URL. It then opens an XMLHttpRequest to Cognos. Cognos will interpret the request and send back a responseText.

The responseText will need to be handled differently depending on the format of the request. In this case, Cognos is returning JSON, and the results will need to be parsed as such.

The paulScripts.parseJSON will loop through the rows in the table. I know that the first cell is the label, and the second is the code, I also know there is only a single object in each table cell.

The monster tableData.filterResultSet.filterResult[0].reportElement[0].lst.group.row[1].cell[0].item[0].txt is how we reference text of the first item in the first cell of the second row (indexes are 0 based). If I managed to pull two lists, I could decide to use reportElement[1] to get the second list.

When parseJSON finishes creating the JS object, it will return it to getValues which in turn returns it to setPromptValue. setPromptValue will loop through the JS object and create the options in the select list.

Now that we have functional prompts. Let’s create a chart that shows revenue per month for each of the selected products.

Put the Month level in the categories, Revenue in the Measure and a new Query Calculation: filter(
[sales_and_marketing].[Products].[Products].[Product]
, [sales_and_marketing].[Products].[Products].[Product].[Product - Category Code] in (#promptmany('Products','string')#)
)

When run, it will prompt for codes.

Now let’s change the HTML item to:

<div id="chart"></div>
<script>
/*
 * Fake Namespace and prompt getters.
 */ 	
var paulScripts = {}
var oCR = cognos.Report.getReport("_THIS_");

paulScripts.getSource = function()
{
    var targ;
    if (!e) var e = window.event;
    if(!e) return false;
    if (e.target) targ = e.target;
    else if (e.srcElement) targ = e.srcElement;
    if (targ.nodeType == 3) // defeat Safari bug
      targ = targ.parentNode;
    return targ;
}

paulScripts.getControl = function(promptName) 
{
  return oCR.prompt.getControlByName(promptName);
}


paulScripts.setPromptValue = function ( promptName, value ) {
var 
  newOption = ''
  , selElm = document.getElementById('PRMT_SV_'+paulScripts.getControl ( promptName )._id_);
//  selElm.options.length=0;
  for(i=0;i<selElm.options.length;i++)
  {
    if(selElm.options[i].selected==true){
      for(x in value) {if(value[x].use == selElm.options[i].value) {value.splice(x,1); break;}}
    } else {selElm.remove(i);i--}
  }
  
  for(i=0;i<value.length;i++)
  {
    newOption = document.createElement( 'option');
    newOption.value=value [i].use ;
    newOption.innerHTML = value[i].display ;
    newOption.dv = value [i].display ;

    selElm.appendChild(newOption );

  }
}

/*
* This creates the XMLHttpRequest object used to communicate with CMS.
* The initialization of the object depends on what browser is being used. This
* code is compatible with IE 5.5, 6, 7, 8 and all versions of Firefox and Chrome
*
* For more information on the XMLHttpRequest object, see http://www.w3.org/TR/XMLHttpRequest/
*/
try  {
var objXHR = new XMLHttpRequest();
} catch (e) {
try {
var objXHR = new ActiveXObject('Msxml2.XMLHTTP');
} catch (e) {
try {
var objXHR = new ActiveXObject('Microsoft.XMLHTTP');
} catch (e) {
alert('XMLHttpRequest not supported'); }
}
}


paulScripts.getValues = function (searchString)
{
  var 
    searchString = searchString?searchString:'',
    url= '../cgi-bin/cognos.cgi/rds/reportData/searchPath/%2fcontent%2ffolder%5b%40name%3d%27CMS%27%5d%2freport%5b%40name%3d%27Source%27%5d?fmt=JSON&async=off&selection=List&p_SearchString=' + searchString;
   objXHR.open("POST", url, false);
   objXHR.send(null);
   if (objXHR.status == 200)
   {
     dataCache = (eval('(' + objXHR.responseText + ')'));
     return paulScripts.parseJSON(dataCache);
   }
}

/*
 * Loop through tableData, extract the use and display fields, and dump them into 
 * a JS object.
 */
paulScripts.parseJSON = function(tableData)
{
  if(!tableData.filterResultSet.filterResult) return false;
  var 
      rows = tableData.filterResultSet.filterResult[0].reportElement[0].lst.group.row
    , JSONData = [];

  for (var i=0; i < rows.length; i++)
  {
    JSONData.push ( {use :  rows[i].cell[1].item[0].txt.fmtVal, display : rows[i].cell[0].item[0].txt.fmtVal  });
  }
return JSONData;
}


/*
 * function loadOptions. Paul Mendelson - 2013-01-15
 * When text is entered into the text box, this will be triggered. It will wait for further input
 * before loading the select box with values.
 */
paulScripts.loadOptions= (function () {
  var timer;
  return function (){
    var name = this.getName()
    , search = this.getValue();
    clearTimeout(timer);
    timer = window.setTimeout(function() {  
      if(this.oldValue==search) {return true} else {this.oldValue=search}
      paulScripts.setPromptValue( 'Select', paulScripts.getValues(search));
    },1000);
    return true;
    };
})();

paulScripts.getControl('Text').setValidator(paulScripts.loadOptions);

/*
 * function loadProducts. Paul Mendelson - 2013-01-15
 * When a product is selected in the select, this will be triggered. It will wait for further input
 * before attempting to retrieve the chart.
 */
paulScripts.loadProducts= (function () {
  var timer;
  return function (){
    var name = this.getName()
    , products = this.getValues()
    , productsLabel='';
    clearTimeout(timer);
    timer = window.setTimeout(function() {  
    if(products.length===0) return true;
    for (i=0;i<products.length;i++) {productsLabel+='&p_Products='+products[i].use}
    paulScripts.getChart(productsLabel);
    },1000);
    return true;
    };
})();

paulScripts.getChart = function (products)
{
  var 
    url= '../cgi-bin/cognos.cgi/rds/reportData/searchPath/%2fcontent%2ffolder%5b%40name%3d%27CMS%27%5d%2freport%5b%40name%3d%27Chart%27%5d?fmt=HTMLFragment&async=off&selection=Chart' + products;
   objXHR.open("POST", url, false);
   objXHR.send(null);
   if (objXHR.status == 200)
   {
     document.getElementById('chart').innerHTML = objXHR.responseText ;
   }
}

paulScripts.getControl('Select').setValidator(paulScripts.loadProducts);

</script>

A div has been added above the scripts node. A validator for the Select prompt has been added. When the user selects a value it will wait one second for further input, then pass the selected codes to the chart report. The chart report will return an HTMLFragment as a string, which is then passed to the div as it’s innerHTML.

Cognos Mashup Services is an incredibly versatile tool. The possibilities are limitless. I suspect, but haven’t tried, that it will allow you to embed objects in systems that do not allow iFrames. The only drawback is that it will only work in HTML. You can’t use this to merge objects from different models into a single PDF

IBM has a few guides on it. Start here.

Report XML:

<report xmlns="http://developer.cognos.com/schemas/report/9.0/" useStyleVersion="10" expressionLocale="en-us">
				<modelPath>/content/folder[@name='Samples']/folder[@name='Cubes']/package[@name='Sales and Marketing (cube)']/model[@name='2008-07-25T15:28:38.072Z']</modelPath>
				<drillBehavior modelBasedDrillThru="true"/>
				<layouts>
					<layout>
						<reportPages>
							<page name="Page1">
								<style>
									<defaultStyles>
										<defaultStyle refStyle="pg"/>
									</defaultStyles>
								</style>
								<pageBody>
									<style>
										<defaultStyles>
											<defaultStyle refStyle="pb"/>
										</defaultStyles>
									</style>
									<contents><table><style><defaultStyles><defaultStyle refStyle="tb"/></defaultStyles><CSS value="border-collapse:collapse"/></style><tableRows><tableRow><tableCells><tableCell><contents><textBox parameter="Parameter1" name="Text" required="false"/></contents></tableCell></tableCells></tableRow><tableRow><tableCells><tableCell><contents><selectValue parameter="Parameter2" multiSelect="true" selectValueUI="listBox" name="Select"/></contents></tableCell></tableCells></tableRow></tableRows></table><HTMLItem description="scripts">
			<dataSource>
				<staticValue>&lt;div id="chart"&gt;&lt;/div&gt;
&lt;script&gt;
/*
 * Fake Namespace and prompt getters.
 */ 	
var paulScripts = {}
var oCR = cognos.Report.getReport("_THIS_");

paulScripts.getSource = function()
{
    var targ;
    if (!e) var e = window.event;
    if(!e) return false;
    if (e.target) targ = e.target;
    else if (e.srcElement) targ = e.srcElement;
    if (targ.nodeType == 3) // defeat Safari bug
      targ = targ.parentNode;
    return targ;
}

paulScripts.getControl = function(promptName) 
{
  return oCR.prompt.getControlByName(promptName);
}


paulScripts.setPromptValue = function ( promptName, value ) {
var 
  newOption = ''
  , selElm = document.getElementById('PRMT_SV_'+paulScripts.getControl ( promptName )._id_);
//  selElm.options.length=0;
  for(i=0;i&lt;selElm.options.length;i++)
  {
    if(selElm.options[i].selected==true){
      for(x in value) {if(value[x].use == selElm.options[i].value) {value.splice(x,1); break;}}
    } else {selElm.remove(i);i--}
  }
  
  for(i=0;i&lt;value.length;i++)
  {
    newOption = document.createElement( 'option');
    newOption.value=value [i].use ;
    newOption.innerHTML = value[i].display ;
    newOption.dv = value [i].display ;

    selElm.appendChild(newOption );

  }
}

/*
* This creates the XMLHttpRequest object used to communicate with CMS.
* The initialization of the object depends on what browser is being used. This
* code is compatible with IE 5.5, 6, 7, 8 and all versions of Firefox and Chrome
*
* For more information on the XMLHttpRequest object, see http://www.w3.org/TR/XMLHttpRequest/
*/
try  {
var objXHR = new XMLHttpRequest();
} catch (e) {
try {
var objXHR = new ActiveXObject('Msxml2.XMLHTTP');
} catch (e) {
try {
var objXHR = new ActiveXObject('Microsoft.XMLHTTP');
} catch (e) {
alert('XMLHttpRequest not supported'); }
}
}


paulScripts.getValues = function (searchString)
{
  var 
    searchString = searchString?searchString:'',
    url= '../cgi-bin/cognos.cgi/rds/reportData/searchPath/%2fcontent%2ffolder%5b%40name%3d%27CMS%27%5d%2freport%5b%40name%3d%27Source%27%5d?fmt=JSON&amp;async=off&amp;selection=List&amp;p_SearchString=' + searchString;
   objXHR.open("POST", url, false);
   objXHR.send(null);
   if (objXHR.status == 200)
   {
     dataCache = (eval('(' + objXHR.responseText + ')'));
     return paulScripts.parseJSON(dataCache);
   }
}

/*
 * Loop through tableData, extract the use and display fields, and dump them into 
 * a JS object.
 */
paulScripts.parseJSON = function(tableData)
{
  if(!tableData.filterResultSet.filterResult) return false;
  var 
      rows = tableData.filterResultSet.filterResult[0].reportElement[0].lst.group.row
    , JSONData = [];

  for (var i=0; i &lt; rows.length; i++)
  {
    JSONData.push ( {use :  rows[i].cell[1].item[0].txt.fmtVal, display : rows[i].cell[0].item[0].txt.fmtVal  });
  }
return JSONData;
}


/*
 * function loadOptions. Paul Mendelson - 2013-01-15
 * When text is entered into the text box, this will be triggered. It will wait for further input
 * before loading the select box with values.
 */
paulScripts.loadOptions= (function () {
  var timer;
  return function (){
    var name = this.getName()
    , search = this.getValue();
    clearTimeout(timer);
    timer = window.setTimeout(function() {  
      if(this.oldValue==search) {return true} else {this.oldValue=search}
      paulScripts.setPromptValue( 'Select', paulScripts.getValues(search));
    },1000);
    return true;
    };
})();

paulScripts.getControl('Text').setValidator(paulScripts.loadOptions);

/*
 * function loadProducts. Paul Mendelson - 2013-01-15
 * When a product is selected in the select, this will be triggered. It will wait for further input
 * before attempting to retrieve the chart.
 */
paulScripts.loadProducts= (function () {
  var timer;
  return function (){
    var name = this.getName()
    , products = this.getValues()
    , productsLabel='';
    clearTimeout(timer);
    timer = window.setTimeout(function() {  
    if(products.length===0) return true;
    for (i=0;i&lt;products.length;i++) {productsLabel+='&amp;p_Products='+products[i].use}
    paulScripts.getChart(productsLabel);
    },1000);
    return true;
    };
})();

paulScripts.getChart = function (products)
{
  var 
    url= '../cgi-bin/cognos.cgi/rds/reportData/searchPath/%2fcontent%2ffolder%5b%40name%3d%27CMS%27%5d%2freport%5b%40name%3d%27Chart%27%5d?fmt=HTMLFragment&amp;async=off&amp;selection=Chart' + products;
   objXHR.open("POST", url, false);
   objXHR.send(null);
   if (objXHR.status == 200)
   {
     document.getElementById('chart').innerHTML = objXHR.responseText ;
   }
}

paulScripts.getControl('Select').setValidator(paulScripts.loadProducts);

&lt;/script&gt;
</staticValue>
			</dataSource>
		</HTMLItem></contents>
								</pageBody>
							</page>
						</reportPages>
					</layout>
				</layouts>
			<XMLAttributes><XMLAttribute name="RS_CreateExtendedDataItems" value="true" output="no"/><XMLAttribute name="listSeparator" value="," output="no"/><XMLAttribute name="RS_modelModificationTime" value="2008-07-25T15:28:38.133Z" output="no"/></XMLAttributes><reportName>start2</reportName><reportVariables><reportVariable type="boolean" name="dontRender">
			<reportExpression>1=0</reportExpression>
			<variableValues>
				<variableValue value="1"/>
			</variableValues>
		</reportVariable></reportVariables></report>

Playing with MotioCI

$
0
0

A few posts back I gave a sneak peek of a new tool Motio was working on. Recently I was fortunate enough to get into the beta.

The installation, for the most part, is fairly straight forward. You download, decompress, modify a few config files to declare which version of Cognos you’re running, location of your JDK. The only major stumbling block I had was Motio requires some sort of authentication against Cognos. Since I was running Cognos anonymously on my laptop, it simply wouldn’t connect. To get around this, I set up OpenDJ and was able to progress.

Once MotioCI is installed and set up, it will create an instance. Each instance is a connection to a specific Cognos server. You can have as many instances as you have Cognos gateways. You can communicate between instances. So, for example, you can a report in Instance 1 to get specific results, and compare them to results in Instance 2. This is all part of the assertions, which I will get into later.

After you create an instance, you will be prompted to create a new project. Create the new project with a descriptive name and continue. The wizard will walk you through selecting which folders you want to test against which assertions. It comes with a suite of default assertions created by Motio and the Best Practices team. Once selected, it will generate test cases and run them.

Generate Test Cases

After the test cases run, you can see which reports have failures or warnings. You can see the results of the test cases, and the outputs of the reports themselves (if the test cases required the reports to run).
failing on assertions
The most interesting part of this tool is the Assertion Studio. This is where you can define the assertions.

Assertions allow you to test almost every aspect of any Cognos object. Do you have a corporate look and feel that every report must follow? Set up a template report and compare each and every report against that. Do you want to find every report that has a run time of more than 5 minutes? Do you want to automatically compare the output of a series of reports against specific SQL queries? Are you upgrading from 8.2 and need to find all instances of the old JS API? Do you want to test your dispatchers for certain settings and response times? The possibilities are endless.

When you design your own assertions you can specify whether the report needs to be executed or not. Executing the report allows you to check things like run time, or results match. Does the third row in the list match the first row of another report? Not executing allows you to use combinations of xpath and regex to parse the report (or model) xml. You might use that to find all reports that contain “formwarprequest” in HTML items.

There is a bit of a learning curve when it comes to MotioCI. It is definitely not something you’d give end users. It does seem to be an invaluable tool for administrators.

You can read more about it at the Motio Website.


Button Prompts in Cognos 10

$
0
0

One of the features I’ve always wanted is buttons that set parameters. The existing prompt buttons just serve to provide navigation features to Cognos reports. You can’t, for instance, press the “Mountaineering Equipment” button and see a report which is filtered by mountaineering. Yes, you can use regular checkbox or radio prompts to do this, but that is hardly the point, is it? I want good, old fashioned buttons!

Consider the following screenshot:
report with buttons

There are buttons going across the top, to let the user select which product line, and buttons going down the left to let the user select how he wants to view the report (xtab, bar, or column).

It would be possible to use standard checkbox or radio prompts with this, but it wouldn’t look nearly as good. Some developers may be tempted to manually create the buttons with extensive use of HTML items. It would work, a certain developer (who will remain anonymous here) used that method for a series of reports and I still get calls asking how to add or remove buttons.

Instead, it is infinitely easier to write JS function that creates the button elements on the fly based on an existing prompt.

Read the following JS (10.2 only):

<script>

/* 
  * Function: addEvent
  * Author: Dan Fruendel
  * Attachs an event or adds an event listener depending on the browser.
  */
var
  addEvent = function(element, event, func)
  {
    if(element.addEventListener)
    {
      addEvent = function(element, event, func)
      {
        element.addEventListener(event, func, false);
        return true;
      };
    }
    else if(element.attachEvent)
    {
      addEvent = function(element, event, func)
      {
        return element.attachEvent("on" + event, func);
      };
    }
    else
    {
      addEvent = function(element, event, func)
      {
        var oldEventHandler = element['on' + event];
        element['on' + event] = function()
        {
          //using .apply to pass on anything this function gets.
          if(typeof(oldEventHandler) === "function")
          {
            oldEventHandler.apply(element, arguments);
          }
          func.apply(element, arguments);
        }
        return true;
      };
    }
    return addEvent(element, event, func);
  }
/*
 * Fake Namespace and prompt getters.
 */ 	
var paulScripts = {}
  , oCR = cognos.Report.getReport("_THIS_");

paulScripts.getSource = function()
{
    var targ;
    if (!e) var e = window.event;
    if(!e) return false;
    if (e.target) targ = e.target;
    else if (e.srcElement) targ = e.srcElement;
    if (targ.nodeType == 3) // defeat Safari bug
      targ = targ.parentNode;
    return targ;
}

paulScripts.getControl = function(promptName) {
  return oCR.prompt.getControlByName(promptName);
}

paulScripts.reprompt = function(){
if(!paulScripts.getSource() ) return true;
  oCR.sendRequest(cognos.Report.Action.REPROMPT);
  return true;
}


paulScripts.addButtons = function ( promptName, myClass,reprompt) {
var 
    newOption = ''
  , reprompt = reprompt?reprompt:false
  , id = paulScripts.getControl ( promptName )._id_
  , selElm = document.getElementById('PRMT_SV_'+ id)
  , selElmSelect = document.getElementById('PRMT_SV_LINK_SELECT_'+ id)
  , selElmDeselect = document.getElementById('PRMT_SV_LINK_DESELECT_'+ id)
  , rads = selElm.getElementsByTagName('input')
  , len = rads.length
  , type = len==0?'none':rads[0].type
  , radioClick = function(){for(var radios=paulScripts.getSource().parentNode.getElementsByTagName('input').length/2;radios<paulScripts.getSource().parentNode.getElementsByTagName('input').length;radios++){paulScripts.getSource().parentNode.getElementsByTagName('input')[radios].className=myClass + 'Unselected'};paulScripts.getSource().parentNode.getElementsByTagName('input')[paulScripts.getSource().index].click(); paulScripts.getSource().className=myClass + 'Selected'}
  , checkClick= function(){paulScripts.getSource().parentNode.getElementsByTagName('input')[paulScripts.getSource().index].click(); paulScripts.getSource().className=paulScripts.getSource().className==myClass + 'Selected'?myClass + 'Unselected':myClass + 'Selected';}
  , selectAll= function(){ for(var elms=rads.length;elms>rads.length/2;elms--){rads[elms-1].className=myClass + 'Selected'}}
  , deselectAll= function(){ ; for(var elms=rads.length;elms>rads.length/2;elms--){rads[elms-1].className=myClass + 'Unselected'}}
;
  selElm.className = myClass;

  if(type == 'none') return false;

  for(i=0;i<len;i++)
  {
    newOption = document.createElement( 'input');
    newOption.type='button';
    newOption.value=rads[i].getAttribute('dv');
    newOption.className=rads[i].selected?myClass + 'Selected': myClass + 'Unselected';
    newOption.index=i;
    if(type=='checkbox') {addEvent(newOption,'click',checkClick)};
    if(type=='radio') {addEvent(newOption,'click',radioClick)};
    rads[i].parentNode.parentNode.style.display='none';
    selElm.appendChild(newOption );
  }

  if(reprompt) paulScripts.getControl ( promptName ).setValidator(paulScripts.reprompt);

  if(selElmSelect) addEvent(selElmSelect,'click',selectAll);
  if(selElmDeselect) addEvent(selElmDeselect,'click',deselectAll);
}

paulScripts.addButtons('Products','Horizontal',1);
paulScripts.addButtons('Reports','Vertical');

</script>

Look complicated? It’s actually not complicated at all. The first function there was written by a friend (and if you think I’m good at JS… he’s the kind of person to look at some code, think for 5 minutes and rewrite it using half the lines and make it run several times faster), it allows you to attach events in different browsers. The getSource function is there because some browsers have issues with THIS. getControl is the 10.2 method of identifying the referenced prompt object. The reprompt function is simply the way I force the report to refresh (on checkbox prompts, for instance).

The meat of the function is in the addButton function. First it finds the prompt object you’re referencing (using 10.2 methods, needs a rewrite if using in earlier versions). Next it determines if the prompt is a checkbox or radio. If it’s neither, the function exits. Then it starts creating the actual button elements. It generates an array of all of the elements in the prompt, then for each one creates a button using the display value and hides the original element. Each generated button has a click function that will, in turn, click on the correct checkbox or radio in the original prompt.

The buttons each have a class based on if it’s selected or not. Clicking on the button will alternate between selected/unselected. The style will have to be included in an HTML item as well. Each style must have three entries, styleName for the top box, styleNameSelected for selected buttons, and styleNameUnselected for unselected buttons.

If the reprompt option is set to true, then it will add the reprompt function to the validator, essentially making it an autosubmit prompt.

Finally, if this is a checkbox group, it will add functions to the select and deselect all links under the prompt.

To use the prompt, it’s then a simple matter of creating your prompt object on the page, naming it, and calling the function. So in the above screenshot there are two prompts on the page. A multiselect checkbox (based on the product line dimension) above the crosstab, and a radio button (with static choices) to the left. The function is called twice, once for each prompt. The reprompt flag is set for the checkbox prompt, while the radio is set to autosubmit in the report.

I wrote some simple CSS to highlight the buttons when selected:

<style>
.Vertical{
  width:'';
  height:'';
}

.VerticalUnselected{
  padding:2px 10px 3px 10px;
  margin-right:7px;
  background-image:url(../reportstyles/images/button_bg.png);
  background-position:left top;
  background-repeat:repeat-x;
  background-color:#EFEFEF;
  color:#000000;
  font-size:10pt;
  font-weight:normal;
  text-align:center;
  border:1px solid #92afc2;
  width: 75px;
  display:block;
}

.VerticalSelected{
  padding:2px 10px 3px 10px;
  margin-right:7px;
  background-image:url(../reportstyles/images/button_bg.png);
  background-position:left top;
  background-repeat:repeat-x;
  background-color:#A0AFEB;
  color:#000000;
  font-size:10pt;
  font-weight:normal;
  text-align:center;
  border:1px solid #92afc2;
  width: 75px;
  display:block;
}

.Horizontal{
  width:0;
  height:0;
  white-space:nowrap;
}

.HorizontalUnselected{
  padding:2px 10px 3px 10px;
  margin-right:7px;
  background-image:url(../reportstyles/images/button_bg.png);
  background-position:left top;
  background-repeat:repeat-x;
  background-color:#EFEFEF;
  color:#000000;
  font-size:10pt;
  font-weight:normal;
  text-align:center;
  border:1px solid #92afc2;
}

.HorizontalSelected{
  padding:2px 10px 3px 10px;
  margin-right:7px;
  background-image:url(../reportstyles/images/button_bg.png);
  background-position:left top;
  background-repeat:repeat-x;
  background-color:#A0AFEB;
  color:#000000;
  font-size:10pt;
  font-weight:normal;
  text-align:center;
  border:1px solid #92afc2;
}

</style>

Each button group can have it’s own unique style, if so desired. Just remember to write the CSS for each one.

Ultimately the report consists of 2 prompts, 2 graphs, a crosstab, a conditional block and a single HTML item.

The report XML (10.2, sales and marketing) below:

<report xmlns="http://developer.cognos.com/schemas/report/9.0/" useStyleVersion="10" expressionLocale="en-us">
				<modelPath>/content/folder[@name='Samples']/folder[@name='Cubes']/package[@name='Sales and Marketing (cube)']/model[@name='2008-07-25T15:28:38.072Z']</modelPath>
				<drillBehavior/>
				<layouts>
					<layout>
						<reportPages>
							<page name="Page1">
								<style>
									<defaultStyles>
										<defaultStyle refStyle="pg"/>
									</defaultStyles>
								</style>
								<pageBody>
									<style>
										<defaultStyles>
											<defaultStyle refStyle="pb"/>
										</defaultStyles>
									</style>
									<contents><table><style><defaultStyles><defaultStyle refStyle="tb"/></defaultStyles><CSS value="border-collapse:collapse;width:100%"/></style><tableRows><tableRow><tableCells><tableCell><contents/></tableCell><tableCell><contents><selectValue parameter="Products" refQuery="Products" multiSelect="true" required="false" name="Products" selectValueUI="checkboxGroup"><useItem refDataItem="Product line"/><style><CSS value="height:0px;width:0px"/></style></selectValue></contents></tableCell></tableCells></tableRow><tableRow><tableCells><tableCell><contents><selectValue selectValueUI="radioGroup" name="Reports" autoSubmit="true" parameter="ReportType" hideAdornments="true"><selectOptions><selectOption useValue="1"><displayValue>Columns</displayValue></selectOption><selectOption useValue="2"><displayValue>Bar</displayValue></selectOption><selectOption useValue="3"><displayValue>Crosstab</displayValue></selectOption></selectOptions><style><CSS value="width:0px;height:0px"/></style><defaultSelections><defaultSimpleSelection>1</defaultSimpleSelection></defaultSelections></selectValue></contents><style><CSS value="vertical-align:top"/></style></tableCell><tableCell><contents>
												<conditionalBlocks>
			<conditionalBlockDefault>
				<contents/>
			</conditionalBlockDefault>
		<conditionalBlockCases refVariable="ReportType"><conditionalBlock refVariableValue="1"><contents><v2_combinationChart maxHotspots="10000" refQuery="Query2" name="Combination Chart2">
														<v2_combinationTypeTooltips/>
														<v2_legend>
															<v2_legendPosition>
																<v2_legendPreset/>
															</v2_legendPosition>
															<v2_legendTitle refQuery="Query2">
																<v2_chartTextContents>
																	<v2_automaticText/>
																</v2_chartTextContents>
																<style>
																	<defaultStyles>
																		<defaultStyle refStyle="lx"/>
																	</defaultStyles>
																</style>
															</v2_legendTitle>
															<style>
																<defaultStyles>
																	<defaultStyle refStyle="lg"/>
																</defaultStyles>
															</style>
														</v2_legend>
														<v2_commonAxis>
															<v2_ordinalAxis>
																<v2_axisTitle refQuery="Query2">
																	<v2_chartTextContents>
																		<v2_automaticText/>
																	</v2_chartTextContents>
																	<style>
																		<defaultStyles>
																			<defaultStyle refStyle="at"/>
																		</defaultStyles>
																	</style>
																</v2_axisTitle>
																<v2_axisLine lineWeight="0"/>
																<v2_axisLabels>
																	<style>
																		<defaultStyles>
																			<defaultStyle refStyle="al"/>
																		</defaultStyles>
																	</style>
																</v2_axisLabels>
															</v2_ordinalAxis>
															<chartNodes><chartNode><chartNodeMembers><chartNodeMember refDataItem="Product Types"><chartContents><chartTextItem><dataSource><memberCaption/></dataSource></chartTextItem></chartContents></chartNodeMember></chartNodeMembers></chartNode></chartNodes></v2_commonAxis>
														<v2_topLeftAxis>
															<v2_combinationChartTypes>
																<v2_bar borders="show">
																	<v2_solidPalette>
																		<v2_solidPaletteEntries>
																			<v2_solidPaletteEntry>
																				<v2_fillEffect defaultColor="#8599D3">
																					<v2_linearGradient>
																						<v2_gradientColor gradientColor="#8599D3"/>
																						<v2_gradientColor colorPosition="100" gradientColor="#5876AE"/>
																					</v2_linearGradient>
																				</v2_fillEffect>
																			</v2_solidPaletteEntry>
																			<v2_solidPaletteEntry>
																				<v2_fillEffect defaultColor="#E3AE6C">
																					<v2_linearGradient>
																						<v2_gradientColor gradientColor="#E3AE6C"/>
																						<v2_gradientColor colorPosition="100" gradientColor="#CD854E"/>
																					</v2_linearGradient>
																				</v2_fillEffect>
																			</v2_solidPaletteEntry>
																			<v2_solidPaletteEntry>
																				<v2_fillEffect defaultColor="#839862">
																					<v2_linearGradient>
																						<v2_gradientColor gradientColor="#839862"/>
																						<v2_gradientColor colorPosition="100" gradientColor="#6C7F56"/>
																					</v2_linearGradient>
																				</v2_fillEffect>
																			</v2_solidPaletteEntry>
																			<v2_solidPaletteEntry>
																				<v2_fillEffect defaultColor="#B7C873">
																					<v2_linearGradient>
																						<v2_gradientColor gradientColor="#B7C873"/>
																						<v2_gradientColor colorPosition="100" gradientColor="#AFB885"/>
																					</v2_linearGradient>
																				</v2_fillEffect>
																			</v2_solidPaletteEntry>
																			<v2_solidPaletteEntry>
																				<v2_fillEffect defaultColor="#8484A8">
																					<v2_linearGradient>
																						<v2_gradientColor gradientColor="#8484A8"/>
																						<v2_gradientColor colorPosition="100" gradientColor="#525E7E"/>
																					</v2_linearGradient>
																				</v2_fillEffect>
																			</v2_solidPaletteEntry>
																			<v2_solidPaletteEntry>
																				<v2_fillEffect defaultColor="#C0CCED">
																					<v2_linearGradient>
																						<v2_gradientColor gradientColor="#C0CCED"/>
																						<v2_gradientColor colorPosition="100" gradientColor="#B0C2E5"/>
																					</v2_linearGradient>
																				</v2_fillEffect>
																			</v2_solidPaletteEntry>
																			<v2_solidPaletteEntry>
																				<v2_fillEffect defaultColor="#8C5580">
																					<v2_linearGradient>
																						<v2_gradientColor gradientColor="#8C5580"/>
																						<v2_gradientColor colorPosition="100" gradientColor="#794067"/>
																					</v2_linearGradient>
																				</v2_fillEffect>
																			</v2_solidPaletteEntry>
																			<v2_solidPaletteEntry>
																				<v2_fillEffect defaultColor="#C789BC">
																					<v2_linearGradient>
																						<v2_gradientColor gradientColor="#C789BC"/>
																						<v2_gradientColor colorPosition="100" gradientColor="#BB72BC"/>
																					</v2_linearGradient>
																				</v2_fillEffect>
																			</v2_solidPaletteEntry>
																			<v2_solidPaletteEntry>
																				<v2_fillEffect defaultColor="#D5BAEF">
																					<v2_linearGradient>
																						<v2_gradientColor gradientColor="#D5BAEF"/>
																						<v2_gradientColor colorPosition="100" gradientColor="#C29FD1"/>
																					</v2_linearGradient>
																				</v2_fillEffect>
																			</v2_solidPaletteEntry>
																			<v2_solidPaletteEntry>
																				<v2_fillEffect defaultColor="#83683F">
																					<v2_linearGradient>
																						<v2_gradientColor gradientColor="#83683F"/>
																						<v2_gradientColor colorPosition="100" gradientColor="#604926"/>
																					</v2_linearGradient>
																				</v2_fillEffect>
																			</v2_solidPaletteEntry>
																			<v2_solidPaletteEntry>
																				<v2_fillEffect defaultColor="#DCB05A">
																					<v2_linearGradient>
																						<v2_gradientColor gradientColor="#DCB05A"/>
																						<v2_gradientColor colorPosition="100" gradientColor="#C09C52"/>
																					</v2_linearGradient>
																				</v2_fillEffect>
																			</v2_solidPaletteEntry>
																			<v2_solidPaletteEntry>
																				<v2_fillEffect defaultColor="#F4DF9E">
																					<v2_linearGradient>
																						<v2_gradientColor gradientColor="#F4DF9E"/>
																						<v2_gradientColor colorPosition="100" gradientColor="#E4CF87"/>
																					</v2_linearGradient>
																				</v2_fillEffect>
																			</v2_solidPaletteEntry>
																			<v2_solidPaletteEntry>
																				<v2_fillEffect defaultColor="#5F8A8C">
																					<v2_linearGradient>
																						<v2_gradientColor gradientColor="#5F8A8C"/>
																						<v2_gradientColor colorPosition="100" gradientColor="#537579"/>
																					</v2_linearGradient>
																				</v2_fillEffect>
																			</v2_solidPaletteEntry>
																			<v2_solidPaletteEntry>
																				<v2_fillEffect defaultColor="#96C4B2">
																					<v2_linearGradient>
																						<v2_gradientColor gradientColor="#96C4B2"/>
																						<v2_gradientColor colorPosition="100" gradientColor="#89B0A0"/>
																					</v2_linearGradient>
																				</v2_fillEffect>
																			</v2_solidPaletteEntry>
																			<v2_solidPaletteEntry>
																				<v2_fillEffect defaultColor="#CBE8E7">
																					<v2_linearGradient>
																						<v2_gradientColor gradientColor="#CBE8E7"/>
																						<v2_gradientColor colorPosition="100" gradientColor="#BDD6D5"/>
																					</v2_linearGradient>
																				</v2_fillEffect>
																			</v2_solidPaletteEntry>
																			<v2_solidPaletteEntry>
																				<v2_fillEffect defaultColor="#AE6564">
																					<v2_linearGradient>
																						<v2_gradientColor gradientColor="#AE6564"/>
																						<v2_gradientColor colorPosition="100" gradientColor="#875352"/>
																					</v2_linearGradient>
																				</v2_fillEffect>
																			</v2_solidPaletteEntry>
																			<v2_solidPaletteEntry>
																				<v2_fillEffect defaultColor="#D88C6F">
																					<v2_linearGradient>
																						<v2_gradientColor gradientColor="#D88C6F"/>
																						<v2_gradientColor colorPosition="100" gradientColor="#C47D61"/>
																					</v2_linearGradient>
																				</v2_fillEffect>
																			</v2_solidPaletteEntry>
																			<v2_solidPaletteEntry>
																				<v2_fillEffect defaultColor="#E3C9B0">
																					<v2_linearGradient>
																						<v2_gradientColor gradientColor="#E3C9B0"/>
																						<v2_gradientColor colorPosition="100" gradientColor="#D2B2A5"/>
																					</v2_linearGradient>
																				</v2_fillEffect>
																			</v2_solidPaletteEntry>
																			<v2_solidPaletteEntry>
																				<v2_fillEffect defaultColor="#848484">
																					<v2_linearGradient>
																						<v2_gradientColor gradientColor="#848484"/>
																						<v2_gradientColor colorPosition="100" gradientColor="#555555"/>
																					</v2_linearGradient>
																				</v2_fillEffect>
																			</v2_solidPaletteEntry>
																			<v2_solidPaletteEntry>
																				<v2_fillEffect defaultColor="#a4a4a4">
																					<v2_linearGradient>
																						<v2_gradientColor gradientColor="#a4a4a4"/>
																						<v2_gradientColor colorPosition="100" gradientColor="#909090"/>
																					</v2_linearGradient>
																				</v2_fillEffect>
																			</v2_solidPaletteEntry>
																			<v2_solidPaletteEntry>
																				<v2_fillEffect defaultColor="#C7C7C7">
																					<v2_linearGradient>
																						<v2_gradientColor gradientColor="#C7C7C7"/>
																						<v2_gradientColor colorPosition="100" gradientColor="#c1c1c1"/>
																					</v2_linearGradient>
																				</v2_fillEffect>
																			</v2_solidPaletteEntry>
																		</v2_solidPaletteEntries>
																	</v2_solidPalette>
																	<!-- v2_solidPaletteRef ref=&amp;amp;quot;gDefaultSolid&amp;amp;quot;/ -->
																	<chartNodes><chartNode><chartNodeMembers><chartNodeMember refDataItem="Revenue"><chartContents><chartTextItem><dataSource><memberCaption/></dataSource></chartTextItem></chartContents></chartNodeMember></chartNodeMembers></chartNode></chartNodes></v2_bar>
															</v2_combinationChartTypes>
															<v2_axis>
																<v2_axisTitle refQuery="Query2">
																	<v2_chartTextContents>
																		<v2_automaticText/>
																	</v2_chartTextContents>
																	<style>
																		<defaultStyles>
																			<defaultStyle refStyle="at"/>
																		</defaultStyles>
																	</style>
																</v2_axisTitle>
																<v2_axisLine lineWeight="0"/>
																<v2_axisRange>
																	<v2_automaticRange/>
																</v2_axisRange>
																<v2_axisLabels>
																	<style>
																		<defaultStyles>
																			<defaultStyle refStyle="al"/>
																		</defaultStyles>
																	</style>
																</v2_axisLabels>
																<v2_majorGridlines lineWeight="0" lineColor="#CCCCCC"/>
																<v2_majorBackgroundColors>
																	<v2_firstBackgroundColor color="#D2D2D2" transparency="50"/>
																	<v2_secondBackgroundColor color="#E2E2E2" transparency="50"/>
																</v2_majorBackgroundColors>
															</v2_axis>
														</v2_topLeftAxis>
														<style>
															<defaultStyles>
																<defaultStyle refStyle="ch"/>
															</defaultStyles>
														</style>
														<noDataHandler>
															<contents>
																<block>
																	<contents>
																		<textItem>
																			<dataSource>
																				<staticValue>No Data Available</staticValue>
																			</dataSource>
																			<style>
																				<CSS value="padding:10px 18px;"/>
																			</style>
																		</textItem>
																	</contents>
																</block>
															</contents>
														</noDataHandler>
														</v2_combinationChart></contents></conditionalBlock><conditionalBlock refVariableValue="2"><contents><v2_combinationChart maxHotspots="10000" orientation="horizontal" refQuery="Query2" name="Combination Chart1">
																		<v2_combinationTypeTooltips/>
																		<v2_legend>
																			<v2_legendPosition>
																				<v2_legendPreset/>
																			</v2_legendPosition>
																			<v2_legendTitle refQuery="Query2">
																				<v2_chartTextContents>
																					<v2_automaticText/>
																				</v2_chartTextContents>
																				<style>
																					<defaultStyles>
																						<defaultStyle refStyle="lx"/>
																					</defaultStyles>
																				</style>
																			</v2_legendTitle>
																			<style>
																				<defaultStyles>
																					<defaultStyle refStyle="lg"/>
																				</defaultStyles>
																			</style>
																		</v2_legend>
																		<v2_commonAxis>
																			<v2_ordinalAxis>
																				<v2_axisTitle refQuery="Query2">
																					<v2_chartTextContents>
																						<v2_automaticText/>
																					</v2_chartTextContents>
																					<style>
																						<defaultStyles>
																							<defaultStyle refStyle="at"/>
																						</defaultStyles>
																					</style>
																				</v2_axisTitle>
																				<v2_axisLine lineWeight="0"/>
																				<v2_axisLabels>
																					<style>
																						<defaultStyles>
																							<defaultStyle refStyle="al"/>
																						</defaultStyles>
																					</style>
																				</v2_axisLabels>
																			</v2_ordinalAxis>
																			<chartNodes><chartNode><chartNodeMembers><chartNodeMember refDataItem="Product Types"><chartContents><chartTextItem><dataSource><memberCaption/></dataSource></chartTextItem></chartContents></chartNodeMember></chartNodeMembers></chartNode></chartNodes></v2_commonAxis>
																		<v2_topLeftAxis>
																			<v2_combinationChartTypes>
																				<v2_bar borders="show">
																					<v2_solidPalette>
																						<v2_solidPaletteEntries>
																							<v2_solidPaletteEntry>
																								<v2_fillEffect defaultColor="#8599D3">
																									<v2_linearGradient>
																										<v2_gradientColor gradientColor="#8599D3"/>
																										<v2_gradientColor colorPosition="100" gradientColor="#5876AE"/>
																									</v2_linearGradient>
																								</v2_fillEffect>
																							</v2_solidPaletteEntry>
																							<v2_solidPaletteEntry>
																								<v2_fillEffect defaultColor="#E3AE6C">
																									<v2_linearGradient>
																										<v2_gradientColor gradientColor="#E3AE6C"/>
																										<v2_gradientColor colorPosition="100" gradientColor="#CD854E"/>
																									</v2_linearGradient>
																								</v2_fillEffect>
																							</v2_solidPaletteEntry>
																							<v2_solidPaletteEntry>
																								<v2_fillEffect defaultColor="#839862">
																									<v2_linearGradient>
																										<v2_gradientColor gradientColor="#839862"/>
																										<v2_gradientColor colorPosition="100" gradientColor="#6C7F56"/>
																									</v2_linearGradient>
																								</v2_fillEffect>
																							</v2_solidPaletteEntry>
																							<v2_solidPaletteEntry>
																								<v2_fillEffect defaultColor="#B7C873">
																									<v2_linearGradient>
																										<v2_gradientColor gradientColor="#B7C873"/>
																										<v2_gradientColor colorPosition="100" gradientColor="#AFB885"/>
																									</v2_linearGradient>
																								</v2_fillEffect>
																							</v2_solidPaletteEntry>
																							<v2_solidPaletteEntry>
																								<v2_fillEffect defaultColor="#8484A8">
																									<v2_linearGradient>
																										<v2_gradientColor gradientColor="#8484A8"/>
																										<v2_gradientColor colorPosition="100" gradientColor="#525E7E"/>
																									</v2_linearGradient>
																								</v2_fillEffect>
																							</v2_solidPaletteEntry>
																							<v2_solidPaletteEntry>
																								<v2_fillEffect defaultColor="#C0CCED">
																									<v2_linearGradient>
																										<v2_gradientColor gradientColor="#C0CCED"/>
																										<v2_gradientColor colorPosition="100" gradientColor="#B0C2E5"/>
																									</v2_linearGradient>
																								</v2_fillEffect>
																							</v2_solidPaletteEntry>
																							<v2_solidPaletteEntry>
																								<v2_fillEffect defaultColor="#8C5580">
																									<v2_linearGradient>
																										<v2_gradientColor gradientColor="#8C5580"/>
																										<v2_gradientColor colorPosition="100" gradientColor="#794067"/>
																									</v2_linearGradient>
																								</v2_fillEffect>
																							</v2_solidPaletteEntry>
																							<v2_solidPaletteEntry>
																								<v2_fillEffect defaultColor="#C789BC">
																									<v2_linearGradient>
																										<v2_gradientColor gradientColor="#C789BC"/>
																										<v2_gradientColor colorPosition="100" gradientColor="#BB72BC"/>
																									</v2_linearGradient>
																								</v2_fillEffect>
																							</v2_solidPaletteEntry>
																							<v2_solidPaletteEntry>
																								<v2_fillEffect defaultColor="#D5BAEF">
																									<v2_linearGradient>
																										<v2_gradientColor gradientColor="#D5BAEF"/>
																										<v2_gradientColor colorPosition="100" gradientColor="#C29FD1"/>
																									</v2_linearGradient>
																								</v2_fillEffect>
																							</v2_solidPaletteEntry>
																							<v2_solidPaletteEntry>
																								<v2_fillEffect defaultColor="#83683F">
																									<v2_linearGradient>
																										<v2_gradientColor gradientColor="#83683F"/>
																										<v2_gradientColor colorPosition="100" gradientColor="#604926"/>
																									</v2_linearGradient>
																								</v2_fillEffect>
																							</v2_solidPaletteEntry>
																							<v2_solidPaletteEntry>
																								<v2_fillEffect defaultColor="#DCB05A">
																									<v2_linearGradient>
																										<v2_gradientColor gradientColor="#DCB05A"/>
																										<v2_gradientColor colorPosition="100" gradientColor="#C09C52"/>
																									</v2_linearGradient>
																								</v2_fillEffect>
																							</v2_solidPaletteEntry>
																							<v2_solidPaletteEntry>
																								<v2_fillEffect defaultColor="#F4DF9E">
																									<v2_linearGradient>
																										<v2_gradientColor gradientColor="#F4DF9E"/>
																										<v2_gradientColor colorPosition="100" gradientColor="#E4CF87"/>
																									</v2_linearGradient>
																								</v2_fillEffect>
																							</v2_solidPaletteEntry>
																							<v2_solidPaletteEntry>
																								<v2_fillEffect defaultColor="#5F8A8C">
																									<v2_linearGradient>
																										<v2_gradientColor gradientColor="#5F8A8C"/>
																										<v2_gradientColor colorPosition="100" gradientColor="#537579"/>
																									</v2_linearGradient>
																								</v2_fillEffect>
																							</v2_solidPaletteEntry>
																							<v2_solidPaletteEntry>
																								<v2_fillEffect defaultColor="#96C4B2">
																									<v2_linearGradient>
																										<v2_gradientColor gradientColor="#96C4B2"/>
																										<v2_gradientColor colorPosition="100" gradientColor="#89B0A0"/>
																									</v2_linearGradient>
																								</v2_fillEffect>
																							</v2_solidPaletteEntry>
																							<v2_solidPaletteEntry>
																								<v2_fillEffect defaultColor="#CBE8E7">
																									<v2_linearGradient>
																										<v2_gradientColor gradientColor="#CBE8E7"/>
																										<v2_gradientColor colorPosition="100" gradientColor="#BDD6D5"/>
																									</v2_linearGradient>
																								</v2_fillEffect>
																							</v2_solidPaletteEntry>
																							<v2_solidPaletteEntry>
																								<v2_fillEffect defaultColor="#AE6564">
																									<v2_linearGradient>
																										<v2_gradientColor gradientColor="#AE6564"/>
																										<v2_gradientColor colorPosition="100" gradientColor="#875352"/>
																									</v2_linearGradient>
																								</v2_fillEffect>
																							</v2_solidPaletteEntry>
																							<v2_solidPaletteEntry>
																								<v2_fillEffect defaultColor="#D88C6F">
																									<v2_linearGradient>
																										<v2_gradientColor gradientColor="#D88C6F"/>
																										<v2_gradientColor colorPosition="100" gradientColor="#C47D61"/>
																									</v2_linearGradient>
																								</v2_fillEffect>
																							</v2_solidPaletteEntry>
																							<v2_solidPaletteEntry>
																								<v2_fillEffect defaultColor="#E3C9B0">
																									<v2_linearGradient>
																										<v2_gradientColor gradientColor="#E3C9B0"/>
																										<v2_gradientColor colorPosition="100" gradientColor="#D2B2A5"/>
																									</v2_linearGradient>
																								</v2_fillEffect>
																							</v2_solidPaletteEntry>
																							<v2_solidPaletteEntry>
																								<v2_fillEffect defaultColor="#848484">
																									<v2_linearGradient>
																										<v2_gradientColor gradientColor="#848484"/>
																										<v2_gradientColor colorPosition="100" gradientColor="#555555"/>
																									</v2_linearGradient>
																								</v2_fillEffect>
																							</v2_solidPaletteEntry>
																							<v2_solidPaletteEntry>
																								<v2_fillEffect defaultColor="#a4a4a4">
																									<v2_linearGradient>
																										<v2_gradientColor gradientColor="#a4a4a4"/>
																										<v2_gradientColor colorPosition="100" gradientColor="#909090"/>
																									</v2_linearGradient>
																								</v2_fillEffect>
																							</v2_solidPaletteEntry>
																							<v2_solidPaletteEntry>
																								<v2_fillEffect defaultColor="#C7C7C7">
																									<v2_linearGradient>
																										<v2_gradientColor gradientColor="#C7C7C7"/>
																										<v2_gradientColor colorPosition="100" gradientColor="#c1c1c1"/>
																									</v2_linearGradient>
																								</v2_fillEffect>
																							</v2_solidPaletteEntry>
																						</v2_solidPaletteEntries>
																					</v2_solidPalette>
																					<!-- v2_solidPaletteRef ref=&amp;amp;quot;gDefaultSolid&amp;amp;quot;/ -->
																					<chartNodes><chartNode><chartNodeMembers><chartNodeMember refDataItem="Revenue"><chartContents><chartTextItem><dataSource><memberCaption/></dataSource></chartTextItem></chartContents></chartNodeMember></chartNodeMembers></chartNode></chartNodes></v2_bar>
																			</v2_combinationChartTypes>
																			<v2_axis>
																				<v2_axisTitle refQuery="Query2">
																					<v2_chartTextContents>
																						<v2_automaticText/>
																					</v2_chartTextContents>
																					<style>
																						<defaultStyles>
																							<defaultStyle refStyle="at"/>
																						</defaultStyles>
																					</style>
																				</v2_axisTitle>
																				<v2_axisLine lineWeight="0"/>
																				<v2_axisRange>
																					<v2_automaticRange/>
																				</v2_axisRange>
																				<v2_axisLabels>
																					<style>
																						<defaultStyles>
																							<defaultStyle refStyle="al"/>
																						</defaultStyles>
																					</style>
																				</v2_axisLabels>
																				<v2_majorGridlines lineWeight="0" lineColor="#CCCCCC"/>
																				<v2_majorBackgroundColors>
																					<v2_firstBackgroundColor color="#D2D2D2" transparency="50"/>
																					<v2_secondBackgroundColor color="#E2E2E2" transparency="50"/>
																				</v2_majorBackgroundColors>
																			</v2_axis>
																		</v2_topLeftAxis>
																		<style>
																			<CSS value=""/><defaultStyles><defaultStyle refStyle="ch"/></defaultStyles></style>
																		<noDataHandler>
																			<contents>
																				<block>
																					<contents>
																						<textItem>
																							<dataSource>
																								<staticValue>No Data Available</staticValue>
																							</dataSource>
																							<style>
																								<CSS value="padding:10px 18px;"/>
																							</style>
																						</textItem>
																					</contents>
																				</block>
																			</contents>
																		</noDataHandler>
																		</v2_combinationChart>
																</contents></conditionalBlock><conditionalBlock refVariableValue="3"><contents><crosstab name="Crosstab1" refQuery="Query2" pageBreakText="false" repeatEveryPage="true">
			<crosstabCorner>
				<contents/>
				<style>
					<defaultStyles>
						<defaultStyle refStyle="xm"/>
					</defaultStyles>
				</style>
			</crosstabCorner>
			
			
			<noDataHandler>
				<contents>
					<block>
						<contents>
							<textItem>
								<dataSource>
									<staticValue>No Data Available</staticValue>
								</dataSource>
								<style>
									<CSS value="padding:10px 18px;"/>
								</style>
							</textItem>
						</contents>
					</block>
				</contents>
			</noDataHandler>
			<style>
				<CSS value="border-collapse:collapse"/>
				<defaultStyles>
					<defaultStyle refStyle="xt"/>
				</defaultStyles>
			</style>
		<crosstabFactCell><contents><textItem><dataSource><cellValue/></dataSource></textItem></contents><style><defaultStyles><defaultStyle refStyle="mv"/></defaultStyles></style></crosstabFactCell><crosstabRows><crosstabNode><crosstabNodeMembers><crosstabNodeMember refDataItem="Product Types" edgeLocation="e1"><style><defaultStyles><defaultStyle refStyle="ml"/></defaultStyles></style><contents><textItem><dataSource><memberCaption/></dataSource></textItem></contents></crosstabNodeMember></crosstabNodeMembers></crosstabNode></crosstabRows><crosstabColumns><crosstabNode><crosstabNodeMembers><crosstabNodeMember refDataItem="Revenue" edgeLocation="e2"><style><defaultStyles><defaultStyle refStyle="ml"/></defaultStyles></style><contents><textItem><dataSource><memberCaption/></dataSource></textItem></contents></crosstabNodeMember></crosstabNodeMembers></crosstabNode></crosstabColumns></crosstab></contents></conditionalBlock></conditionalBlockCases></conditionalBlocks></contents><style><CSS value="width:100%;vertical-align:top;text-align:left"/></style></tableCell></tableCells></tableRow></tableRows></table><HTMLItem>
			<dataSource>
				<staticValue>&lt;style&gt;
.Vertical{
  width:'';
  height:'';
}

.VerticalUnselected{
  padding:2px 10px 3px 10px;
  margin-right:7px;
  background-image:url(../reportstyles/images/button_bg.png);
  background-position:left top;
  background-repeat:repeat-x;
  background-color:#EFEFEF;
  color:#000000;
  font-size:10pt;
  font-weight:normal;
  text-align:center;
  border:1px solid #92afc2;
  width: 75px;
  display:block;
}

.VerticalSelected{
  padding:2px 10px 3px 10px;
  margin-right:7px;
  background-image:url(../reportstyles/images/button_bg.png);
  background-position:left top;
  background-repeat:repeat-x;
  background-color:#A0AFEB;
  color:#000000;
  font-size:10pt;
  font-weight:normal;
  text-align:center;
  border:1px solid #92afc2;
  width: 75px;
  display:block;
}

.Horizontal{
  width:0;
  height:0;
  white-space:nowrap;
}

.HorizontalUnselected{
  padding:2px 10px 3px 10px;
  margin-right:7px;
  background-image:url(../reportstyles/images/button_bg.png);
  background-position:left top;
  background-repeat:repeat-x;
  background-color:#EFEFEF;
  color:#000000;
  font-size:10pt;
  font-weight:normal;
  text-align:center;
  border:1px solid #92afc2;
}

.HorizontalSelected{
  padding:2px 10px 3px 10px;
  margin-right:7px;
  background-image:url(../reportstyles/images/button_bg.png);
  background-position:left top;
  background-repeat:repeat-x;
  background-color:#A0AFEB;
  color:#000000;
  font-size:10pt;
  font-weight:normal;
  text-align:center;
  border:1px solid #92afc2;
}

&lt;/style&gt;
&lt;script&gt;

/* 
  * Function: addEvent
  * Author: Dan Fruendel
  * Attachs an event or adds an event listener depending on the browser.
  */
var
  addEvent = function(element, event, func)
  {
    if(element.addEventListener)
    {
      addEvent = function(element, event, func)
      {
        element.addEventListener(event, func, false);
        return true;
      };
    }
    else if(element.attachEvent)
    {
      addEvent = function(element, event, func)
      {
        return element.attachEvent("on" + event, func);
      };
    }
    else
    {
      addEvent = function(element, event, func)
      {
        var oldEventHandler = element['on' + event];
        element['on' + event] = function()
        {
          //using .apply to pass on anything this function gets.
          if(typeof(oldEventHandler) === "function")
          {
            oldEventHandler.apply(element, arguments);
          }
          func.apply(element, arguments);
        }
        return true;
      };
    }
    return addEvent(element, event, func);
  }
/*
 * Fake Namespace and prompt getters.
 */ 	
var paulScripts = {}
  , oCR = cognos.Report.getReport("_THIS_");

paulScripts.getSource = function()
{
    var targ;
    if (!e) var e = window.event;
    if(!e) return false;
    if (e.target) targ = e.target;
    else if (e.srcElement) targ = e.srcElement;
    if (targ.nodeType == 3) // defeat Safari bug
      targ = targ.parentNode;
    return targ;
}

paulScripts.getControl = function(promptName) {
  return oCR.prompt.getControlByName(promptName);
}

paulScripts.reprompt = function(){
if(!paulScripts.getSource() ) return true;
  oCR.sendRequest(cognos.Report.Action.REPROMPT);
  return true;
}


paulScripts.addButtons = function ( promptName, myClass,reprompt) {
var 
    newOption = ''
  , reprompt = reprompt?reprompt:false
  , id = paulScripts.getControl ( promptName )._id_
  , selElm = document.getElementById('PRMT_SV_'+ id)
  , selElmSelect = document.getElementById('PRMT_SV_LINK_SELECT_'+ id)
  , selElmDeselect = document.getElementById('PRMT_SV_LINK_DESELECT_'+ id)
  , rads = selElm.getElementsByTagName('input')
  , len = rads.length
  , type = len==0?'none':rads[0].type
  , radioClick = function(){for(var radios=paulScripts.getSource().parentNode.getElementsByTagName('input').length/2;radios&lt;paulScripts.getSource().parentNode.getElementsByTagName('input').length;radios++){paulScripts.getSource().parentNode.getElementsByTagName('input')[radios].className=myClass + 'Unselected'};paulScripts.getSource().parentNode.getElementsByTagName('input')[paulScripts.getSource().index].click(); paulScripts.getSource().className=myClass + 'Selected'}
  , checkClick= function(){paulScripts.getSource().parentNode.getElementsByTagName('input')[paulScripts.getSource().index].click(); paulScripts.getSource().className=paulScripts.getSource().className==myClass + 'Selected'?myClass + 'Unselected':myClass + 'Selected';}
  , selectAll= function(){ for(var elms=rads.length;elms&gt;rads.length/2;elms--){rads[elms-1].className=myClass + 'Selected'}}
  , deselectAll= function(){ ; for(var elms=rads.length;elms&gt;rads.length/2;elms--){rads[elms-1].className=myClass + 'Unselected'}}
;
  selElm.className = myClass;

  if(type == 'none') return false;

  for(i=0;i&lt;len;i++)
  {
    newOption = document.createElement( 'input');
    newOption.type='button';
    newOption.value=rads[i].getAttribute('dv');
    newOption.className=rads[i].selected?myClass + 'Selected': myClass + 'Unselected';
    newOption.index=i;
    if(type=='checkbox') {addEvent(newOption,'click',checkClick)};
    if(type=='radio') {addEvent(newOption,'click',radioClick)};
    rads[i].parentNode.parentNode.style.display='none';
    selElm.appendChild(newOption );
  }

  if(reprompt) paulScripts.getControl ( promptName ).setValidator(paulScripts.reprompt);

  if(selElmSelect) addEvent(selElmSelect,'click',selectAll);
  if(selElmDeselect) addEvent(selElmDeselect,'click',deselectAll);
}

paulScripts.addButtons('Products','Horizontal',1);

paulScripts.addButtons('Reports','Vertical');
&lt;/script&gt;</staticValue>
			</dataSource>
		</HTMLItem></contents>
								</pageBody>
							</page>
						</reportPages>
					</layout>
				</layouts>
			<XMLAttributes><XMLAttribute name="RS_CreateExtendedDataItems" value="true" output="no"/><XMLAttribute name="listSeparator" value="," output="no"/><XMLAttribute name="RS_modelModificationTime" value="2008-07-25T15:28:38.133Z" output="no"/></XMLAttributes><classStyles><classStyle name="cls1" label="Button1"><CSS value="padding:2px 10px 3px 10px;margin-right:7px;background-image:url(../reportstyles/images/button_bg.png);background-position:left top;background-repeat:repeat-x;background-color:#CCFFCC;color:#000000;font-size:10pt;font-weight:normal;text-align:center;border:1px solid #92afc2"/></classStyle></classStyles><reportName>radios to buttons</reportName><queries><query name="Query2"><source><model/></source><selection><dataItem name="Product Types"><expression>descendants(
#promptmany('Products','mun','[sales_and_marketing].[Products].[Products].[Products]-&gt;:[PC].[@MEMBER].[Products]','set(','',')')#
,[sales_and_marketing].[Products].[Products].[Product type]
)</expression></dataItem><dataItemMeasure name="Revenue"><dmMember><MUN>[sales_and_marketing].[Measures].[Revenue]</MUN><itemCaption>Revenue</itemCaption></dmMember><dmDimension><DUN>[sales_and_marketing].[Measures]</DUN><itemCaption>Measures</itemCaption></dmDimension><XMLAttributes><XMLAttribute name="RS_dataType" value="9" output="no"/></XMLAttributes></dataItemMeasure></selection></query><query name="Products"><source><model/></source><selection><dataItem name="Product line" aggregate="none"><expression>[sales_and_marketing].[Products].[Products].[Product line]</expression></dataItem></selection></query></queries><reportVariables><reportVariable type="string" name="ReportType">
			<reportExpression>ParamValue('ReportType')</reportExpression>
		<variableValues><variableValue value="1"/><variableValue value="2"/><variableValue value="3"/></variableValues></reportVariable></reportVariables></report>

Checkbox List Prompts revisited

$
0
0

A long while back, I published an article detailing how to use a list to interact with a checkbox prompt. Since then, several people have asked me to add features to the code, and to fix some bugs. I’ve also learned quite a bit since I wrote that, so I’ve rewritten a parts of it.

The basic core of the code is the same. Using div tags to identify the list and prompt objects, with more HTML items to build the actual checkbox in the list. This is by no means optimized JavaScript, nor is it using the 10.2 Prompt API.

Previously the code would only work with one list. The reference to the list was hardcoded in the script and the checkboxes and select all buttons would fail for the second list. Also requested, using grouped rows. For instance, a user might want to select all of the months in 2011 by checking on the checkbox in the 2011 group. Another thing I fixed was the way it would loop through value prompts to find the correct value. If the key had any special characters, it wouldn’t be able to find it. Cognos would automatically escape those special characters.

The XML below was written on 10.2, but will downgrade easily to 10.1 by changing

xmlns="http://developer.cognos.com/schemas/report/9.0/"

to

xmlns="http://developer.cognos.com/schemas/report/8.0/"

The JavaScript will work in 8.4 as well, but downgrading will be a bit more difficult – you need to use /report/6.0/ and remove all of the version 10 only XML elements. If there’s a demand for it, I’ll go through and post all of the different JavaScript objects here. (But there shouldn’t be, because 10.2 is the greatest things since 10.1.1 and you should all upgrade and IBM should be paying me push upgrades like this.)

<report xmlns="http://developer.cognos.com/schemas/report/9.0/" expressionLocale="he" interactivePageBreakByFrame="true">
    <modelPath>/content/folder[@name='Samples']/folder[@name='Cubes']/package[@name='Sales and Marketing (cube)']/model[@name='2008-07-25T15:28:38.072Z']</modelPath> 
    <layouts> 
        <layout> 
            <reportPages> 
                <page name="Page1"> 
                    <pageBody> 
                        <contents><HTMLItem description="Styles"> 
                                <dataSource> 
                                    <staticValue>&lt;style type="text/css"&gt; 
  
input.updatebutton 
{ 
   font-size:11px; 
   font-weight:bold; 
   width:140px; 
   height:27px; 
   color:#000000; 
   background-color:#cdc9c9; 
   border-style:solid; 
   border-color:#003377; 
   border-width:3px; 
} 
  
  
  
input.matchbutton 
{ 
   font-size:11px; 
   font-weight:bold; 
   width:140px; 
   height:27px; 
   color:#EEFFFF; 
   background-color:#0088DD; 
   border-style:solid; 
   border-color:#003377; 
   border-width:3px; 
} 
  
input.selectbutton 
{ 
   font-size:9px; 
   font-weight:bold; 
   width:60px; 
   height:20px; 
   color:#000000; 
   background-color:#FFFFFF; 
   border-style:solid; 
   border-color:#FFFFFF; 
   border-width:3px; 
} 
  
&lt;/style&gt; 
  
&lt;script language="javascript"&gt; 
  
function goLite(FRM,BTN) 
{ 
   window.document.forms[FRM].elements[BTN].style.color = "#FFFF99"; 
   window.document.forms[FRM].elements[BTN].style.backgroundColor = "#11AAEE"; 
} 
  
function goDim(FRM,BTN) 
{ 
   window.document.forms[FRM].elements[BTN].style.color = "#EEFFFF"; 
   window.document.forms[FRM].elements[BTN].style.backgroundColor = "#0088DD"; 
} 
  
&lt;/script&gt; 
</staticValue> 
                                </dataSource> 
                            </HTMLItem> 
                            <HTMLItem description="Scripts"> 
                                <dataSource> 
                                    <staticValue>&lt;script&gt; 
function selectInCheckbox(cbGroup,id) 
{ 
   var inputs= document.getElementById(cbGroup).getElementsByTagName('input'); 
   for (var i=0;i&lt;inputs.length;i++) 
   { 
        if (inputs[i].value == id)  
        { 
            inputs[i].click(); 
        } 
   } 
} 
  
function selectInCheckboxRow(cbGroup,id) 
{ 
    var inputs= document.getElementById(cbGroup).getElementsByTagName('input'); 
    inputs[id].click(); 
} 

function checkAll(list){ 
var inputs=document.getElementById(list).getElementsByTagName('input') 
for (var i=0;i&lt;inputs.length;i++){ 
        if (inputs[i].type == 'checkbox') { 
            if (inputs[i].checked == true)  
        {} 
        else {inputs[i].click();} 
        } 
} 
}  
  
function unCheckAll(list){ 
var inputs=document.getElementById(list).getElementsByTagName('input') 
for (var i=0;i&lt;inputs.length;i++){ 
        if (inputs[i].type == 'checkbox') { 
            if (inputs[i].checked == true)  
        {inputs[i].click();} 
        else {} 
        } 
} 
}  

function getSource (){
    var targ; 
    if (!e) var e = window.event; 
    if(!e) return false; 
    if (e.target) targ = e.target; 
    else if (e.srcElement) targ = e.srcElement; 
    if (targ.nodeType == 3) // defeat Safari bug 
      targ = targ.parentNode; 
    return targ; 
} 
  

function checkNested(){

var 
    elm = getSource().parentNode
  , tbody = elm.parentNode.parentNode.parentNode
  , rowsLength = tbody.rows.length
  , rowSpanLength = elm.rowSpan
  , rowIndex = elm.parentNode.rowIndex
  , isChecked = getSource().checked;

  for(var i=rowIndex;i&lt;rowIndex+rowSpanLength;i++)
  {
     var e = i == rowIndex?elm.cellIndex + 1 : 0;
      if(tbody.rows[i].cells[e].getElementsByTagName('INPUT')[0].checked == isChecked) {continue;}
     else{  tbody.rows[i].cells[e].getElementsByTagName('INPUT')[0].click()}
      i = i+elm.nextSibling.rowSpan - 1;

  }
}
&lt;/script&gt; 
  
</staticValue> 
                                </dataSource> 
                            </HTMLItem> 
                              
                              
                            <promptButton type="reprompt"> 
            <contents/> 
            <style> 
                <defaultStyles> 
                    <defaultStyle refStyle="bp"/> 
                </defaultStyles> 
            </style> 
        </promptButton><table><style><defaultStyles><defaultStyle refStyle="tb"/></defaultStyles><CSS value="border-collapse:collapse"/></style><tableRows><tableRow><tableCells><tableCell><contents><HTMLItem description="div"> 
            <dataSource> 
                <staticValue>&lt;div id="checkbox1" &gt;</staticValue> 
            </dataSource> 
        </HTMLItem><selectValue multiSelect="true" parameter="code" range="false" refQuery="Prompt" required="false" selectValueUI="checkboxGroup"><useItem refDataItem="Product line code"/><sortList><sortItem refDataItem="Product line code"/></sortList></selectValue><HTMLItem description="/div"> 
            <dataSource> 
                <staticValue>&lt;/div&gt;</staticValue> 
            </dataSource> 
        </HTMLItem><HTMLItem description="div"> 
            <dataSource> 
                <staticValue>&lt;div id="checkbox2" &gt;</staticValue> 
            </dataSource> 
        </HTMLItem><selectValue multiSelect="true" parameter="Quarter" refQuery="Quarters" required="false" selectValueUI="checkboxGroup"><useItem refDataItem="Quarter - Category Code"><displayItem refDataItem="Quarter"/></useItem></selectValue><HTMLItem description="/div"> 
            <dataSource> 
                <staticValue>&lt;/div&gt;</staticValue> 
            </dataSource> 
        </HTMLItem></contents><style><CSS value="vertical-align:top"/></style></tableCell><tableCell><contents><HTMLItem description="div id=&quot;list1&quot;"> 
                                                                <dataSource> 
                                                                    <staticValue>&lt;div id="list1"&gt;</staticValue> 
                                                                </dataSource> 
                                                            </HTMLItem><list name="List2" pageBreakText="false" refQuery="Prompt" repeatEveryPage="true"> 
              
              
              
            <style> 
                <CSS value="border-collapse:collapse"/> 
                <defaultStyles> 
                    <defaultStyle refStyle="ls"/> 
                </defaultStyles> 
            </style> 
        <listColumns><listColumn><listColumnTitle><style><defaultStyles><defaultStyle refStyle="lt"/></defaultStyles></style><contents><textItem><dataSource><staticValue>HTML Item</staticValue></dataSource></textItem></contents></listColumnTitle><listColumnBody><style><defaultStyles><defaultStyle refStyle="lc"/></defaultStyles></style><contents><HTMLItem description="Checkbox Start"> 
                                                                                    <dataSource> 
                                                                                        <staticValue>&lt;input title="Faster but if the sorting is off then this won't work" type="checkbox"  
</staticValue></dataSource> 
                                                                                </HTMLItem><HTMLItem description="checked"> 
            <dataSource> 
                  
            <reportExpression>case when (ParamValue('code') +', ') contains ([Product line code] +', ') then (' checked ') else ('') end</reportExpression></dataSource> 
        </HTMLItem><HTMLItem description="onClick"> 
            <dataSource> 
                <staticValue>onClick="selectInCheckboxRow('checkbox1','</staticValue> 
            </dataSource> 
        </HTMLItem><HTMLItem description="Row"> 
            <dataSource> 
                  
            <reportExpression>RowNumber ()</reportExpression></dataSource> 
        </HTMLItem><HTMLItem description="CheckboxEnd"> 
                                                                                    <dataSource> 
                                                                                        <staticValue>'); 
"&gt; 
</staticValue> 
                                                                                    </dataSource> 
                                                                                </HTMLItem></contents></listColumnBody></listColumn><listColumn><listColumnTitle><style><defaultStyles><defaultStyle refStyle="lt"/></defaultStyles></style><contents><textItem><dataSource><staticValue>By Code</staticValue></dataSource></textItem></contents></listColumnTitle><listColumnBody><style><defaultStyles><defaultStyle refStyle="lc"/></defaultStyles></style><contents><HTMLItem description="Checkbox Start"> 
                                                                                    <dataSource> 
                                                                                        <staticValue>&lt;input title="Slower but less prone to error" type="checkbox"  
</staticValue></dataSource> 
                                                                                </HTMLItem><HTMLItem description="checked"> 
            <dataSource> 
                  
            <reportExpression>case when (ParamValue('code') +', ') contains ([Product line code] +', ') then (' checked ') else ('') end</reportExpression></dataSource> 
        </HTMLItem><HTMLItem description="onClick"> 
            <dataSource> 
                <staticValue>onClick="selectInCheckbox('checkbox1','</staticValue> 
            </dataSource> 
        </HTMLItem><HTMLItem description="Code"> 
            <dataSource> 
                  
            <dataItemValue refDataItem="Product line code"/></dataSource> 
        </HTMLItem><HTMLItem description="CheckboxEnd"> 
                                                                                    <dataSource> 
                                                                                        <staticValue>'); 
"&gt; 
</staticValue> 
                                                                                    </dataSource> 
                                                                                </HTMLItem></contents></listColumnBody></listColumn><listColumn><listColumnTitle><style><defaultStyles><defaultStyle refStyle="lt"/></defaultStyles></style><contents><textItem><dataSource><dataItemLabel refDataItem="Product line"/></dataSource></textItem></contents></listColumnTitle><listColumnBody><style><defaultStyles><defaultStyle refStyle="lc"/></defaultStyles></style><contents><textItem><dataSource><dataItemValue refDataItem="Product line"/></dataSource></textItem></contents></listColumnBody></listColumn><listColumn><listColumnTitle><style><defaultStyles><defaultStyle refStyle="lt"/></defaultStyles></style><contents><textItem><dataSource><dataItemLabel refDataItem="Quantity"/></dataSource></textItem></contents></listColumnTitle><listColumnBody><style><defaultStyles><defaultStyle refStyle="lm"/></defaultStyles></style><contents><textItem><dataSource><dataItemValue refDataItem="Quantity"/></dataSource></textItem></contents></listColumnBody></listColumn><listColumn><listColumnTitle><style><defaultStyles><defaultStyle refStyle="lt"/></defaultStyles></style><contents><textItem><dataSource><dataItemLabel refDataItem="Revenue"/></dataSource></textItem></contents></listColumnTitle><listColumnBody><style><defaultStyles><defaultStyle refStyle="lm"/></defaultStyles></style><contents><textItem><dataSource><dataItemValue refDataItem="Revenue"/></dataSource></textItem></contents></listColumnBody></listColumn><listColumn><listColumnTitle><style><defaultStyles><defaultStyle refStyle="lt"/></defaultStyles></style><contents><textItem><dataSource><dataItemLabel refDataItem="Gross profit"/></dataSource></textItem></contents></listColumnTitle><listColumnBody><style><defaultStyles><defaultStyle refStyle="lm"/></defaultStyles></style><contents><textItem><dataSource><dataItemValue refDataItem="Gross profit"/></dataSource></textItem></contents></listColumnBody></listColumn></listColumns><propertyList><propertyItem refDataItem="Product line code"/></propertyList><sortList><sortItem refDataItem="Product line code"/></sortList></list><HTMLItem description="/div"> 
                                                                <dataSource> 
                                                                    <staticValue>&lt;/div&gt;</staticValue> 
                                                                </dataSource> 
                                                            </HTMLItem><HTMLItem description="doAll"> 
                                                        <dataSource> 
                                                            <staticValue> &lt;input type="button" value="Select All" class="selectbutton" onmouseover = "this.style.cursor='hand'" onclick="checkAll('list1');"&gt; 
&lt;input type="button" value="Clear All" class="selectbutton" onmouseover = "this.style.cursor='hand'" onclick="unCheckAll('list1');"&gt;</staticValue> 
                                                        </dataSource> 
                                                    </HTMLItem><HTMLItem description="div id=&quot;list2&quot;"> 
                                                                <dataSource> 
                                                                    <staticValue>&lt;div id="list2"&gt;</staticValue> 
                                                                </dataSource> 
                                                            </HTMLItem><list horizontalPagination="true" name="List1" refQuery="Prompt">
			
			
			
			<noDataHandler>
				<contents>
					<block>
						<contents>
							<textItem>
								<dataSource>
									<staticValue>No Data Available</staticValue>
								</dataSource>
								<style>
									<CSS value="padding:10px 18px;"/>
								</style>
							</textItem>
						</contents>
					</block>
				</contents>
			</noDataHandler>
			<style>
				<CSS value="border-collapse:collapse"/>
				<defaultStyles>
					<defaultStyle refStyle="ls"/>
				</defaultStyles>
			</style>
		<listColumns><listColumn><listColumnTitle><style><defaultStyles><defaultStyle refStyle="lt"/></defaultStyles></style><contents><textItem><dataSource><dataItemLabel refDataItem="Time"/></dataSource></textItem></contents></listColumnTitle><listColumnBody><style><defaultStyles><defaultStyle refStyle="lc"/></defaultStyles></style><contents><HTMLItem>
			<dataSource>
				<staticValue>&lt;input type="checkbox" onclick="
checkNested()"&gt;</staticValue>
			</dataSource>
		</HTMLItem><textItem><dataSource><dataItemValue refDataItem="Time"/></dataSource></textItem></contents><listColumnRowSpan refDataItem="Time"/></listColumnBody></listColumn><listColumn><listColumnTitle><style><defaultStyles><defaultStyle refStyle="lt"/></defaultStyles></style><contents><textItem><dataSource><dataItemLabel refDataItem="Year"/></dataSource></textItem></contents></listColumnTitle><listColumnBody><style><defaultStyles><defaultStyle refStyle="lc"/></defaultStyles></style><contents><HTMLItem>
			<dataSource>
				<staticValue>&lt;input type="checkbox" onclick="
checkNested()"&gt;</staticValue>
			</dataSource>
		</HTMLItem><textItem><dataSource><dataItemValue refDataItem="Year"/></dataSource></textItem></contents><listColumnRowSpan refDataItem="Year"/></listColumnBody></listColumn><listColumn><listColumnTitle><style><defaultStyles><defaultStyle refStyle="lt"/></defaultStyles></style><contents><textItem><dataSource><dataItemLabel refDataItem="Quarter"/></dataSource></textItem></contents></listColumnTitle><listColumnBody><style><defaultStyles><defaultStyle refStyle="lc"/></defaultStyles></style><contents><HTMLItem description="Checkbox Start"> 
                                                                                    <dataSource> 
                                                                                        <staticValue>&lt;input title="Slower but less prone to error" type="checkbox"  
</staticValue></dataSource> 
                                                                                </HTMLItem><HTMLItem description="checked"> 
            <dataSource> 
                  
            <reportExpression>case when (ParamValue('Quarter') +', ') contains ([Quarter - Category Code] +', ') then (' checked ') else ('') end</reportExpression></dataSource> 
        </HTMLItem><HTMLItem description="onClick"> 
            <dataSource> 
                <staticValue>onClick="selectInCheckbox('checkbox2',unescape('</staticValue> 
            </dataSource> 
        </HTMLItem><HTMLItem description="Code"> 
            <dataSource> 
                  
            <reportExpression>URLEncode ([Prompt].[Quarter - Category Code])</reportExpression></dataSource> 
        </HTMLItem><HTMLItem description="CheckboxEnd"> 
                                                                                    <dataSource> 
                                                                                        <staticValue>')); 
"&gt; 
</staticValue> 
                                                                                    </dataSource> 
                                                                                </HTMLItem><textItem><dataSource><dataItemValue refDataItem="Quarter"/></dataSource></textItem></contents></listColumnBody></listColumn><listColumn><listColumnTitle><style><defaultStyles><defaultStyle refStyle="lt"/></defaultStyles></style><contents><textItem><dataSource><dataItemLabel refDataItem="Quantity"/></dataSource></textItem></contents></listColumnTitle><listColumnBody><style><defaultStyles><defaultStyle refStyle="lm"/></defaultStyles></style><contents><textItem><dataSource><dataItemValue refDataItem="Quantity"/></dataSource></textItem></contents></listColumnBody></listColumn><listColumn><listColumnTitle><style><defaultStyles><defaultStyle refStyle="lt"/></defaultStyles></style><contents><textItem><dataSource><dataItemLabel refDataItem="Revenue"/></dataSource></textItem></contents></listColumnTitle><listColumnBody><style><defaultStyles><defaultStyle refStyle="lm"/></defaultStyles></style><contents><textItem><dataSource><dataItemValue refDataItem="Revenue"/></dataSource></textItem></contents></listColumnBody></listColumn><listColumn><listColumnTitle><style><defaultStyles><defaultStyle refStyle="lt"/></defaultStyles></style><contents><textItem><dataSource><dataItemLabel refDataItem="Gross profit"/></dataSource></textItem></contents></listColumnTitle><listColumnBody><style><defaultStyles><defaultStyle refStyle="lm"/></defaultStyles></style><contents><textItem><dataSource><dataItemValue refDataItem="Gross profit"/></dataSource></textItem></contents></listColumnBody></listColumn></listColumns><propertyList><propertyItem refDataItem="Year - Category Code"/><propertyItem refDataItem="Quarter - Category Code"/></propertyList><listGroups><listGroup refDataItem="Time"/><listGroup refDataItem="Year"/></listGroups></list><HTMLItem description="/div"> 
                                                                <dataSource> 
                                                                    <staticValue>&lt;/div&gt;</staticValue> 
                                                                </dataSource> 
                                                            </HTMLItem><HTMLItem description="doAll"> 
                                                        <dataSource> 
                                                            <staticValue> &lt;input type="button" value="Select All" class="selectbutton" onmouseover = "this.style.cursor='hand'" onclick="checkAll('list2');"&gt; 
&lt;input type="button" value="Clear All" class="selectbutton" onmouseover = "this.style.cursor='hand'" onclick="unCheckAll('list2');"&gt;</staticValue> 
                                                        </dataSource> 
                                                    </HTMLItem><HTMLItem description="div id=&quot;list3&quot;"> 
                                                                <dataSource> 
                                                                    <staticValue>&lt;div id="list3"&gt;</staticValue> 
                                                                </dataSource> 
                                                            </HTMLItem><crosstab name="Crosstab1" pageBreakText="false" refQuery="Prompt" repeatEveryPage="true">
			<crosstabCorner>
				<contents/>
				<style>
					<defaultStyles>
						<defaultStyle refStyle="xm"/>
					</defaultStyles>
				</style>
			</crosstabCorner>
			
			
			
			<style>
				<CSS value="border-collapse:collapse"/>
				<defaultStyles>
					<defaultStyle refStyle="xt"/>
				</defaultStyles>
			</style>
		<crosstabFactCell><contents><textItem><dataSource><cellValue/></dataSource></textItem></contents><style><defaultStyles><defaultStyle refStyle="mv"/></defaultStyles></style></crosstabFactCell><crosstabColumns><crosstabNode><crosstabNodeMembers><crosstabNodeMember edgeLocation="e5" refDataItem="Product line"><style><defaultStyles><defaultStyle refStyle="ml"/></defaultStyles></style><contents><HTMLItem description="Checkbox Start"> 
                                                                                    <dataSource> 
                                                                                        <staticValue>&lt;input title="Slower but less prone to error" type="checkbox"  
</staticValue></dataSource> 
                                                                                </HTMLItem><HTMLItem description="checked"> 
            <dataSource> 
                  
            <reportExpression>case when (ParamValue('code') +', ') contains ([Product line code] +', ') then (' checked ') else ('') end</reportExpression></dataSource> 
        </HTMLItem><HTMLItem description="onClick"> 
            <dataSource> 
                <staticValue>onClick="selectInCheckbox('checkbox1','</staticValue> 
            </dataSource> 
        </HTMLItem><HTMLItem description="Code"> 
            <dataSource> 
                  
            <dataItemValue refDataItem="Product line code"/></dataSource> 
        </HTMLItem><HTMLItem description="CheckboxEnd"> 
                                                                                    <dataSource> 
                                                                                        <staticValue>'); 
"&gt; 
</staticValue> 
                                                                                    </dataSource> 
                                                                                </HTMLItem><textItem><dataSource><memberCaption/></dataSource></textItem></contents><propertyList><propertyItem refDataItem="Product line code"/></propertyList></crosstabNodeMember></crosstabNodeMembers><crosstabNestedNodes><crosstabNode><crosstabNodeMembers><crosstabNodeMember edgeLocation="e1" refDataItem="Quantity"><contents><textItem><dataSource><memberCaption/></dataSource></textItem></contents><style><defaultStyles><defaultStyle refStyle="ml"/></defaultStyles></style></crosstabNodeMember></crosstabNodeMembers></crosstabNode><crosstabNode><crosstabNodeMembers><crosstabNodeMember edgeLocation="e2" refDataItem="Revenue"><contents><textItem><dataSource><memberCaption/></dataSource></textItem></contents><style><defaultStyles><defaultStyle refStyle="ml"/></defaultStyles></style></crosstabNodeMember></crosstabNodeMembers></crosstabNode><crosstabNode><crosstabNodeMembers><crosstabNodeMember edgeLocation="e3" refDataItem="Gross profit"><contents><textItem><dataSource><memberCaption/></dataSource></textItem></contents><style><defaultStyles><defaultStyle refStyle="ml"/></defaultStyles></style></crosstabNodeMember></crosstabNodeMembers></crosstabNode></crosstabNestedNodes></crosstabNode></crosstabColumns><crosstabRows><crosstabNode><crosstabNodeMembers><crosstabNodeMember edgeLocation="e4" refDataItem="Quarter"><style><defaultStyles><defaultStyle refStyle="ml"/></defaultStyles></style><contents><HTMLItem description="Checkbox Start"> 
                                                                                    <dataSource> 
                                                                                        <staticValue>&lt;input title="Slower but less prone to error" type="checkbox"  
</staticValue></dataSource> 
                                                                                </HTMLItem><HTMLItem description="checked"> 
            <dataSource> 
                  
            <reportExpression>case when (ParamValue('Quarter') +', ') contains ([Quarter - Category Code] +', ') then (' checked ') else ('') end</reportExpression></dataSource> 
        </HTMLItem><HTMLItem description="onClick"> 
            <dataSource> 
                <staticValue>onClick="selectInCheckbox('checkbox2',unescape('</staticValue> 
            </dataSource> 
        </HTMLItem><HTMLItem description="Code"> 
            <dataSource> 
                  
            <reportExpression>URLEncode ([Prompt].[Quarter - Category Code])</reportExpression></dataSource> 
        </HTMLItem><HTMLItem description="CheckboxEnd"> 
                                                                                    <dataSource> 
                                                                                        <staticValue>')); 
"&gt; 
</staticValue> 
                                                                                    </dataSource> 
                                                                                </HTMLItem><textItem><dataSource><memberCaption/></dataSource></textItem></contents><propertyList><propertyItem refDataItem="Quarter - Category Code"/></propertyList></crosstabNodeMember></crosstabNodeMembers></crosstabNode></crosstabRows></crosstab><HTMLItem description="/div"> 
                                                                <dataSource> 
                                                                    <staticValue>&lt;/div&gt;</staticValue> 
                                                                </dataSource> 
                                                            </HTMLItem><HTMLItem description="doAll"> 
                                                        <dataSource> 
                                                            <staticValue> &lt;input type="button" value="Select All" class="selectbutton" onmouseover = "this.style.cursor='hand'" onclick="checkAll('list3');"&gt; 
&lt;input type="button" value="Clear All" class="selectbutton" onmouseover = "this.style.cursor='hand'" onclick="unCheckAll('list3');"&gt;</staticValue> 
                                                        </dataSource> 
                                                    </HTMLItem></contents><style><CSS value="vertical-align:top"/></style></tableCell></tableCells></tableRow></tableRows></table><block> 
                                <contents/> 
                            </block> 
                        <combinationChart maxHotspots="10000" name="Combination Chart1" refQuery="Report" showTooltips="true"> 
                                <legend> 
                                    <legendPosition> 
                                        <relativePosition/> 
                                    </legendPosition> 
                                    <legendTitle refQuery="Report"> 
                                        <style> 
                                            <defaultStyles> 
                                                <defaultStyle refStyle="lx"/> 
                                            </defaultStyles> 
                                        </style> 
                                    </legendTitle> 
                                    <style> 
                                        <defaultStyles> 
                                            <defaultStyle refStyle="lg"/> 
                                        </defaultStyles> 
                                    </style> 
                                </legend> 
                                <ordinalAxis> 
                                    <axisTitle refQuery="Report"> 
                                        <style> 
                                            <defaultStyles> 
                                                <defaultStyle refStyle="at"/> 
                                            </defaultStyles> 
                                        </style> 
                                    </axisTitle> 
                                    <axisLine color="black"/> 
                                    <style> 
                                        <defaultStyles> 
                                            <defaultStyle refStyle="al"/> 
                                        </defaultStyles> 
                                    </style> 
                                </ordinalAxis> 
                                <numericalAxisY1> 
                                    <axisTitle refQuery="Report"> 
                                        <style> 
                                            <defaultStyles> 
                                                <defaultStyle refStyle="at"/> 
                                            </defaultStyles> 
                                        </style> 
                                    </axisTitle> 
                                    <gridlines color="#cccccc"/> 
                                    <axisLine color="black"/> 
                                    <style> 
                                        <defaultStyles> 
                                            <defaultStyle refStyle="al"/> 
                                        </defaultStyles> 
                                    </style> 
                                </numericalAxisY1> 
                                <combinationChartTypes> 
                                    <bar><chartNodes><chartNode><chartNodeMembers><chartNodeMember refDataItem="Revenue"><chartContents><chartTextItem><dataSource><memberCaption/></dataSource></chartTextItem></chartContents></chartNodeMember></chartNodeMembers></chartNode></chartNodes></bar> 
                                </combinationChartTypes> 
                                <style> 
                                    <defaultStyles> 
                                        <defaultStyle refStyle="ch"/> 
                                    </defaultStyles> 
                                </style> 
                                <commonClusters><chartNodes><chartNode><chartNodeMembers><chartNodeMember refDataItem="Product type"><chartContents><chartTextItem><dataSource><memberCaption/></dataSource></chartTextItem></chartContents></chartNodeMember></chartNodeMembers></chartNode></chartNodes></commonClusters><conditionalRender refVariable="renderGraph"><renderFor refVariableValue="1"/></conditionalRender></combinationChart> 
                        </contents> 
                    <style><defaultStyles><defaultStyle refStyle="pb"/></defaultStyles></style></pageBody> 
                <style><defaultStyles><defaultStyle refStyle="pg"/></defaultStyles></style></page> 
            <page name="Page2"> 
                    <pageBody> 
                        <contents><HTMLItem description="Styles"> 
                                <dataSource> 
                                    <staticValue>&lt;style type="text/css"&gt; 
  
input.updatebutton 
{ 
   font-size:11px; 
   font-weight:bold; 
   width:140px; 
   height:27px; 
   color:#000000; 
   background-color:#cdc9c9; 
   border-style:solid; 
   border-color:#003377; 
   border-width:3px; 
} 
  
  
  
input.matchbutton 
{ 
   font-size:11px; 
   font-weight:bold; 
   width:140px; 
   height:27px; 
   color:#EEFFFF; 
   background-color:#0088DD; 
   border-style:solid; 
   border-color:#003377; 
   border-width:3px; 
} 
  
input.selectbutton 
{ 
   font-size:9px; 
   font-weight:bold; 
   width:60px; 
   height:20px; 
   color:#000000; 
   background-color:#FFFFFF; 
   border-style:solid; 
   border-color:#FFFFFF; 
   border-width:3px; 
} 
  
&lt;/style&gt; 
  
&lt;script language="javascript"&gt; 
  
function goLite(FRM,BTN) 
{ 
   window.document.forms[FRM].elements[BTN].style.color = "#FFFF99"; 
   window.document.forms[FRM].elements[BTN].style.backgroundColor = "#11AAEE"; 
} 
  
function goDim(FRM,BTN) 
{ 
   window.document.forms[FRM].elements[BTN].style.color = "#EEFFFF"; 
   window.document.forms[FRM].elements[BTN].style.backgroundColor = "#0088DD"; 
} 
  
&lt;/script&gt; 
</staticValue> 
                                </dataSource> 
                            </HTMLItem> 
                            <HTMLItem description="Scripts"> 
                                <dataSource> 
                                    <staticValue>&lt;script&gt; 
function selectInCheckbox(cbGroup,id) 
{ 
   var inputs= document.getElementById(cbGroup).getElementsByTagName('input'); 
   for (var i=0;i&lt;inputs.length;i++) 
   { 
        if (inputs[i].value == id)  
        { 
            inputs[i].click(); 
        } 
   } 
} 
  
function selectInCheckboxRow(cbGroup,id) 
{ 
    var inputs= document.getElementById(cbGroup).getElementsByTagName('input'); 
    inputs[id].click(); 
} 

function checkAll(list){ 
var inputs=document.getElementById(list).getElementsByTagName('input') 
for (var i=0;i&lt;inputs.length;i++){ 
        if (inputs[i].type == 'checkbox') { 
            if (inputs[i].checked == true)  
        {} 
        else {inputs[i].click();} 
        } 
} 
}  
  
function unCheckAll(list){ 
var inputs=document.getElementById(list).getElementsByTagName('input') 
for (var i=0;i&lt;inputs.length;i++){ 
        if (inputs[i].type == 'checkbox') { 
            if (inputs[i].checked == true)  
        {inputs[i].click();} 
        else {} 
        } 
} 
}  
&lt;/script&gt; 
  
</staticValue> 
                                </dataSource> 
                            </HTMLItem> 
                              
                              
                            <promptButton type="reprompt"> 
            <contents/> 
            <style> 
                <defaultStyles> 
                    <defaultStyle refStyle="bp"/> 
                </defaultStyles> 
            </style> 
        </promptButton><table><style><defaultStyles><defaultStyle refStyle="tb"/></defaultStyles><CSS value="border-collapse:collapse"/></style><tableRows><tableRow><tableCells><tableCell><contents><HTMLItem description="div"> 
            <dataSource> 
                <staticValue>&lt;div id="checkbox1" &gt;</staticValue> 
            </dataSource> 
        </HTMLItem><selectValue multiSelect="true" parameter="code" range="false" refQuery="Prompt" required="false" selectValueUI="checkboxGroup"><useItem refDataItem="Product line code"/><sortList><sortItem refDataItem="Product line code"/></sortList></selectValue><HTMLItem description="/div"> 
            <dataSource> 
                <staticValue>&lt;/div&gt;</staticValue> 
            </dataSource> 
        </HTMLItem><HTMLItem description="div"> 
            <dataSource> 
                <staticValue>&lt;div id="checkbox2" &gt;</staticValue> 
            </dataSource> 
        </HTMLItem><selectValue multiSelect="true" parameter="Year" refQuery="Quarters" required="false" selectValueUI="checkboxGroup"><useItem refDataItem="Quarter - Category Code"><displayItem refDataItem="Quarter"/></useItem></selectValue><HTMLItem description="/div"> 
            <dataSource> 
                <staticValue>&lt;/div&gt;</staticValue> 
            </dataSource> 
        </HTMLItem></contents><style><CSS value="vertical-align:top"/></style></tableCell><tableCell><contents/><style><CSS value="vertical-align:top"/></style></tableCell></tableCells></tableRow></tableRows></table><block> 
                                <contents/> 
                            </block> 
                        <combinationChart maxHotspots="10000" name="Combination Chart2" refQuery="Report" showTooltips="true"> 
                                <legend> 
                                    <legendPosition> 
                                        <relativePosition/> 
                                    </legendPosition> 
                                    <legendTitle refQuery="Report"> 
                                        <style> 
                                            <defaultStyles> 
                                                <defaultStyle refStyle="lx"/> 
                                            </defaultStyles> 
                                        </style> 
                                    </legendTitle> 
                                    <style> 
                                        <defaultStyles> 
                                            <defaultStyle refStyle="lg"/> 
                                        </defaultStyles> 
                                    </style> 
                                </legend> 
                                <ordinalAxis> 
                                    <axisTitle refQuery="Report"> 
                                        <style> 
                                            <defaultStyles> 
                                                <defaultStyle refStyle="at"/> 
                                            </defaultStyles> 
                                        </style> 
                                    </axisTitle> 
                                    <axisLine color="black"/> 
                                    <style> 
                                        <defaultStyles> 
                                            <defaultStyle refStyle="al"/> 
                                        </defaultStyles> 
                                    </style> 
                                </ordinalAxis> 
                                <numericalAxisY1> 
                                    <axisTitle refQuery="Report"> 
                                        <style> 
                                            <defaultStyles> 
                                                <defaultStyle refStyle="at"/> 
                                            </defaultStyles> 
                                        </style> 
                                    </axisTitle> 
                                    <gridlines color="#cccccc"/> 
                                    <axisLine color="black"/> 
                                    <style> 
                                        <defaultStyles> 
                                            <defaultStyle refStyle="al"/> 
                                        </defaultStyles> 
                                    </style> 
                                </numericalAxisY1> 
                                <combinationChartTypes> 
                                    <bar><chartNodes><chartNode><chartNodeMembers><chartNodeMember refDataItem="Revenue"><chartContents><chartTextItem><dataSource><memberCaption/></dataSource></chartTextItem></chartContents></chartNodeMember></chartNodeMembers></chartNode></chartNodes></bar> 
                                </combinationChartTypes> 
                                <style> 
                                    <defaultStyles> 
                                        <defaultStyle refStyle="ch"/> 
                                    </defaultStyles> 
                                </style> 
                                <commonClusters><chartNodes><chartNode><chartNodeMembers><chartNodeMember refDataItem="Product type"><chartContents><chartTextItem><dataSource><memberCaption/></dataSource></chartTextItem></chartContents></chartNodeMember></chartNodeMembers></chartNode></chartNodes></commonClusters><conditionalRender refVariable="renderGraph"><renderFor refVariableValue="1"/></conditionalRender></combinationChart> 
                        </contents> 
                    <style><defaultStyles><defaultStyle refStyle="pb"/></defaultStyles></style></pageBody> 
                <style><defaultStyles><defaultStyle refStyle="pg"/></defaultStyles></style></page></reportPages> 
        </layout> 
    </layouts> 
<queries> 
      
      
      
          
    <query name="Prompt"> 
            <source> 
                <model/> 
            </source> 
            <selection><dataItem aggregate="none" name="Product line code" rollupAggregate="none"><expression>[sales_and_marketing].[Products].[Products].[Product line].[Product line - Category Code]</expression></dataItem><dataItem aggregate="none" name="Product line" rollupAggregate="none"><expression>[sales_and_marketing].[Products].[Products].[Product line]</expression></dataItem><dataItem aggregate="total" name="Quantity"><expression>[sales_and_marketing].[Measures].[Quantity]</expression></dataItem><dataItem aggregate="total" name="Revenue"><expression>[sales_and_marketing].[Measures].[Revenue]</expression></dataItem><dataItem aggregate="total" name="Gross profit"><expression>[sales_and_marketing].[Measures].[Gross profit]</expression></dataItem><dataItem aggregate="none" name="Year - Category Code"><expression>[sales_and_marketing].[Time].[Time].[Year].[Year - Category Code]</expression></dataItem><dataItem aggregate="none" name="Year" rollupAggregate="none" sort="ascending"><expression>[sales_and_marketing].[Time].[Time].[Year]</expression></dataItem><dataItem aggregate="none" name="Quarter" rollupAggregate="none"><expression>[sales_and_marketing].[Time].[Time].[Quarter]</expression></dataItem><dataItem aggregate="none" name="Quarter - Category Code" rollupAggregate="none"><expression>[sales_and_marketing].[Time].[Time].[Quarter].[Quarter - Category Code]</expression></dataItem><dataItem name="Time" aggregate="none" rollupAggregate="none"><expression>[sales_and_marketing].[Time].[Time].[Time]-&gt;:[PC].[@MEMBER].[Time]</expression></dataItem></selection> 
        </query><query name="Report"><source><model/></source><selection><dataItem aggregate="total" name="Revenue"><expression>[sales_and_marketing].[Measures].[Revenue]</expression></dataItem><dataItem aggregate="none" name="Product type" rollupAggregate="none"><expression>[sales_and_marketing].[Products].[Products].[Product type]</expression></dataItem></selection><detailFilters><detailFilter><filterExpression>[sales_and_marketing].[Products].[Products].[Product line].[Product line - Category Code] in (?code?)</filterExpression></detailFilter><detailFilter use="optional"><filterExpression>[sales_and_marketing].[Time].[Time].[Quarter].[Quarter - Category Code] in (?Quarter?)</filterExpression></detailFilter></detailFilters></query><query name="Quarters"><source><model/></source><selection><dataItem aggregate="none" name="Quarter - Category Code"><expression>[sales_and_marketing].[Time].[Time].[Quarter].[Quarter - Category Code]</expression></dataItem><dataItem aggregate="none" name="Quarter" sort="ascending"><expression>[sales_and_marketing].[Time].[Time].[Quarter]</expression></dataItem></selection></query></queries><XMLAttributes><XMLAttribute name="RS_CreateExtendedDataItems" output="no" value="false"/><XMLAttribute name="listSeparator" output="no" value=","/><XMLAttribute name="RS_modelModificationTime" output="no" value="2008-07-25T15:28:38.133Z"/></XMLAttributes><reportVariables><reportVariable name="renderGraph" type="boolean"> 
            <reportExpression>ParamValue('code') is not null</reportExpression> 
            <variableValues> 
                <variableValue value="1"/> 
            </variableValues> 
        </reportVariable></reportVariables><reportName>checkbox 2</reportName></report>

Viewing all 135 articles
Browse latest View live