Lingo Code "[cc]" is coming up as a fault - adobe-director

The game is a word search game in an advanced lingo book and the lingo code is using [cc] which is coming up as a code fault. What is wrong or is this use of [cc] obsolete? And if so, how can it be corrected?
on getPropertyDescriptionList me
list = [:]
-- the text member with the words in it
addProp list, #pWordSource,[cc]
[#comment: "Word Source",[cc]
#format: #text,[cc]
#default: VOID]
addProp list, #pEndGameFrame,[cc]
[#comment: "End Game Frame",[cc]
#format: #marker,[cc]
#default: #next]
return list
end

I guess this is code from here, right?
That seems like an older version of Lingo syntax. [cc], apparently, stands for "continuation character". It basically makes the compiler ignore the linebreak right after it, so that it sees everything from [#comment: to #default: VOID] as one long line, which is the syntactically correct way to write it.
If I remember correctly, once upon a time, the guys who made Lingo made one more crazy decision and made the continuation character look like this: ¬ Of course, this didn't print in lots of places, so some texts like your book used things like [cc] in its place.
In modern versions of Lingo, the continuation character is \, just like in C.

I programmed in early director but have gone on to other languages in the many years since. I understand this code. The function attempts to generate a dictionary of dictionaries. in quasi-JSON:
{
'pWordSource': { ... } ,
'pEndGameFrame': { ... }
}
It is creating a string hash, then storing a "pWordSource" as a new key pointing to a 3 item hash of it's own. The system then repeats the process with a new key "pEndGameFrame", providing yet another 3 item hash. So just to expand the ellipses ... from the above code example:
{
'pWordSource': { 'comment': 'Word Source', 'format': 'text', 'default': null } ,
'pEndGameFrame': { 'End Game Frame': 'Word Source', 'format': 'marker', 'default': 'next' }
}
So I hope that explains the hash characters. It's lingo's way of saying "this is not just a string, it's a special director-specific system we're calling a symbol. It can be described in more conventional programming terms as a constant. The lingo compiler will replace your #string1 with an integer, and it's always going to be the same integer associated with #string1. Because the hash keys are actually integers rather than strings, we can change the json model to look something more like this:
{
0: { 2: 'Word Source', 3: 'text', 4: null } ,
1: { 2:'End Game Frame', 3: 'marker', 4: 'next' }
}
where:
0 -> pWordSource
1 -> pEndGameFrame
2 -> comment
3 -> format
4 -> default
So to mimic the same construction behavior in 2016 lingo, we use the newer object oriented dot syntax for calling addProp on property lists.
on getPropertyDescriptionList me
list = [:]
-- the text member with the words in it
list.addProp(#pWordSource,[ \
#comment: "Word Source", \
#format: #text, \
#default: void \
])
list.addProp(#pEndGameFrame,[ \
#comment: "End Game Frame", \
#format: #marker, \
#default: #next \
])
return list
end
Likewise, the same reference shows examples of how to use square brackets to "access" properties, then initialize them by setting their first value.
on getPropertyDescriptionList me
list = [:]
-- the text member with the words in it
list[#pWordSource] = [ \
#comment: "Word Source", \
#format: #text, \
#default: void \
]
list[#pEndGameFrame] = [ \
#comment: "End Game Frame", \
#format: #marker, \
#default: #next \
]
return list
end
And if you are still confused about what the backslashes are doing, there are other ways to make the code more vertical.
on getPropertyDescriptionList me
list = [:]
-- the text member with the words in it
p = [:]
p[#comment] = "Word Source"
p[#format] = #text
p[#default] = void
list[#pWordSource] = p
p = [:] -- allocate new dict to avoid pointer bug
p[#comment] = "End Game Frame"
p[#format] = #marker
p[#default] = #next
list[#pEndGameFrame] = p
return list
end
The above screenshot shows it working in Director 12.0 on OS X Yosemite.

Related

How to get/set Trello custom fields using the API?

I'm already in love with the Custom Fields feature in Trello. Is there a way to get and set custom fields via the API?
I tried using the get field API call to get a field (on a board with a custom field defined called "MyCustomField"):
curl "https://api.trello.com/1/cards/57c473503a5ef0b76fddd0e5/MyCustomField?key=${TRELLO_API_KEY}&token=${TRELLO_OAUTH_TOKEN}"
to no avail.
The Custom Fields API from Trello is now officially available (announcement blog post here).
It allows users to manipulate both custom field items of boards and custom field item values on cards.
Custom Fields API documentation
Getting customFieldItems For Cards
Setting & Updating CustomFieldItems
This is just to add to bdwakefield's answer. His solution involves hard coding the names of the field ids.
If you want to also retrieve the name of the fields themselves (for example get that "ZIn76ljn-4yeYvz" is actually "priority" in Trello, without needing to hard code it, call the following end point:
boards/{trello board id}/pluginData
This will return an array with the plugins information and in one of the array items, it will include a line along the lines of:
[value] => {"fields":[{"n":"~custom field name~:","t":0,"b":1,"id":"~custom field id that is the weird stuff at the card level~","friendlyType":"Text"}]}
So you just need to figure out the plugin for custom fields in your case, and you can retrieve the key -> value pair for the custom field name and the id associated with it.
It means that if you add / remove fields, or rename them, you can handle it at run time vs changing your code.
This will also give you the options for the custom field (when it is a dropdown like in bdwakefield's example above).
So I have a "sort of" answer to this. It requires some hackery on your part to make it work and there is more than a little manual upkeep as you add properties or values -- but it works.
I am doing this in powershell (I am NOT well versed in ps just yet and this my first really 'big' script that I have pulled together for it) since my intent is to use this with TFS Builds to automate moving some cards around and creating release notes. We are using custom fields to help us classify the card and note estimate/actual hours etc. I used this guys work as a basis for my own scripting. I am not including everything but you should be able to piece everything together.
I have left out everything with connecting to Trello and all that. I have a bunch of other functions for gettings lists, moving cards, adding comments etc. The ps module I linked above has a lot of that built in as well.
function Get-TrelloCardPluginData
{
[CmdletBinding()]
param
(
[Parameter(Mandatory,ValueFromPipelineByPropertyName)]
[ValidateNotNullOrEmpty()]
[Alias('Id')]
[string]$CardId
)
begin
{
$ErrorActionPreference = 'Stop'
}
process
{
try
{
$uri = "$baseUrl/cards/$CardId/pluginData?$($trelloConfig.String)"
$result = Invoke-RestMethod -Uri $uri -Method GET
return $result
}
catch
{
Write-Error $_.Exception.Message
}
}
}
You'll get data that looks like this:
#{id=582b5ec8df1572e572411513; idPlugin=56d5e249a98895a9797bebb9;
scope=card; idModel=58263201749710ed3c706bef;
value={"fields":{"ZIn76ljn-4yeYvz":2,"ZIn76ljn-c2yhZH":1}};
access=shared}
#{id=5834536fcff0525f26f9e53b; idPlugin=56d5e249a98895a9797bebb9;
scope=card; idModel=567031ea6a01f722978b795d;
value={"fields":{"ZIn76ljn-4yeYvz":4,"ZIn76ljn-c2yhZH":3}};
access=shared}
The fields collection is basically key/pair. The random characters correspond to the property and the value after that is what was set on the custom property. In this case it is an 'index' for the value in the dropdown. These two fields have a 'priority' (low, medium, high) and a 'classification' (Bug, Change Request, etc) for us. (We are using labels for something else).
So you'll have to create another fucntion where you can parse this data out. I am sure there are better ways to do it -- but this is what I have now:
function Get-TrelloCustomPropertyData($propertyData)
{
$data = $propertyData.Replace('{"fields":{', '')
$data = $data.Replace('}}', '')
$data = $data.Replace('"', '')
$sepone = ","
$septwo = ":"
$options = [System.StringSplitOptions]::RemoveEmptyEntries
$obj = $data.Split($sepone, $options)
$cardCustomFields = Get-TrelloCustomFieldObject
foreach($pair in $obj)
{
$field = $pair.Split($septwo,$options)
if (-Not [string]::IsNullOrWhiteSpace($field[0].Trim()))
{
switch($field[0].Trim())
{
'ZIn76ljn-4yeYvz' {
switch($field[1].Trim())
{
'1'{
$cardCustomFields.Priority = "Critical"
}
'2'{
$cardCustomFields.Priority = "High"
}
'3'{
$cardCustomFields.Priority = "Medium"
}
'4'{
$cardCustomFields.Priority = "Low"
}
}
}
'ZIn76ljn-c2yhZH' {
switch($field[1].Trim())
{
'1'{
$cardCustomFields.Classification = "Bug"
}
'2'{
$cardCustomFields.Classification = "Change Request"
}
'3'{
$cardCustomFields.Classification = "New Development"
}
}
}
'ZIn76ljn-uJyxzA'{$cardCustomFields.Estimated = $field[1].Trim()}
'ZIn76ljn-AwYurD'{$cardCustomFields.Actual = $field[1].Trim()}
}
}
}
return $cardCustomFields
}
Get-TrelloCustomFieldObject is another ps function that I set up to build an object based on the properties I know that I have defined.
function Get-TrelloCustomFieldObject
{
[CmdletBinding()]
param()
begin
{
$ErrorActionPreference = 'Stop'
}
process
{
$ccf = New-Object System.Object
$ccf | Add-Member -type NoteProperty -name Priority -value "None"
$ccf | Add-Member -type NoteProperty -name Classification -value "None"
$ccf | Add-Member -type NoteProperty -name Estimated -value ""
$ccf | Add-Member -type NoteProperty -name Actual -value ""
return $ccf
}
}

REBOL layout: How to create layout words automatically - word has no context?

Using the REBOL/View 2.7.8 Core, I would like to prepare a view layout beforehand by automatically assigning words to various layout items, as in the following example.
Instead of
prepared-view: [across
cb1: check
label "Checkbox 1"
cb2: check
label "Checkbox 2"
cb3: check
label "Checkbox 3"
cb4: check
label "Checkbox 4"
]
view layout prepared-view
I would thus like the words cb1 thru cb5 to be created automatically, e.g.:
prepared-view2: [ across ]
for i 1 4 1 [
cbi: join "cb" i
cbi: join cbi ":"
cbi: join cbi " check"
append prepared-view2 to-block cbi
append prepared-view2 [
label ]
append prepared-view2 to-string join "Checkbox " i
]
view layout prepared-view2
However, while difference prepared-view prepared-view2 shows no differences in the block being parsed (== []), the second script leads to an error:
** Script Error: cb1 word has no context
** Where: forever
** Near: new/var: bind to-word :var :var
I've spent hours trying to understand why, and I think somehow the new words need to be bound to the specific context, but I have not yet found any solution to the problem.
What do I need to do?
bind prepared-view2 'view
view layout prepared-view2
creates the correct bindings.
And here's another way to dynamically create layouts
>> l: [ across ]
== [across]
>> append l to-set-word 'check
== [across check:]
>> append l 'check
== [across check: check]
>> append l "test"
== [across check: check "test"]
>> view layout l
And then you can use loops to create different variables to add to your layout.
When you use TO-BLOCK to convert a string to a block, that's a low-level operation that doesn't go through the "ordinary" binding to "default" contexts. All words will be unbound:
>> x: 10
== 10
>> code: to-block "print [x]"
== [print [x]]
>> do code
** Script Error: print word has no context
** Where: halt-view
** Near: print [x]
So when you want to build code from raw strings at runtime whose lookups will work, one option is to use LOAD and it will do something default-ish, and that might work for some code (the loader is how the bindings were made for the code you're running that came from source):
>> x: 10
== 10
>> code: load "print [x]"
== [print [x]]
>> do code
10
Or you can name the contexts/objects explicitly (or by way of an exemplar word bound into that context) and use BIND.

Defining Variables Prior to use in TCL

I'm brand new to TCL, and am trying to wrap my brain around all the usages of "", {}, and [] that it uses. Something I'm used to doing in other languages is defining my variables prior to use, at the beginning of the application. The below code works:
puts "Please enter an integer of choice to be added: "
flush stdout
gets stdin intAnswer
puts "Please enter a second integer of choice to be added: "
flush stdout
gets stdin intAnswerTwo
puts "Please enter a third integer of choice to be added: "
flush stdout
gets stdin intAnswerThree
puts "The total of the three integers is: [expr $intAnswer + $intAnswerTwo + $intAnswerThree]"
What I'm wanting to do is define the variables prior to use. As such:
set intAnswer 0
set intAnswerTwo 0
set intAnswerThree 0
set intTotal 0
This code, placed at the beginning, doesn't work with the rest of the code. What am I missing?
The code looks absolutely fine to me, though [expr {$intAnswer + $intAnswerTwo + $intAnswerThree}] would be better (as it stops potential reinterpretation of the variables' contents, which would be both a safety and performance issue).
However, if you really want to have integers from the user, you need to validate their input. This is most easily done by writing a procedure to do the job so you can reuse it (i.e., you refactor the code to get a value so you can use a more sophisticated version and get it right once):
proc getIntFromUser {message} {
# Loop forever (until we [exit] or [return $response])
while true {
puts $message
flush stdout
set response [gets stdin]
# Important to check for EOF...
if {[eof stdin]} {
exit
}
# The validator (-strict is needed for ugly historical reasons)
if {[string is integer -strict $response]} {
return $response
}
# Not an integer, so moan about it
puts "\"$response\" is not an integer!"
}
}
Now you have that procedure, the rest of your code can become:
set intAnswer [getIntFromUser "Please enter an integer of choice to be added: "]
set intAnswerTwo [getIntFromUser "Please enter a second integer of choice to be added: "]
set intAnswerThree [getIntFromUser "Please enter a third integer of choice to be added: "]
puts "The total of the three integers is: [expr {$intAnswer + $intAnswerTwo + $intAnswerThree}]"
The art of writing good Tcl code (or good code in pretty much any other language) is knowing what are the good points to refactor. A good starting point is “if you do it twice or more, do it once and share”. It's doubly good if you can give the procedure a good name and clear interface, a clear indication that you've got it right. Indeed, you could also go for:
set total [expr {
[getIntFromUser "Please enter an integer of choice to be added: "] +
[getIntFromUser "Please enter a second integer of choice to be added: "] +
[getIntFromUser "Please enter a third integer of choice to be added: "]
}]
puts "The total of the three integers is: $total"
The results observed by the user will be identical.

Mass PDF form fill

I need to fill in a single PDF template multiple times and concat the results. When I say multiple, I mean up to a few hundred times, potentially over one thousand.
I can do this with pdftk fill_form, one by one, and then use pdftk cat. We can parallelize this fairly easily.
I'm curious if this is the only option, or if there is a piece of software (Linux + OSX, command line) that will allow me to say "take this template, and these sets of fields, fill out this form, and concat the files" so I can avoid doing every one individually. Then again, if something does exist, but it's not any faster than just doing the fork parallelization method, then it's probably not worth it.
My Perl library CAM::PDF can do this. The form filling is a bit weak (it doesn't support checkboxes, for example) but the concatenation works great.
#perl -w
use strict;
use CAM::PDF;
my $infile = 'in.pdf';
my $outfile = 'out.pdf';
my #fills = (
{ name => 'John' },
{ name => 'Fred' },
);
my $pdf = CAM::PDF->new($infile) or die $CAM::PDF::errstr;
for my $i (0 .. #fills-1) {
my $filledPDF = $i == 0 ? $pdf : CAM::PDF->new($infile);
$filledPDF->fillFormFields(%{$fills[$i]});
if ($i > 0) {
$pdf->appendPDF($filledPDF);
}
}
$pdf->cleanoutput($outfile) or die;

How can I implement incremental (find-as-you-type) search on command line?

I'd like to write small scripts which feature incremental search (find-as-you-type) on the command line.
Use case: I have my mobile phone connected via USB, Using gammu --sendsms TEXT I can write text messages. I have the phonebook as CSV, and want to search-as-i-type on that.
What's the easiest/best way to do it? It might be in bash/zsh/Perl/Python or any other scripting language.
Edit:
Solution: Modifying Term::Complete did what I want. See below for the answer.
I get the impression GNU Readline supports this kind of thing. Though, I have not used it myself. Here is a C++ example of custom auto complete, which could easily be done in C too. There is also a Python API for readline.
This StackOverflow question gives examples in Python, one of which is ...
import readline
def completer(text, state):
options = [x in addrs where x.startswith(text)]
if state < options.length:
return options[state]
else
return None
readline.set_completer(completer)
this article on Bash autocompletion may help. This article also gives examples of programming bash's auto complete feature.
Following Aiden Bell's hint, I tried Readline in Perl.
Solution 1 using Term::Complete (also used by CPAN, I think):
use Term::Complete;
my $F;
open($F,"<","bin/phonebook.csv");
my #terms = <$F>; chomp(#terms);
close($F);
my $input;
while (!defined $input) {
$input = Complete("Enter a name or number: ",#terms);
my ($name,$number) = split(/\t/,$input);
print("Sending SMS to $name ($number).\n");
system("sudo gammu --sendsms TEXT $number");
}
Press \ to complete, press Ctrl-D to see all possibilities.
Solution 2: Ctrl-D is one keystroke to much, so using standard Term::Readline allows completion and the display off possible completions using only \.
use Term::ReadLine;
my $F;
open($F,"<","bin/phonebook.csv");
my #terms = <$F>; chomp(#terms);
close($F);
my $term = new Term::ReadLine;
$term->Attribs->{completion_function} = sub { return #terms; };
my $prompt = "Enter name or number >> ";
my $OUT = $term->OUT || \*STDOUT;
while ( defined (my $input = $term->readline($prompt)) ) {
my ($name,$number) = split(/\t/,$input);
print("Sending SMS to $name ($number).\n");
system("sudo gammu --sendsms TEXT $number");
}
This solution still needs a for completion.
Edit: Final Solution
Modifying Term::Complete (http://search.cpan.org/~jesse/perl-5.12.0/lib/Term/Complete.pm) does give me on the fly completion.
Source code: http://search.cpan.org/CPAN/authors/id/J/JE/JESSE/perl-5.12.0.tar.gz
Solution number 1 works with this modification. I will put the whole sample online somewhere else if this can be used by somebody
Modifications of Completion.pm (just reusing it's code for Control-D and \ for each character):
170c172,189
my $redo=0;
#match = grep(/^\Q$return/, #cmp_lst);
unless ($#match < 0) {
$l = length($test = shift(#match));
foreach $cmp (#match) {
until (substr($cmp, 0, $l) eq substr($test, 0, $l)) {
$l--;
}
}
print("\a");
print($test = substr($test, $r, $l - $r));
$redo = $l - $r == 0;
if ($redo) { print(join("\r\n", '', grep(/^\Q$return/, #cmp_lst)), "\r\n"); }
$r = length($return .= $test);
}
if ($redo) { redo LOOP; } else { last CASE; }