Linking multiple custom variables in Omniture - tags

I have an implementation in Sitecatalyst, where i have to track categories and the multiple tags associated with the categories. How should i go for it. What should be the variables which should be defined for it in omniture.
for example -
|---------------------|
| MOOD | // Main Category
|---------------------|
| Uplifting | // Sub Category
|---------------------|
| Fun | // Sub Category
|---------------------|
| Proud | // Sub Category
|---------------------|
| Fun | // Sub Category

There are three options:
Listprop
You could create a listprop which you can enable in the report suite settings by implementing a delimiter for the traffic variable. This is especially handy if you have the possibility to create multiple levels. You can then implement the traffic variable like so:
s.prop1 = "MOOD|Uplifting|Fun|Proud|Fun";
Adobe Analytics will automatically split the values based on the pipe character. Please note that listprops don't allow correlations and pathing.
Multiple traffic variables/props
The other option would be to create multiple traffic variables and define all of them on every page where they're required.
s.prop1 = "MOOD";
s.prop2 = "Uplifting";
s.prop3 = "Fun";
s.prop4 = "Proud";
s.prop5 = "Fun";
However, this option will consume a lot of traffic variables of which you only have 75.
Classification
The third option would look the same as the listprop, however, you don't configure the traffic variable as a listprop, you configure it as a normal traffic variable and classify it later on using the Classification Rule Builder.
Using the classification rule builder you can split the incoming data by the pipe character (using regular expression) and create new dimensions resembling the categories.
s.prop1 = "MOOD|Uplifting|Fun|Proud|Fun";
I would personally go for the third option as it doesn't require a lot of props and it allows for a future proof approach of measuring the categories even when you're adding more levels.
Good luck with your implementation!

Related

Aggregating Wildcards in Sumologic

I'm trying to aggregate the API logs based on the different endpoints I have. There are a total of 4 endpoints:
1: /v1/vehicle_locations
2: /v1/vehicle_locations/id
3: /v1/driver_locations
4: /v1/driver_locations/id
The way I'm currently doing this is:
_sourceCategory=production | keyvalue auto | where (path matches "/v1/driver_locations" OR path matches "/v1/driver_locations/*" or path matches "/v1/vehicle_locations" or path matches "/v1/vehicle_locations/*") | count by path
The problem with this is that while I get the correct aggregate for /v1/vehicle_locations and /v1/driver_locations, I get individual results for /v1/driver_locations/id and /v1/vehicle_locations/id since the id is a wildcard. Is there a way I can aggregate these wildcards as well?
There are several ways to achieve what you ask. I think the most straightforward one and suggested is to use | parse operator so that you can treat the top-most element of your path as a field, e.g.
_sourceCategory=production
| keyvalue auto
| parse field=path "*/*" as topmost, rest
| where (topmost = "vehicle_locations" or topmost = "driver_locations")
| count by topmost
Note that by default | parse operator works on the raw message (e.g. the original log line), but you can make it parse a field - using the field= syntax and this is what it's used above.
You might want to tweak the parse expression or use a regex depending on the actual paths you encounter.
(Disclaimer: I am currently employed by Sumo Logic)

Does Get-NetIPConfiguration return interfaces in binding order?

