Tag: Interviews

JavaScript Extensions for Oracle Policy Modeling

JavaScript Extensions for Oracle Policy Modeling

It’s almost ready. The perfect Christmas gift (yeah, right, in bizarro-world) or New Year workout kit. The new book is due out in a few weeks, and you have the chance to win a free copy ahead of everyone else by entering our prize Survey (30 seconds) right now.

The book comes with 50 examples. You get them as Zip Files as well when you buy the book. The book covers all the different types of JavaScript Extensions that are currently available, with examples of each of them (sometimes many different examples) using easily-understandable business scenarios as the starting point, and using example projects from Oracle Policy Modeling – so you don’t need to install a Hub, or do anything special – which let’s you get started straight away.

  • Label Extensions
  • Input Extensions
  • Search Extensions
  • Options Extensions
  • Entity Collect Extensions
  • Entity Container Extensions
  • Button Extensions
  • Event Extensions
  • Navigation, Header and Footer Extensions

The OPA Hub Website Community has also stepped up and I am delighted to say that 8 examples (with credits) came from readers of this website. I am very grateful to them and encourage all of you to submit your ideas and code snippets for the next version.

Hopefully this book will appeal to non-technical people too – I wrote it in the same style as the others (Getting Started with OPA, Getting Started with OSvC) and tried to make it as accessible as possible to everyone.

Here, in avant-premiere, is the cover. And no, I’m not sure what those things are either. But they sure look exotic and tasty. I wanted a parsnip on the cover but these were available and they look good. These are important questions that you worry about late at night. The publisher’s website has been updated, watch this space for the launch date!

 

JavaScript Extensions

Back to Basics : Seeding from a URL Parameter

Back to Basics : Seeding from a URL Parameter

This topic comes up regularly and it often seems to get mixed up with just plain old “starting the interview from a URL”. So it’s time for a little refresher about Seeding from a URL Parameter. Time for another Back to Basics topic (catch the previous one here) !

First of all : What do we mean by seeding from a URL parameter?

Sometimes you want to start an Interview with certain attributes already populated. But this is not a situation where you are using a Connection, for example, to perform an inbound mapping loaded at start. Perhaps you are embedding Oracle Policy Automation Interviews on a Web site, and the Web site is going to pass some information into the Interview when it starts.

In pseudo-world, you want to do something like this:

https://myinterview.com/startsession/Interview/?myattribute=X

It’s really quite simple and it is becoming more frequent, since lots of Oracle Policy Automation is appearing in modern interfaces driven by JavaScript and other frameworks that support using JavaScript.

But if you try to do something like this with Oracle Policy Automation, you get a nasty surprise. It doesn’t work at all.

Then you read the documentation, and discover two or three important things that must be in place.

  1. You must authorize pre-seeding for the attribute(s) you are interested in

Seeding from a URL Parameter 1

2. You must use the seedData= tag on your URL to introduce the information to the Interview.

Armed with this you come back to your Interview and you try something like this, with impressive results:

Seeding from a URL Parameter 2

What the heck is happening here? It all seemed so simple. Well it is, but you forgot the most important point. Whatever your seeding from a URL requirements, they must be URL encoded. So the “=” character for example, is not going to get through the defences of Oracle Policy Automation. You have to encode it all first. So let’s imagine you have an attribute, whose name is my_seeded_value, and you want to populate that attribute with Richard Napier.

You need to encode part of what you are sending. You do NOT need to encode “seedData=” in fact if you do, there will be yet another error. Your URL needs to look like this :

http://xxx.com/web-determinations/startsession/URL_Seeding?seedData=

And the rest of the URL needs to be something like my_seeded_value=Richard Napier. But that part needs to be encoded. As a simple example, take it to https://www.urlencoder.org/ and put it through the encoder. It probably comes out like my_seeded_value%3DRichard%20Napier. Excellent. Now you can create the complete URL:

http://xxx.com/web-determinations/startsession/URL_Seeding?seedData=my_seeded_value%3DRichard%20Napier

And it comes out just fine:

Seeding from a URL Parameter 3

So there has definitely been an important lesson here : don’t encode seedData=, but do encode the information after it.

There is a lot more to learn about URL-based seeding, and we will continue this after the break. If you want the full online help, it is to be found here.

Have a good Holiday and see you in 2019!

What is Happening Here – Date Function with Wrong Date

