Add an Intro page to exam in R/exams - moodle

I am using R/exams to generate Moodle exams (Thanks Achim and team). I would like to make an introductory page to set the scenario for the exam. Is there a way to do it? (Now, I am generating a schoice with answerlist blank.)
Thanks!
João Marôco

Usually, I wouldn't do this "inside" the exam but "outside". In Moodle you can include a "Description" in the "General Settings" when editing the quiz. This is where I would put all the general information so that students read this before starting with the actual questions.
If you want to include R-generated content (R output, graphics, data, ...) in this description I would usually include this in "Question 1" rather than as a "Question 0" without any actual questions.
The "description" question type could be used for the latter, though. However, it is currently not supported in exams2moodle() (I'll put it on the wishlist). You could manually work around this in the following steps:
Create a string question with the desired content and set the associated expoints to 0.
Generate the Moodle XML output as usual with exams2moodle().
Open the XML file in a text editor or simply within RStudio and replace <question type="shortanswer"> with <question type="description"> for the relevant questions.
In the XML file omit the <answer>...</answer> for the relevant questions.
Caveat: As you are aware it is technically possible to share the same data across subsequent exercises within the same exam. If .Rnw exercises are used, all variables from the exercises are created in the global environment (.GlobalEnv) and can be easily accessed anyway. If .Rmd exercises are used, it is necessary to set the envir argument to a dedicated shared environment (e.g., .GlobalEnv or a new.env()) in exams2moodle(..., envir = ...). However, if this is done then no random exercises must be drawn in Moodle because this would break up the connections between the exercises (i.e., the first replication in Question 1 is not necessarily followed by by the first replication in Question 2). Instead you have to put together tests with a fixed selection of exercises (i.e., always the first replication for all questions or the second replication for all questions, ...).

Related

Migrating from itext2 to itext7

Years ago, I wrote a small app in itext2 to gather reports on a weekly basis and concatenate them into one PDF. The app used com.lowagie.text.pdf.PdfCopy to copy and merge the PDFs. And it worked fine. Performed exactly as expected.
A few weeks ago I looked into migrating the application to itex7. To that end, I used the copyPagesTo method of com.itextpdf.kernel.pdf.PdfDocument. When run on the same file set, this produces warnings like:
WARN PdfNameTree - Name "section.1" already exists in the name tree; old value will be replaced by the new one.
When I click on the link to "section.1" in the first document of the merged PDF, I am taken to "section.1" of the last document. Not what I expected and not what happens when using the itext2 app. In the PDF's produced by itext2, if I click on the link to "section.1" of the first document in the combined PDF, I am taken to section 1 of the first document.
There is a hint in Javadocs for copyPagesTo saying
If outlines destination names are the same in different documents, all
such outlines will lead to a single location in the resultant
document. In this case iText will log a warning. This can be avoided
by renaming destinations names in the source document.
There is however, no explanation of how this should be done. I find it odd that this should be necessary in itext7, although it wasn't in itext2.
Is there a simple way to get around his problem?
I've also tried the Sejda desktop app and it produces correct results, but I would prefer to automate the process through a batch script.
My guess is iText 2 didn't even know it might be a problem.
If iText can't deduplicate destination names, the procedure is roughly:
Follow /Catalog -> /Names -> /Dests in each document to find the destination name tree.
Deduplicate the names, by adding suffixes. Remember that a name with a suffix added might be equal to an existing name in the same or another document. Be careful!
Now you can rewrite the destination name trees. Since you have only used suffixes, you can do this in place - the lexicographic ordering of the names is unaltered so the search tree structure is not broken.
Now, rewrite destination links in each PDF for the new names. For example any dictionary entry with key /Dest, or any /D in a /GoTo action.
Now, after all this preprocessing, the files will merge without name clashes.
(I know all this because I've just implemented it for my own PDF software. It's slightly hairy stuff, but not intractable.)
If you like, I can provide a devel version of cpdf with this functionality, if you would like to test it.

VS Code Regex search to remove references based on containing text in string

I am attempting to remove all references of a managed package that is going to be uninstalled that spans throughout code base in VS Code
I have using a query to find the field permissions but am wondering if there is a way to search for the reference outside of specifying the exact field name compared to the field containing only "agf" since they are all using it.
Below is the search query:
<fieldPermissions>
<editable>false</editable>
<field>User.agf_Certified_Product_Owner__c</field>
<readable>false</readable>
</fieldPermissions>
In the field, I want to be able to find and delete the 5 associated lines from multiple files if they match "agf" in any combination. Something like the below:
<fieldPermissions>
<editable>false</editable>
<field>agf</field>
<readable>false</readable>
</fieldPermissions>
With any combination of agf in the field, delete all from any file it appears in.
Not an answer but too long for a comment
You don't have to? Profiles/perm sets don't block package's delete. Probably neither do reports.
You'd use your time better by searching for all instances of agf__ (that's with double underscore), should find fields, objects... used in classes, flows, page layouts etc. And search for agf. (with dot) should find all instances where your Apex code calls their classes marked as global.
Alternatively Apex / VF pages with dependencies on package will have it listed in their "meta.xml", for example
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>54.0</apiVersion>
<packageVersions>
<majorNumber>236</majorNumber>
<minorNumber>1</minorNumber>
<namespace>SBQQ</namespace>
</packageVersions>
<status>Active</status>
</ApexClass>
Last but not least - why not just spawn a dev sandbox and attempt the delete there? If it succeeds - great. If not - it'll list the dependencies that blocked the delete. It'll be "the real thing", it'll smite you even if your VSCode project doesn't contain all flows, layouts and thus could lull you into false sense of security. I'd seriously do it in sandbox and then run all tests for good measure, just in case there are some dynamic soql queries that don't count as hard, delete-blocking references.
After delete's done - fetch Profiles / Permsets from this org and the field references will be gone from the xml.