I noticed that
(Get-NetIPConfiguration).InterfaceIndex
always seems to return the index's in interface binding order for me. is this the way its suppose to function, always returning in interface binding order or it is just a fluke that it always returns in interface binding order for me in this case?
You could try
(Get-NetIPConfiguration).InterfaceIndex | Sort [int]
ok, got this figured out. Starting with windows 10 the preferred IP Address enabled (either IPv4 or IPv6) interface is the one with the lowest sum of the IPv4 (or IPv4) route metric and the interface metric (route metric + if metric). This may not be the one with the default route 0.0.0.0/0 depending on if you have multiple interfaces set up or not with multiple default routes. That interface will bind to the one with the next lowest lowest sum on the same route ...and so forth and so on. This also, it turns out, may not be the order of the interface GUID's in the registry value at 'HKLM:\SYSTEM\Currentcontrolset\Services\TCPIP\Linkage\bind\
But...how they appear in a list, including other methods, is determined just by the interface metric. So in Windows 10 there is (i'm gonna call it) 'route binding order' and the list order. Although this may seem to match up sometimes because most people don't have multiple interfaces in their systems it becomes important if you are going to start playing around with setting interface and route metric to ensure the interface you want to be used is the one being used for a particular route. So you want the actual binding order and not the list order.
so, in windows 10, to get correct route binding order (vs list order) you have to examine the route table and do the 'math' for sum of route metric + interface metric to get actual binding order, and use that same 'sum' methodolgy to set up interfaces if you are going to do it yourself.
Below is an example of this method usage that i threw together quickly. I have one Windows 10 machine with two hardware interfaces, one for hard line connection and the other wifi. I also have OpenVPN with a TAP adapter installed on this system, so i need to know which hardware interface that OpenVPN was binding to through the TAP adapter. The TAP adapter is a virtual (software) interface. When the TAP is installed/connected it uses a interface metric less than 10 because windows minimum automatic interface metric is always no lower than 10 (although you can manually set it lower) , and the tap uses a route metric of 0. So the tap is going to be the lowest 'sum' Ip enabled interface in the system. So all this info and using the below code I got the hardware interface the Open/VPN/Tap is binding to (code thrown together quickly, will refine later when I have the time)..
$route = (Get-NetRoute); $rtmetric = $route.RouteMetric; $ifmetric = $route.InterfaceMetric; $index = $route.ifIndex;
$sumarray = #(); $indexarray = #(); For ($i=0; $i -lt $rtmetric.Length; $i++)
{
$sum = $rtmetric[$i] + $ifmetric[$i]
$sumarray += $sum
$indexarray += $index[$i]
}
$sumsort = $sumarray | sort -unique; [int]$sumlowest = ($sumsort | measure -Minimum).Minimum;
$pos = [Array]::indexof($sumsort,$sumlowest) + 1; $sumget = $sumsort[$pos]; $posA = [Array]::indexof($sumarray,$sumget); $ifindexbind = $indexarray[$posA];
(Get-NetAdapter | ? ifIndex -eq $ifindexbind)
so, that's the long way around it to get the route binding order vs the list order. If you do this:
(Get-NetAdapter).InstanceID
you will get the binding in list order as they are in the registry key starting from the bottom and working your way up. But.... if you do this
(Get-NetIPConfiguration).NetAdapter.InstanceID
you will notice that as interfaces are disabled or enable the order given will also change, and that's because '(Get-NetIPConfiguration).NetAdapter.InstanceID' is giving the route binding order and not the registry list order. Disabling an interface removes it from the route table but just disabling an interface does not remove its binding to another interface but the priority changes so the previously bound interface now becomes the preferred interface in the route so moves to the top. When that disabled interface with the binding to the enabled interface, is enabled again it takes it place in the route binding on top. The one on top will be the preferred adapter (the one with the lowest 'sum' value), the one under that will be the 'next prefered' (the one with the next lowest 'sum' value) and if on the same route is the interface bound to one above it, thus binding order. So using (Get-NetIPConfiguration).NetAdapter.InstanceID the needed route binding order for enabled and connected interfaces can be had without resorting to reading the registry.

Graph representation - display individuals by data property and group by type

I currently use OntoGraf 1.0.3 (via "Class views"/"OntoGraf") to display a small ontology created in Protege 5 beta-17 as a graph; not out of choice but because it is the first tool I found.
My chosen display mode is "Horizontal Directed". Unfortunately, within a layer the order of items appears to be random; it would help clarity if they could be grouped by their type.
Is this possible and how?
Furthermore, nodes in the graph are displayed by their URI. All individuals have a data property "Name" however, and I would like those to be labelled with that property instead of their URI.
Is this possible and how?
Bonus question:
When displaying the whole ontology, layers of the tree are strictly arranged based on relation jumps; I would like to push individuals below the deepest class layer.
To elaborate, this is how it looks like:
C
|\
C I <- same layer, no correlation
/| |
I C I <- same layer, no correlation
This is how I would like it:
C
|\
C \
/| |
| C |
I I <- same layer, same level of abstraction
|
I
If there is a better solution to produce a graphical tree with such characteristics, I will gladly accept that instead.

Determine size of Stateflow Subchart

I am writing a Model Advisor check right now and I need to know the size of a subcharted Stateflow State or Box. But the "Stateflow.State" and "Stateflow.Box" objects only have a "Position" attribute, which gives their position inside their parent elements. I need to know the size of the subchart itself (where their contents reside). How can I get this size?
The "Position" attribute is the absolute position of "Stateflow.State" inside the Chart.Here is an example:
___________________
|AA |
|___________ |
||BB | |
||_________| |
-------------------
AA = r.find('-isa', 'Stateflow.State', 'Name', 'AA').Position
AA = 330.0924 542.7458 157.4576 94.6164
BB = r.find('-isa', 'Stateflow.State', 'Name', 'BB').Position
BB = 334.5304 571.1490 115.7404 62.6628
I finally asked the MathWorks support for a solution and got this answer:
[...] there is currently no API functionality to retrieve the size of the subchart in the subchart subviewer. Unfortunately there are no workarounds to access this information currently.
Update: I recently learned about the undocumented sf API. It is possible to get information about the subchart with it. Therefore you need to get the ID of the State whos dimensions are needed. Here is an example:
r = sfroot;
s = r.find('-isa', 'Stateflow.State', '-and', 'IsSubchart', 1);
sf('get', s(1).id, '.subviewS.pos')
This does the following:
Store the Simulink.Root object in r.
Find all subcharted States and store them in s. You might need to refine the search to detect the exact State you need.
Use the sf API to retrieve the position .pos of the first Subchart, which is represented by .subviewS
There is plenty of information about each of the Stateflow objects. To investigate further, you just need to find the appropriate object (using r.find()) and use sf('get', <object>.id). This lists all available information about the Stateflow object <object>.

Extract portions of Google Docs form data and write it on separate lines

Let's say I have a Google Docs Form that gathers the following info:
Timestamp (default field)
Names
Ref#
The form data then appears on the spreadsheet as follows:
4/10/2013 16:20:31 | Jack, Jill, Oscar | Ref6656X
(Note: the number of names may be anywhere from 1 to many)
I need the data to appear on the spreadsheet as follows:
4/10/2013 16:20:31 | Jack | Ref6656X
4/10/2013 16:20:31 | Jill | Ref6656X
4/10/2013 16:20:31 | Oscar | Ref6656X
I can often decipher and edit Google Apps Script (JavaScript?), but I don't know how to think in that language in order to create it for myself (especially with an unknown number of names in the Name field). How can I get started on solving this?
First of all, you've got some choices to make before you start writing your code.
Do you want to modify the spreadsheet that's accepting form input, or produce a separate sheet that has the modified data? If you want to have a record of what was actually input by a user, you'd best leave the original data alone. If you're using a second sheet for the massaged output, the presence of multiple tabs might be confusing to your users, unless you take steps to hide it.
Do you want to do the modifications as forms come in, or (in bulk) at some point afterwards? If you already have collected data, you'll have to have the bulk processing, and that will involve looping and having to handle insertions of new rows in the middle of things. To handle forms as they come in, you'll need to set up a function that is triggered by form submissions, and only extend the table further down... but you've got more learning to do - see Container-Specific Triggers, Understanding Triggers and Understanding Events for background info.
Will you primarily use Spreadsheet service functions, or javascript Arrays? This choice is often about speed - the more you can do in javascript, the faster your script will be, but switching between the two can be confusing at first.
Here's an example function to do bulk processing. It reads all existing data into an array, goes through that and copies all rows into a new array, expanding multiple names into multiple rows. When done, the existing sheet data is overwritten. (Note - not debugged or tested.)
function bulkProcess() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dataIn = ss.getDataRange().getValues();
var dataOut = [];
for (var row in dataIn) { // Could use: for (var row = 0; row < dataIn.length; row++)
var names = dataIn[row][1].split(','); // array of names in second column
var rowOut = dataIn[row];
for (var i in names) {
rowOut[1] = names[i]; // overwrite with single name
dataOut.push(rowOut); // then copy to dataOut array
}
}
// Write the updated array back to spreadsheet, overwriting existing values.
ss.getRange(1,1,dataOut.length,dataOut[0].length).setValues(dataOut);
}