What is Happening Here – Date Function with Wrong Date

See if you can guess : What is Happening Here?

Below is a project written in Oracle Policy Automation 12 (this was actually in 12.18B but it has no bearing on the example). It has only one attribute : the date of the next visit. This is written as follows:

The date of the next visit= YearEnd (AddYears(the current date;1))

The date you are running the Debugger, the current date is November 19, 2018. The rule should perform a simple assignment, taking the current date, adding a year and then using that as the input for the YearEnd function. So :

YearEnd(November 19, 2019)

This should give the value of December 31 2019. Also, there are no other attributes in this project. There are no JavaScript extensions, no custom controls, no CSS or other additions. The project is being built using English language. The project does not have any translations, forms, or anything else inside it. But the Debugger  session of the Oracle Policy Automation Interview displays the following:

OPA 12 - What is Happening Here

The date is incorrectly showing 12/31/20. So what is happening here? Even more fun, the Data tab of the Debugger shows the following:

OPA 12 - What is Happening Here

The value is correct on the right, wrong on the left. So what has happened to the Oracle Policy Automation project in this example?

You are free to give the answer, if you know it, in the comments. I will come back in a couple of days and explain. And before you ask, yes, I can across this in the real world yesterday and it is not a bug, it did not require a Service Request, and somebody had done something. The behavior is entirely reproducible I would imagine in any language.

Sometimes you want to write about something (in my case, I wanted to look at Silent and Hidden settings) but life gets in the way. This was such an amusing thing (with hindsight) that I decided to write about it instead.

Enjoy this and hopefully you will immediately have spotted the possible culprit. You can peruse the documentation online here.

Temporal Reasoning #5 : Temporal Attributes in Interviews

Temporal Reasoning #5 : Temporal Attributes in Interviews

In the final part of this mini-series, the OPA Hub Website continues to look at Temporal Reasoning and in this particular chapter discusses the display of Temporal Attributes data in the Interview experience.

If you missed any of the previous parts of the series, they are here:

So now that the we have a bit of understanding of how these data elements work, what about displaying them in a good way to the end user in the Interview. Well, part of the answer is hidden in part four of this series. We cannot actually display temporal attributes for data entry in an Interview (so conversion comes in very handy).

Let’s be more specific. Using the project from the previous chapter, in 18C, when an attempt is made to display the temporal information on a Screen, various things happen that underline the some important concepts:

Temporal Attributes in Interviews Animation OPA 12Please excuse the retro-style animated GIF above. But the demonstration above illustrates the fact that Temporal attributes and their change-points are complex data types that cannot be handled in a “normal” way. The one exception to the above is if you have a Temporal attribute whose values are the Goal of the interview, then an Explanation will display the data in a coherent way:

OPA 12 - Viewing Temporal Attributes in Interviews

If your project is using RuleScript and your data is pre-seeded, then potentially you could access it by deriving a string value which is a concatenation of the different values and displaying that attribute using a label control.

// RuleScript(myString) <- (temporalBankBalance)
function FindHighest(global) {
	console.log("Starting RuleScript");
	var v = global.temporalBankBalance;

		console.log("Base Value of v " + v._baseValue);
		var idx,
		maxVal = null;
		var myString = "";
		console.log("Length of Temporal Array " + v._changeValues.length);

	if (v._changeValues.length <= 0) {
		global.myString = "No Temporal Values";
	} else {
		console.log("Getting Temporal Values");
		for (idx = 0; idx < v._changeValues.length; idx++) { var changeValue = v._changeValues.valueAt(idx); if (changeValue != null && (maxVal == null || changeValue > maxVal))
				maxVal = changeValue;
		}
		global.myString = global.myString + changeValue + ";";
	}

}

But given that RuleScript is experimental, that it’s use cases are highly controlled this would be a very bad idea. Plus it would only work if the temporal values were pre-seeded into the Interview, which renders it all very complex.

So what is plan B? It might be to use something like the Entity Container Extension that we have previously looked at (which would imply using the conversion technique mentioned in part four).

If you are looking for a quick and dirty way to get at the Temporal values, even though the JavaScript Extensions do not actually support them today, the values are still accessible. They can be accessed using something like this. I have not published this as a download since the snippet below is very primitive.

 

/**
 * Richard Napier The OPA Hub Website August 2018
 * Educational Example of Custom Container with a Timeline inside
 * I will remember this is for demonstration and educational purposes only
 */