IBM Chatbot Assistant - Array with same values

I have this piece of code in JSON editor of Watson:
"context": {
"array": "<? entities['spare_part'].![literal] ?>",
"array_size": "<?$array.size() ?>"
When the input of the user, for example, is "Hello, I need a valve, and the part number of the valve is 1234", the size of the array ends up being 2 since the user mentions the word "valve" twice in his input. Some nodes are being executed depending on size of the array. For instance if the size of the array is 1, some nodes will be ignored because they are only executed only if the size of the array is 2.
I want the array to store only the inputs with different values, which is basically I don`t want the array to store the values of the same type, in my case 2 valves. If it is possible somehow please show me a way.
All that can be done, but the best approach depends on the overall system architecture. Remember that Watson Assistant is a conversation service, not a data processing platform...
You can process JSON in either Watson Assistant directly using the built-in methods and SpEL, see these links to get started:
- https://console.bluemix.net/docs/services/conversation/expression-language.html#expressions-for-accessing-objects
- http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html
- https://console.bluemix.net/docs/services/conversation/dialog-methods.html#expression-language-methods
That would require some coding within the dialog nodes. It could be ok. What I would recommend is to either process in your app that drives the dialog (you need that app anyway) or to code up small server actions to transform data.
If it is the word you are looking for, you can use contextual entities to train for this.
As an example I created the following intent (along with general intents from catalog).
For each example I highlighted the "valve" word that is the one I am interested in, and added to the entity.
Now when I test it I get the following.
All this was done in a couple of minutes. For production level you may want to add more examples, or think about how you want to annotate.

Grails: Radio button doesn't populate command obj when not selected

When I submit my form, if I do not select a value for my radio box then nothing is sent over to my command object for validation. I don't have issues with textFields or other input types.
class ApplicationCommand implements Validateable {
Map<String,String[]> questions = new LinkedHashMap<String,String[]>();
static constraints = {
questions validator: {val, obj, errors ->
for(String key : val.keySet()) {
errors.rejectValue("questions[${key}]",'required');
}
}
}
}
<g:radioGroup name="cmd.questions[1]" values="['Yes']" labels="['Yes']">
${it.radio}${it.label}
</g:radioGroup>
<g:textField name="cmd.questions[2]" />
With the above example, If i leave both fields empty and I submit I get the following
qusetions = [2: String[0]]
What I expect to see is
questions = [1: String[0], 2: String[0]]
Due to this issue, in my questions validator since key=1 is not populated I cannot validate it. The questions are dynamic all pulled from a DB so I cant hard-code anything in the validator such as if !questions.contains(1). Whatever data is populated into questions upon submission is what I have to assume the data is.
I have found 2 work-arounds, neither of which I like
1) Only for radio buttons, add a hidden field that will force a value to be populated if a radio is not selected. Horribly ugly
<g:hiddenField name="cmd.questions[1]" value="-" />
2) In my validator, I query the DB for all my questions and manually check for the existence of each one in the questions map. I want to avoid DB queries in my validators.
So while my 2 work-around options do work, I don't feel like I should have to resort to them.
I don't think this is a limitation of command objects or Grails; I think it's a limitation of HTML. I see the same question popping up in PHP.
The essential problem is that your command object doesn't know how many questions there are, but is responsible for making sure they are all there. I can think of a couple of (additional) ways to deal with this limitation:
The quick and easy way would be to put a single hidden input with the number of questions into your form. Also ugly, and open to alteration by the end-user.
The other option is to promote questions into a Domain so that the number of questions is known ahead of time, and is made available to your command object via a field or method. Then your command object can ask your questions, "How many are there supposed to be? Okay, did I get that many from the view?" This is similar to your #2 but without having to retrieve an entire collection and iterate it. This also opens up a path to perform further validation on each question (e.g., don't allow text into a numbers-only answer).
This does require hitting the DB, but it's the only way I can think of to validate the number of questions without relying on input from the view. The nice thing is that you can make it a very shallow hit, and hitting the DB can be very quick if you do it properly.

Query with toLocalizedTime in Plone

I'm using toLocalizedTime to output a date, as below
<span tal:content="python:here.toLocalisedTime(date.get('start_date'))"/>
This outputs eg. 2007/08/02, I'm just curious as to how one would alter the output so that it reads 02/08/2007
I'm not having much luck finding much info on toLocalizedTime, would someone point me in the right direction?
This depends on whether you have English selected as the site language (Site Setup >> Language). If so, then the default settings are used. You can change the defaults by dropping down into the ZMI, then into 'portal_properties', then 'site_properties'. The fields to change are either 'localTimeFormat' or 'localLongTimeFormat' depending on whether you pass in 'long_format=1' to the toLocalisedTime function.
If on the other hand, you have translations set up, the format may instead be pulled from the translation file for the locale selected. I'm not sure what is the easy way to change the format in this case (other than switching the site back to English). I guess you can register your own translation file but I've never needed to do that so you're going to have to look up the details.
Date string formatting follows the Python rules (http://docs.python.org/library/time.html#time.strftime).
Perhaps even more detail than you need:
here.toLocalizedTime()
is defined in the plone browser view at...
CMFPlone/browser/ploneview.py
which looks up the 'translation_service' utility, to call its 'ulocalized_time' function, defined at...
CMFPlone/TranslationServiceTool.py
which itself calls the 'ulocalized_time' function defined at...
CMFPlone/i18nl10n.py
As always, you can learn interesting things by grepping the source code ;-)
For an up to date answer for Plone 4.3 (after going through the source code)
These fields are now in the registry found at:
http://localhost:8080/yoursite/portal_registry
Then filter on "i18nl10n", which should give you the 4 fields you need to change.