OraclePolicyAutomation.AddExtension({
	customLabel: function (control, interview) {
		if (control.getProperty("name") === "xTimeline") {

			return {
				mount: function (el) {
					var script_tag_addition = document.createElement('script');
					script_tag_addition.setAttribute('src', '${resources-root}/js/timeline.min.js');
					script_tag_addition.setAttribute('type', 'text/javascript');
					document.getElementsByTagName('head')[0].appendChild(script_tag_addition);
					var stylesheet_tag_addition = document.createElement('link');
					stylesheet_tag_addition.setAttribute('href', '${resources-root}/css/timeline.min.css');
					stylesheet_tag_addition.setAttribute('rel', 'stylesheet');
					stylesheet_tag_addition.setAttribute('type', 'text/css');
					document.getElementsByTagName('head')[0].appendChild(stylesheet_tag_addition);

					var myDiv = document.createElement("div");
					myDiv.setAttribute("class", "timeline");
										myDiv.setAttribute("data-mode", "horizontal");
					el.appendChild(myDiv);
					
					
					var myDivWrap = document.createElement("div");
					myDivWrap.setAttribute("class", "timeline__wrap");
					$(".timeline").append(myDivWrap);

					var myDivChild = document.createElement("div");
					myDivChild.setAttribute("class", "timeline__items");
					$(".timeline__wrap").append(myDivChild);
					
					// Don't do this, it relies upon the temporal attribute
					// being the only one in Global exposed on the page as a %label%
					var myTemporal = []
					myTemporal = control._source.screen.config.data[0].instances[0].attributes[0].value.changePoints
						for (var i in myTemporal) {
							var iterateDIV = document.createElement("div");
							iterateDIV.setAttribute("class", "timeline__item");
							iterateDIV.setAttribute("id", i);
							$(".timeline__items").append(iterateDIV)
							var iterateDIVContent = document.createElement("div");
							iterateDIVContent.setAttribute("class", "timeline__content");
							$('.timeline__item[id="' + i + '"]').append( "GBP "  + myTemporal[i].value + " on " + myTemporal[i].date)
						}
				},
				update: function (el) {},
				unmount: function (el) {
					var myDiv = $(".timeline");
					myDiv.remove();

				}

			}
		}
	}
});

The above snippet relies upon a jQuery plugin to display the data. This gives something like this, a visual timeline on the left of this page:

Temporal Attributes in Interviews JavaScript Extension

Of course there are hundreds of Timeline plugins, each more sophisticated than the other, on the Internet.

We hope that this series has brought to light some of the key features of temporal reasoning, and thanks to Orlando who suggested this series in the first place. Have a good day and see you soon!

 

JavaScript Extensions with a Live Entity-based Chart in Oracle Policy Modelling

JavaScript Extensions with a Live Entity-based Chart in Oracle Policy Modelling

[NB : An updated post has been written in February 2019]

One of the most interesting questions I have been asked during my current assignment in beautiful Madrid has been the following :

“How can I make a Chart”

Well, that’s easy I said : pick your Charting platform (for example, you might choose D3 as the charting library as it is well-known and incredibly powerful. Or alternatively you could manipulate SVG arcs and lines yourself if you want to, to achieve the same thing.

“How can I make a Chart based on Oracle Policy Automation data”

Well, that’s easy I said : you even have an example in the Oracle Policy Automation Example Projects, called the Loan Advisor. You can see a screenshot from that project, right here:

JavaScript Extensions with a Live Entity-based Chart : Intro

Digging deeper into that Project, we discover that the attributes that are used to create the chart are global :

JavaScript Extensions with a Live Entity-based Chart : Intro 2

“How can I make a Chart that uses Entity data”

Well that’s easy I said, you could hook up the D3 library to the entity, and use a similar system to our custom Entity Container example to retrieve the data. After all, the Pie Chart in D3  accepts any array of data organized into labels and values. You may remember in that example, we sought the name of the entity using EntityId and then iterated through the instances in the Entity to display them.

But upon investigation this is not really satisfactory. Adding an instance to the entity container does not refresh the Chart. In fact, you have to navigate forward and then backwards to get the Chart to refresh. That’s because, of course, your new “instance” does not actually exist yet. It does not get added into the entity.instances[i] list until you leave the current screen.

“How Can I make JavaScript Extensions with a Live Entity-based Chart in Oracle Policy Modelling”

You will have guessed by now that my entourage here is pretty demanding! So here goes. Firstly, the scenario. I have created an Entity called the payment. It has two attributes, the identifier, a text attribute, and the payment amount, a currency or number as you wish.

The goal : on ONE Screen, enter data and view a live chart that updates live, without changing Screens, as data is added or removed.

To experiment further with this, I also decided to create another Entity called the shadow payment. This is a copy of the original, created by the simple rule in Word that follows:

JavaScript Extensions with a Live Entity-based Chart Intro 3

The idea was to test if it would work both on inferred and normal entity instances. It seemed to, so you could probably use the code with either. To enable my shadow entities, I set up the relationship for the above Word rules to function properly.

JavaScript Extensions with a Live Entity-based Chart in Oracle Policy Modelling Intro 5

The Code Concept

Now we come to the code itself. This is, as I always state clearly, just code that I have hacked together to see if a concept had the ability to be taken further. It is in no way production or even unit test ready. That’s your problem. But I hope you find it interesting and inspiring.

Another note, I have seen that this “code view” messes with some characters. The OPA Hub Shop has a PDF version which you can use to compare and correct anything that looks wrong, notably the > and < characters don’t show up correctly here.

The code uses D3 for the pie chart, and the explanation follows after the code. Pop D3 in a JS file in the resources folder, as well as the D3 library.

/**
 * Richard Napier The OPA Hub Website April 2018
 * Educational Example of Custom D3 Chart Extension with live refresh on a screen
 * I will remember this is for demonstration and educational purposes only
 */

OraclePolicyAutomation.AddExtension({
	customContainer: function (control) {
		if (control.getProperty("name") === "xChart") {

			return {
				mount: function (el) {
			
				},
				update: function (el) {
					
					if (document.readyState == "complete") {
						
						var entity = control._source.screen.serverState.shadowpayment;
						var myFlatList = [];
						var myObject;
						
						var width = 300, //width
						height = 300, //height
						radius = 150, //radius
						
						color = d3.scaleOrdinal(d3.schemeCategory10);
						var size = Object.keys(entity).length;
						
						for (i = 1; i < size+1; i++) {
							myObject = new Object();
							myObject.label =control._source.screen.serverState.shadowpayment["@_@opa-rel-target={payment[the payment" + i + "]}/global[global]"].shadow_payment;
							myObject.value = control._source.screen.serverState.shadowpayment["@_@opa-rel-target={payment[the payment" + i + "]}/global[global]"].shadow_amount;
							myFlatList.push(myObject);
							//console.log(" Flattened the list - item " + i);
						}
						data = myFlatList;
						var vis = d3.select(el);
						vis.select("svg").remove();
						var vis = d3.select(el)
						.append("svg")
							.data([data])
							.attr("width", width)
							.attr("height", height)
							.append("g")
							.attr('transform', 'translate(' + (width / 2) +
								',' + (height / 2) + ')'); 
						var arc = d3.arc().outerRadius(radius)
							.innerRadius(0); ;
						var pie = d3.pie()
							.value(function (d) {
								return d.value;
							});
						var arcs = vis.selectAll("g.slice")
							.data(pie)
							.enter()
							.append("svg:g")
							.attr("class", "slice");
						arcs.append("svg:path")
						.attr("fill", function (d, i) {
							return color(i);
						})
						.attr("d", arc);
						arcs.append("svg:text")
						.attr("transform", function (d) {
							d.innerRadius = 0;
							d.outerRadius = radius;
							return "translate(" + arc.centroid(d) + ")";
						})
						.attr("text-anchor", "middle")
						.text(function (d, i) {
							return data[i].label;
						});
					}
				}
			}
		}
	}
});

Review of JavaScript Extensions with a Live Entity-based Chart

Line 8 : This is a Custom Container. So make sure that you drop a container into your Screen, and in the container make sure you add your Entity. In my example, I displayed both the original the payment entity, for the user to add or delete records, as well as the shadow payment which I leveraged to draw the pie chart.

Line 19 ; This example uses control._source.screen.serverState.shadowpayment. This JavaScript object contains the instances of your entity, and is updated as new instances are added, before you leave the page. Of course the name is the technical name  of your entity so don’t forget to add that to your Data tab.

Line 27 : Selecting a standard set of colors from the D3 color categories

Line 28: Finding how many objects are inside the control._source.screen.serverState.shadowpayment object. Each instance is a child object.

Lines 32 and 33 : Creating dynamically the identifiers of each row to select the label and the value using the names of the attributes in your entity, and copying them into a flat object with values and labels

Line 37 : Set the flat list as the data source for the Pie Chart

Line 40 : Add the Chart into the Container

Line 41 : Add the pie chart, setting the origin to the center of the Container, and hooking up to the data we created

Line 50 and beyond : Using D3, draw the arcs and fills that make the Pie Chart by going through the total set of data and dividing the pie into the right number of pieces.

This is the result, in full Hollywood glory, of JavaScript Extensions with a Live Entity-based Chart in Oracle Policy Modelling.

The PDF version is on the OPA Hub Shop, just search for the Pie Chart example.

We will of course be revisiting this to investigate making it more robust, but it’s a good starting point. Have fun and see you soon!

Back to Basics Fun with Relationships

Back to Basics Fun with Relationships

The other day I had cause to discuss Relationships with an Oracle Policy Automation developer, and as a result of the discussions and the level of interest expressed in the learning curve, I thought I would share here the project that I used to illustrate some of the main concepts used when working with them in an Interview. Firstly, to put Back to Basics Fun with Relationships in context, here are the entities we will discuss :

  • Global (of course)
  • the car
  • the passenger

The entities are in part received from another system, and look like this:

To simulate the external system in this demonstration, the data for the cars is coming from a Microsoft Excel spreadsheet which infers various vehicles. The passengers are manually entered in the Interview and then different relationships are using to construct the connections between the cars and the passengers. In this case, we need to identify the passengers in each car (which has been called the car’s passengers here), and then to specify which passenger is sitting in the front seat (which has been called the copilot here). So the car entity has the following reference relationships, both of them with the passenger but of different cardinality.

Back to Basics Fun with Relationships 3

When we look at the first two Screens there is not much to report. The first displays the cars and the second gets the passengers.

Back to Basics Fun with Relationships Cars Back to Basics Fun with Relationships Passengers

The third Screen is where some students can go wrong. The key is to display the relationship (the car’s passengers) . In the case shown, a label has been added to display the car name. Notice how the choice of display is limited to Checkbox because of the cardinality of the relationship. This makes for a situation where the user can choose the passengers and of course a passenger can only be in one car. Selecting the same passenger for two cars produces an error (as it should, even if the error message is generic).

Back to Basics Fun with Relationships Choose Passengers

  1. The relationship is added to the Screen
  2. The selection control is displayed
  3. Only Checkbox is available

The Screen looks like this in the Debugger:

Back to Basics Fun with Relationships Selecting Passengers for Cars

Finally, the fourth Screen will allow the selection of one of the passengers to be assigned as the front seat passenger (a.k.a the copilot). The Screen is displayed below and the key areas highlighted:

  1. Again we add the relationship to the Screen
  2. The cardinality means the default display option is a Drop-down, although others are available in the Toolbar this time (fixed list or radio buttons). I wish these were customizable using Control Extensions but they are not…as of 18A.
  3. The display will allow you to select a copilot, and filtering the data ensures that only passengers of the correct car are available. In this way, the first relationship (the car’s passengers) drives the second (the copilot).

The Screen looks like this in the Debugger:

Back to Basics Fun with Relationships Copilot

Finally there was a requirement to associate the copilot with the car in a more direct fashion. Specifically, the car entity had attributes to contain the name of the copilot. The basics (not complete) of this are shown below:

Back to Basics Fun with Relationships Mapping

So the car has a front seat occupant boolean attribute and the value is retrieved from the passenger entity and the copilot relationship and copied into the car attribute. The relationships and the entities allow us to retrieve data in the structure and place it in the car.

Back to Basics Fun with Relationships Data Tab

Hopefully this example will let you imagine how relationships can be used to enhance your Oracle Policy Modelling. I hope you enjoyed this Back to Basics Fun with Relationships post. As always the official Oracle Policy Automation documentation can be found here.

February 2017 Release of Oracle Policy Automation

February 2017 Release of Oracle Policy Automation

In case you missed it, the February 2017 Release of Oracle Policy Automation is now available for download and inspection from the official sources. This release sees some interesting new tweaks in the Interview Tab, as well as enhancements to the Oracle Policy Automation Hub, especially in respect of programmatic access to some features. There are also some exciting new flexibility enhancements in respect of the Oracle Service Cloud connection. Here is a list of the new features.

  • Service Cloud connection – enhanced usage of a single interview for agents, logged-in users and anonymous users
  • Manage Hub users programatically – Oracle Policy Automation HUB REST Interface
  • New User Account Type in the Hub (see Video)
  • Use external identity providers (via REST)
  • Export Data Model to CSV (See Video)
  • Entity Type Highlight in Data Tab (See Video)
  • Slider Enhancements (See Video)
  • File Upload Enhancements (See Video)
  • Unsaved Interview Prompts

We have already posted five videos outlining the new features, and more will be uploaded in the coming days to give you a rapid overview of the new enhancements both in the Oracle Policy Modeling application and on the Oracle Policy Automation Hub web application.  Proof, if ever proof was needed, of the continued investment in the OPA line to further enhance its status as the go-to natural language logic and dematerialised interview engine.

OPA 12 – November 2016 Release New Feature Review #2

OPA 12 – November 2016 Release New Feature Review #2

Part One is here.

Continuing our review of new features in the latest version of the Oracle Policy Automation family, OPA 12 – November 2016 Release; some of the most interesting new features concern the user interface as we were discussing last time round. There are a couple of things I want to applaud loudly (having often spent time making them happen in earlier versions).

  • The ability to create image groups. We have all seen them on modern websites. Instead of a row of radio buttons or a list, we have icons. The icons have two states : clicked or unclicked. The user “gets the idea” in about 2 seconds flat:

These now can be created purely from the Oracle Policy Modeler interface. No more need for image sprites, CSS or anything else. I am disappointed though that the “hover” state is not supported.

  • Slider Controls. The ability to map a numeric attribute to a slider, complete with upper and lower bounds. That is cool and takes another mess of JavaScript off my shoulders.

OPA 12 – November 2016 Release

The slider and the image group are just two of the new graphical features. The third one I am going to talk about today also will make our lives (and those of our consumers) much more fun. The capability to have dynamic update of an attribute, live, on the same screen as the source attributes, is very nice indeed.

I don’t think it will make a huge difference in a lot of cases, but if you can do it, and you don’t need to have rafts of JavaScript any more, I’m in!

OPA 12 – November 2016 Release

In the example above, changing the values in the area (1) changes the value in (2) with no change of page. JavaScript and jQuery we love you!

Next time we will look at some great new features in the back end of OPA 12 – November 2016 Release! Until then, have a great day!

Back to Basics 7 – Interview Styles

Back to Basics 7 – Interview Styles

This episode looks at something that crops us regularly in workshops or training sessions with Oracle Policy Automation. What can we do to make the interview more unique , more like my website, more modern? You name it, you can insert plenty of other things in there – most people will recognize the sort of discussions I’m sure.

All too often the next step appears to bring in web specialists. I’m not against that at all, in fact quite the opposite, but only at the point where it becomes necessary, because we cannot achieve what the customer is asking without it.

There does not need to be a lot of Cascading Style Sheet manipulation on every project – because there are a host of options that can be managed from inside the Oracle Policy Modeler application and that will result in a custom style being written for you, but without the need for actual CSS editing.

The Styles Dialog is perfectly good for a lot of basic groundwork. It’s great that so many different things can be adjusted so quickly without resorting to customization.

OPA 12 Interview Styles Dialog

Bare Metal

In fact one of the things I like most about the Interview is the ability to strip right back to a minimalist look and feel, which is great for focusing the minds present on the actual business rules and not the gadgets. My own favorite thing is to strip off the extra styling on the radio buttons, calendar and drop-downs. These controls are already lightly styled out of the box. Compare the following.

This is the standard look and feel and the bare metal side by side:

Notice the difference. The custom sprites have been removed from the radio buttons and the other controls have had similar treatment. This is controlled by one option in the appearances.properties file. This file can be found if you go to the Styles dialog and click the Custom Files… button on the bottom left corner, then accept the warning. To activate the option you will need to remove the “#” on the following line.

OPA 12 Interview Styles Appearances ExtractThe appearances.properties file contains so many useful options that I am glad you have found it!

Have fun until next time.

 

Worldwide
Logo by Southpaw Projects LLC