×

To be able to write in the forum you need to authenticate. Meanwhile it's read-only.

Change History

Documentation and guidelines for writing challenge checkers and creating tags. Also some useful links.

Message: Documentation

Changed By: magma1447
Change Date: February 20, 2024 09:14AM

Documentation
[size=large]Script language[/size]
The script language used is based on LUA, running in a Sandbox. The LUA version currently used is version 5.1. You can read more about it in the [url=http://www.lua.org/manual/5.1/]LUA 5.1 manual[/url].

[size=large]LUA Sandbox[/size]
Our Sandbox environment is based on [url=https://www.mediawiki.org/wiki/LuaSandbox]Mediawiki's LuaSandbox[/url].

[size=large]LUA Functions[/size]
Generally all functions that are harmless should be included. Functions that generally are excluded are those with file operations, network operations and similar. For more details, read Mediawiki's documentation for their LuaSandbox.

[size=large]APIs from Project-GC[/size]
To get data from Project-GC there are a few API methods available. They are documented using doxygen [url=http://project-gc.com/doxygen/lua-sandbox/classPGC__LUA__Sandbox.html]here[/url].
The functions have different names in LUA and in the documentation, since they are renamed for the Sandbox environment. For example, if you want to use the function
[code]static PGC_LUA_Sandbox::CreateHTMLTable($data)[/code] from LUA, it's called PGC.CreateHTMLTable($data).

[size=large]Script keywords[/size]
The keywords are used to help others finding your script. This together with the script description is indexed for the search engine.

[size=large]Script description[/size]
Try to describe what your script can do here, without being too long about it. If your script handles different parameters they should be documented here. In that way others might find the need for your source code for other challenges as well (see below about Tag config).

[size=large]Tags[/size]
There are two terms to be aware of when creating scripts. [i]Scripts[/i] and [i]Tags[/i]. The scripts are the main part and include the source code itself. But without a [i]tag[/i] it can not be executed. The tag contains information like gccode, configuration and a comment. The comment is mostly used to describe what the tag does, maybe the name of the challenge isn't clear enough. Note that even under development you then need to create a tag. You can leave both configuration and the gccode empty meanwhile.

Here is an example
[list]
[*] You write a checker that checks if User X has Y finds in country Z.
[*] You then create a tag that refers to the GC-code of a challenge that requires the user to have 1000 finds in Sweden. You then create a config that passes the parameter Y = 1000 and Z = Sweden as well (see below for more information about configs).
[/list]
In this way, you can use the same script for many different challenges, since many of them are almost the same.

[size=large]Tag config[/size]
When adding tags to your checker you can also add a json blob of config variables. Very useful if you want to use the same code but need different in-parameters. For example. 1000 finds in country X and 5000 finds in country Y. For that, add a json blob like this one:
[code]{"count":"1000", "country":"Sweden"}[/code]
Your script will then receive this config as an array in its arguments, see [i]Predefined arguments to the script[/i].

You can check your json using an online Json Lint service like [url]http://jsonlint.com/[/url].

[size=large]Predefined arguments to the script[/size]
All scripts will be provided by an array that looks like this:
[code]array() {
profileName => string
profileId => string
config => array
gccode => string
environementSettings environmentSettings => array {
cli => bool
token => string (32 byte md5)
maxMemoryUsage => int (bytes)
maxExecutionTime => int (seconds)
sandboxVersion => int (currently 2)
}
}
[/code]
... where the config array comes from the tag-config. You can retrieve the above by using code like this:
[code]local args={...}
conf = args[1].config
profileName = args[1]['profileName']
profileId = args[1]['profileId']
[/code]

[size=large]Return values[/size]
A checker script should end with returning an array of values. The currently supported variables are: ok, log, html and map.
LUA syntax:
[list]
[*] [b]ok[/b] can be true or false, depending on if the given profile name fulfills the requirement or not.
[*] [b]log[/b] can be either false, or contain a string with a log example. Normally this is filled in if the given profile name fulfills the requirements, and the required log data is added here. The log will be prefixed with a hard coded string saying something like:
[i]XXX has used Project-GC to see if he/she qualifies for this challenge and he/she does.[/i]
[*] [b]html[/b] can be either false or contain a HTML blob that will be given back to the user. It could be more detailed feedback information for example. This blob will most likely not be useful to post in a log entry. This is an excellent output field to use when the user has not fulfilled the challenge and the script can give some helpful information.
[/list]
[code]return { ok = ok, log = log, html = false }[/code]

[size=large]Enabling/Disabling scripts[/size]
While developing we recommend doing that on a script that is [b]not[/b] enabled. In that way no-one else can find the script and try to execute code that might be faulty. In fact, the scripts are write protected when they are enabled.

If you need to update an existing script, we suggest that you copy the source code into a new script (fork it) while developing. The old script can then be kept available to everyone while you keep the new one disabled. When you are done you just copy the source back into the original, and optionally delete your temporary script.

If you need to add new tags to a script, you can keep the new tags disabled as well, until you have tested them.

[size=large]Source code template[/size]
When creating a new script, you will get a start of ~50 lines of skeleton code. It's the basics to retrieve the arguments mentioned above, and a basic return structure.

[size=large]Getting started[/size]
To get started, you are recommended to download the source from some of the current available checkers to see how they are built. An extremely simple example script would be [url]http://project-gc.com/Challenges//19600[/url].
Changed By: magma1447
Change Date: March 19, 2018 10:15AM

Documentation
[size=large]Script language[/size]
The script language used is based on LUA, running in a Sandbox. The LUA version currently used is version 5.1. You can read more about it in the [url=http://www.lua.org/manual/5.1/]LUA 5.1 manual[/url].

[size=large]LUA Sandbox[/size]
Our Sandbox environment is based on [url=https://www.mediawiki.org/wiki/LuaSandbox]Mediawiki's LuaSandbox[/url].

[size=large]LUA Functions[/size]
LUA functions available in the sandbox are listed below. To the left you will find the name you can use in the LUA Sandbox. To the right is the official name of the function.
[list]
[*] Next = next
[*] Print = print
[*] OsClock = os.clock
[*] OsTime = os.time
[*] Pairs = pairs
[*] IPairs = ipairs
[*] ToNumber = tonumber
[*] ToString = tostring
[*] Type = type
[*] StringByte = string.byte
[*] StringChar = string.char
[*] StringFind = string.find
[*] StringFormat = string.format
[*] StringGmatch = string.gmatch
[*] StringGsub = string.gsub
[*] StringLen = string.len
[*] StringLower = string.lower
[*] StringMatch = string.match
[*] StringRep = string.rep
[*] StringReverse = string.reverse
[*] StringSub = string.sub
[*] StringUpper = string.upper
[*] TableInsert = table.insert
[*] TableMaxn = table.maxn
[*] TableRemove = table.remove
[*] TableSort = table.sort
[*] TableConcat = table.concat
[*] MathAbs = math.abs
[*] MathAcos = math.acos
[*] MathAsin = math.asin
[*] MathAtan = math.atan
[*] MathAtan2 = math.atan2
[*] MathCeil = math.ceil
[*] MathCos = math.cos
[*] MathCosh = math.cosh
[*] MathDeg = math.deg
[*] MathExp = math.exp
[*] MathFloor = math.floor
[*] MathFmod = math.fmod
[*] MathFrexp = math.frexp
[*] MathHuge = math.huge
[*] MathLdexp = math.ldexp
[*] MathLog = math.log
[*] MathLog10 = math.log10
[*] MathMax = math.max
[*] MathMin = math.min
[*] MathModf = math.modf
[*] MathPi = math.pi
[*] MathPow = math.pow
[*] MathRad = math.rad
[*] MathRandom = math.random
[*] MathRandomseed = math.randomseed
[*] MathSin = math.sin
[*] MathSinh = math.sinh
[*] MathSqrt = math.sqrt
[*] MathTan = math.tan
[*] MathTanh = math.tanh
[*] StringXImport = stringx.import
[*] SetMetaTable = setmetatable
[*] GetMetaTable = getmetatable
[*] Unpack = unpack
[/list]

[size=large]LUA Libraries[/size]
Also the [url=http://stevedonovan.github.io/Penlight/api/modules/pl.Date.html]Date object[/url] from the [url=http://stevedonovan.github.io/Penlight/api/index.html]Penlight library[/url] has been included. The constructor is called [b]Date[/b].
Example:
[code]
local d = Date {year = 2011, month = 3, day = 2 }
d:add { year = 1 }
d:add { day = -3 }
Print(d:year() .. '-' .. d:month() .. '-' .. d:day() .. "\n")
[/code]
Output: [i]2012-2-28[/i]
Generally all functions that are harmless should be included. Functions that generally are excluded are those with file operations, network operations and similar. For more details, read Mediawiki's documentation for their LuaSandbox.

[size=large]APIs from Project-GC[/size]
To get data from Project-GC there are a few API methods available. They are documented using doxygen [url=http://project-gc.com/doxygen/lua-sandbox/classPGC__LUA__Sandbox.html]here[/url].
The functions have different names in LUA and in the documentation, since they are renamed for the Sandbox environment. For example, if you want to use the function
[code]static PGC_LUA_Sandbox::CreateHTMLTable($data)[/code] from LUA, it's called PGC_.CreateHTMLTable($data).

[size=large]Script keywords[/size]
The keywords are used to help others finding your script. This together with the script description is indexed for the search engine.

[size=large]Script description[/size]
Try to describe what your script can do here, without being too long about it. If your script handles different parameters they should be documented here. In that way others might find the need for your source code for other challenges as well (see below about Tag config).

[size=large]Tags[/size]
There are two terms to be aware of when creating scripts. [i]Scripts[/i] and [i]Tags[/i]. The scripts are the main part and include the source code itself. But without a [i]tag[/i] it can not be executed. The tag contains information like gccode, configuration and a comment. The comment is mostly used to describe what the tag does, maybe the name of the challenge isn't clear enough. Note that even under development you then need to create a tag. You can leave both configuration and the gccode empty meanwhile.

Here is an example
[list]
[*] You write a checker that checks if User X has Y finds in country Z.
[*] You then create a tag that refers to the GC-code of a challenge that requires the user to have 1000 finds in Sweden. You then create a config that passes the parameter Y = 1000 and Z = Sweden as well (see below for more information about configs).
[/list]
In this way, you can use the same script for many different challenges, since many of them are almost the same.

[size=large]Tag config[/size]
When adding tags to your checker you can also add a json blob of config variables. Very useful if you want to use the same code but need different in-parameters. For example. 1000 finds in country X and 5000 finds in country Y. For that, add a json blob like this one:
[code]{"count":"1000", "country":"Sweden"}[/code]
Your script will then receive this config as an array in its arguments, see [i]Predefined arguments to the script[/i].

You can check your json using an online Json Lint service like [url]http://jsonlint.com/[/url].

[size=large]Predefined arguments to the script[/size]
All scripts will be provided by an array that looks like this:
[code]array(3) ) {
'profileName' =>
string(3) "foo"
'profileId' =>
string(3) "123"
'config' =>
array(0) {
profileName => string
profileId => string
config => array
gccode => string
environementSettings => array {
cli => bool
token => string (32 byte md5)
maxMemoryUsage => int (bytes)
maxExecutionTime => int (seconds)
sandboxVersion => int (currently 2)
}
}
[/code]
... where the config array comes from the tag-config. You can retrieve the above by using code like this:
[code]local args={...}
conf = args[1].config
profileName = args[1]['profileName']
profileId = args[1]['profileId']
[/code]

[size=large]Return values[/size]
A checker script should end with returning an array of values. The currently supported variables are: ok, log, html.
and map.
LUA syntax:
[list]
[*] [b]ok[/b] can be true or false, depending on if the given profile name fulfills the requirement or not.
[*] [b]log[/b] can be either false, or contain a string with a log example. Normally this is filled in if the given profile name fulfills the requirements, and the required log data is added here. The log will be prefixed with a hard coded string saying something like:
[i]XXX has used Project-GC to see if he/she qualifies for this challenge and he/she does.[/i]
[*] [b]html[/b] can be either false or contain a HTML blob that will be given back to the user. It could be more detailed feedback information for example. This blob will most likely not be useful to post in a log entry. This is an excellent output field to use when the user has not fulfilled the challenge and the script can give some helpful information.
[/list]
[code]return { ok = ok, log = log, html = false }[/code]

[size=large]Enabling/Disabling scripts[/size]
While developing we recommend doing that on a script that is [b]not[/b] enabled. In that way no-one else can find the script and try to execute code that might be faulty. In fact, the scripts are write protected when they are enabled.

If you need to update an existing script, we suggest that you copy the source code into a new script (fork it) while developing. The old script can then be kept available to everyone while you keep the new one disabled. When you are done you just copy the source back into the original, and optionally delete your temporary script.

If you need to add new tags to a script, you can keep the new tags disabled as well, until you have tested them.

[size=large]Source code template[/size]
When creating a new script, you will get a start of 10-20 ~50 lines of skeleton code. It's the basics to retrieve the arguments mentioned above, and a basic return structure.

[size=large]Getting started[/size]
To get started, you are recommended to download the source from some of the current available checkers to see how they are built. An extremely simple example script would be [url]http://project-gc.com/Challenges//19600[/url].
Changed By: magma1447
Change Date: February 09, 2017 11:33AM

Documentation
[size=large]Script language[/size]
The script language used is based on LUA, running in a Sandbox. The LUA version currently used is version 5.1. You can read more about it in the [url=http://www.lua.org/manual/5.1/]LUA 5.1 manual[/url].

[size=large]LUA Functions[/size]
LUA functions available in the sandbox are listed below. To the left you will find the name you can use in the LUA Sandbox. To the right is the official name of the function.
[list]
[*] Next = next
[*] Print = print
[*] OsClock = os.clock
[*] OsTime = os.time
[*] Pairs = pairs
[*] IPairs = ipairs
[*] ToNumber = tonumber
[*] ToString = tostring
[*] Type = type
[*] StringByte = string.byte
[*] StringChar = string.char
[*] StringFind = string.find
[*] StringFormat = string.format
[*] StringGmatch = string.gmatch
[*] StringGsub = string.gsub
[*] StringLen = string.len
[*] StringLower = string.lower
[*] StringMatch = string.match
[*] StringRep = string.rep
[*] StringReverse = string.reverse
[*] StringSub = string.sub
[*] StringUpper = string.upper
[*] TableInsert = table.insert
[*] TableMaxn = table.maxn
[*] TableRemove = table.remove
[*] TableSort = table.sort
[*] TableConcat = table.concat
[*] MathAbs = math.abs
[*] MathAcos = math.acos
[*] MathAsin = math.asin
[*] MathAtan = math.atan
[*] MathAtan2 = math.atan2
[*] MathCeil = math.ceil
[*] MathCos = math.cos
[*] MathCosh = math.cosh
[*] MathDeg = math.deg
[*] MathExp = math.exp
[*] MathFloor = math.floor
[*] MathFmod = math.fmod
[*] MathFrexp = math.frexp
[*] MathHuge = math.huge
[*] MathLdexp = math.ldexp
[*] MathLog = math.log
[*] MathLog10 = math.log10
[*] MathMax = math.max
[*] MathMin = math.min
[*] MathModf = math.modf
[*] MathPi = math.pi
[*] MathPow = math.pow
[*] MathRad = math.rad
[*] MathRandom = math.random
[*] MathRandomseed = math.randomseed
[*] MathSin = math.sin
[*] MathSinh = math.sinh
[*] MathSqrt = math.sqrt
[*] MathTan = math.tan
[*] MathTanh = math.tanh
[*] StringXImport = stringx.import
[*] SetMetaTable = setmetatable
[*] GetMetaTable = getmetatable
[*] Unpack = unpack
[/list]

[size=large]LUA Libraries[/size]
Also the [url=http://stevedonovan.github.io/Penlight/api/modules/pl.Date.html]Date object[/url] from the [url=http://stevedonovan.github.io/Penlight/api/index.html]Penlight library[/url] has been included. The constructor is called [b]Date[/b].
Example:
[code]
local d = Date {year = 2011, month = 3, day = 2 }
d:add { year = 1 }
d:add { day = -3 }
Print(d:year() .. '-' .. d:month() .. '-' .. d:day() .. "\n")
[/code]
Output: [i]2012-2-28[/i]

[size=large]APIs from Project-GC[/size]
To get data from Project-GC there are a few API methods available. They are documented using doxygen [url=http://project-gc.com/doxygen/lua-sandbox/classPGC__LUA__Sandbox.html]here[/url].
The functions have different names in LUA and in the documentation, since they are renamed for the Sandbox environment. For example, if you want to use the function
[code]static PGC_LUA_Sandbox::CreateHTMLTable($data)[/code] from LUA, it's called PGC_CreateHTMLTable($data).

[size=large]Script keywords[/size]
The keywords are used to help others finding your script. This together with the script description is indexed for the search engine.

[size=large]Script description[/size]
Try to describe what your script can do here, without being too long about it. If your script handles different parameters they should be documented here. In that way others might find the need for your source code for other challenges as well (see below about Tag config).

[size=large]Tags[/size]
There are two terms to be aware of when creating scripts. [i]Scripts[/i] and [i]Tags[/i]. The scripts are the main part and include the source code itself. But without a [i]tag[/i] it can not be executed. The tag contains information like gccode, configuration and a comment. The comment is mostly used to describe what the tag does, maybe the name of the challenge isn't clear enough. Note that even under development you then need to create a tag. You can leave both configuration and the gccode empty meanwhile.

Here is an example
[list]
[*] You write a checker that checks if User X has Y finds in country Z.
[* ][*] You then create a tag that refers to the GC-code of a challenge that requires the user to have 1000 finds in Sweden. You then create a config that passes the parameter Y = 1000 and Z = Sweden as well (see below for more information about configs).
[/list]
In this way, you can use the same script for many different challenges, since many of them are almost the same.

[size=large]Tag config[/size]
When adding tags to your checker you can also add a json blob of config variables. Very useful if you want to use the same code but need different in-parameters. For example. 1000 finds in country X and 5000 finds in country Y. For that, add a json blob like this one:
[code]{"count":"1000", "country":"Sweden"}[/code]
Your script will then receive this config as an array in its arguments, see [i]Predefined arguments to the script[/i].

You can check your json using an online Json Lint service like [url]http://jsonlint.com/[/url].

[size=large]Predefined arguments to the script[/size]
All scripts will be provided by an array that looks like this:
[code]array(3) {
'profileName' =>
string(3) "foo"
'profileId' =>
string(3) "123"
'config' =>
array(0) {
}
}
[/code]
... where the config array comes from the tag-config. You can retrieve the above by using code like this:
[code]local args={...}
conf = args[1].config
profileName = args[1]['profileName']
profileId = args[1]['profileId']
[/code]

[size=large]Return values[/size]
A checker script should end with returning an array of values. The currently supported variables are: ok, log, html.
LUA syntax:
[list]
[*] [b]ok[/b] can be true or false, depending on if the given profile name fulfills the requirement or not.
[*] [b]log[/b] can be either false, or contain a string with a log example. Normally this is filled in if the given profile name fulfills the requirements, and the required log data is added here. The log will be prefixed with a hard coded string saying something like:
[i]XXX has used Project-GC to see if he/she qualifies for this challenge and he/she does.[/i]
[*] [b]html[/b] can be either false or contain a HTML blob that will be given back to the user. It could be more detailed feedback information for example. This blob will most likely not be useful to post in a log entry. This is an excellent output field to use when the user has not fulfilled the challenge and the script can give some helpful information.
[/list]
[code]return { ok = ok, log = log, html = false }[/code]

[size=large]Enabling/Disabling scripts[/size]
While developing we recommend doing that on a script that is [b]not[/b] enabled. In that way no-one else can find the script and try to execute code that might be faulty. In fact, the scripts are write protected when they are enabled.

If you need to update an existing script, we suggest that you copy the source code into a new script (fork it) while developing. The old script can then be kept available to everyone while you keep the new one disabled. When you are done you just copy the source back into the original, and optionally delete your temporary script.

If you need to add new tags to a script, you can keep the new tags disabled as well, until you have tested them.

[size=large]Source code template[/size]
When creating a new script, you will get a start of 10-20 lines of skeleton code. It's the basics to retrieve the arguments mentioned above, and a basic return structure.

[size=large]Getting started[/size]
To get started, you are recommended to download the source from some of the current available checkers to see how they are built. An extremely simple example script would be [url]http://project-gc.com/Challenges//19600[/url].
Changed By: magma1447
Change Date: May 04, 2016 11:10AM

Documentation
[size=large]Introduction[/size]
This far, this page is mostly a placeholder page with short notes. I will try to fix it up some day.

[size=large]Script language[/size]
The script language used is based on LUA, running in a Sandbox. The LUA version of LUA currently used is version 5.1. You can read more about it in the [url=http://www.lua.org/manual/5.1/]LUA 5.1 manual[/url].

[size=large]LUA Functions[/size]
LUA functions available in the sandbox are listed below. To the left you will find the name you can use it with in the LUA Sandbox. To the right is the official name of the function.
[list]
[*] Next = next
[*] Print = print
[*] OsClock = os.clock
[*] OsTime = os.time
[*] Pairs = pairs
[*] IPairs = ipairs
[*] ToNumber = tonumber
[*] ToString = tostring
[*] Type = type
[*] StringByte = string.byte
[*] StringChar = string.char
[*] StringFind = string.find
[*] StringFormat = string.format
[*] StringGmatch = string.gmatch
[*] StringGsub = string.gsub
[*] StringLen = string.len
[*] StringLower = string.lower
[*] StringMatch = string.match
[*] StringRep = string.rep
[*] StringReverse = string.reverse
[*] StringSub = string.sub
[*] StringUpper = string.upper
[*] TableInsert = table.insert
[*] TableMaxn = table.maxn
[*] TableRemove = table.remove
[*] TableSort = table.sort
[*] TableConcat = table.concat
[*] MathAbs = math.abs
[*] MathAcos = math.acos
[*] MathAsin = math.asin
[*] MathAtan = math.atan
[*] MathAtan2 = math.atan2
[*] MathCeil = math.ceil
[*] MathCos = math.cos
[*] MathCosh = math.cosh
[*] MathDeg = math.deg
[*] MathExp = math.exp
[*] MathFloor = math.floor
[*] MathFmod = math.fmod
[*] MathFrexp = math.frexp
[*] MathHuge = math.huge
[*] MathLdexp = math.ldexp
[*] MathLog = math.log
[*] MathLog10 = math.log10
[*] MathMax = math.max
[*] MathMin = math.min
[*] MathModf = math.modf
[*] MathPi = math.pi
[*] MathPow = math.pow
[*] MathRad = math.rad
[*] MathRandom = math.random
[*] MathRandomseed = math.randomseed
[*] MathSin = math.sin
[*] MathSinh = math.sinh
[*] MathSqrt = math.sqrt
[*] MathTan = math.tan
[*] MathTanh = math.tanh
[*] StringXImport = stringx.import
[*] SetMetaTable = setmetatable
[*] GetMetaTable = getmetatable
[*] Unpack = unpack
[/list]


[size=large]LUA Libraries[/size]
Also the [url=http://stevedonovan.github.io/Penlight/api/modules/pl.Date.html]Date object[/url] from the [url=http://stevedonovan.github.io/Penlight/api/index.html]Penlight library[/url] has been included. The constructor is called [b]Date[/b].
Example:
[code]
local d = Date {year = 2011, month = 3, day = 2 }
d:add { year = 1 }
d:add { day = -3 }
Print(d:year() .. '-' .. d:month() .. '-' .. d:day() .. "\n")
[/code]
Output: [i]2012-2-28[/i]

[size=large]APIs from Project-GC[/size]
To get data from Project-GC there are a few API methods available. They are documented using doxygen [url=http://project-gc.com/doxygen/lua-sandbox/classPGC__LUA__Sandbox.html]here[/url].
The functions have different names in LUA and in the documentation, since they are renamed for the Sandbox environment. For example, if you want to use the function
[code]static PGC_LUA_Sandbox::CreateHTMLTable($data)[/code] from LUA, it's called PGC_CreateHTMLTable($data).

[size=large]Input fields[/size]
This was completely changed in October 2014. Before, the script defined a list of input fields it supported in a comment in the source code.

Now there is only support for one input field, and that is [i]Profile name[/i]. This field is provided for all scripts and both a [i]profile name[/i] and the [i]profile id[/i] will automatically be passed into the script as parameters.

[size=large]Script keywords[/size]
The keywords are used to help others finding your script. This together with the script description is indexed for the search engine.

[size=large]Script description[/size]
Try to describe what your script can do here, without being to too long about it. If your script handles different parameters they should be documentioned here. In that way others might find the need for your source code for other challenges as well (see below about Tag config).

[size=large]Tags[/size]
There are two terms to be aware of when creating scripts. [i]Scripts[/i] and [i]Tags[/i]. The scripts are the main part and include the source code itself. But without a [i]tag[/i] it can not be executed. The tag contains information like gccode, configuration and a comment. The comment is mostly used to describe what itthe tag does. M, maybe the name of the challenge isn't clear enough. Note that even under development you then need to create a tag. You can leave both configuration and the gccode empty meanwhile.

Here is an example
[list]
[*] You write a checker that checks if User X has Y finds in country Z.
[* ]You then create a tag that refers to the GC-code of a challenge that requires the user to have 1000 finds in Sweden. You then create a config that passes the parameter Y = 1000 and Z = Sweden as well (see below for more information about configs).
[/list]
In this way, you can use the same script for many different challenges, since many of them are almost the same.

[size=large]Tag config[/size]
When adding tags to your checker you can also add a json blob of config variables. Very useful if you want to use the same code but need different in-parameters. For example. 1000 finds in country X and 5000 finds in country Y. For that, add a json blob like this one:
[code]{"count":"1000", "country":"Sweden"}[/code]
Your script will then receive this config as an array in its arguments, see below.
[i]Predefined arguments to the script[/i].

You can check your json using an online Json Lint service like [url]http://jsonlint.com/[/url].

[size=large]Predefined arguments to the script[/size]
All scripts will be provided by an array that looks like this:
[code]array(3) {
'profileName' =>
string(3) "foo"
'profileId' =>
string(3) "123"
'config' =>
array(0) {
}
}
[/code]
... where the config array comes from the tag-config. You can retreiieve the above by using code like this:
[code]local args={...}
conf = args[1].config
profileName = args[1]['profileName']
profileId = args[1]['profileId']
[/code]

[size=large]Return values[/size]
A checker script should end with returning an array of values. The currently supported variables are: ok, log, html.
LUA syntax:
[list]
[*] [b]ok[/b] can be true or false, depending on if the given profile name fulfills the requirement or not.
[*] [b]log[/b] can be either false, or contain a string with a log example. Normally this is filled in if the given profile name fulfills the requirements, and the required log data is added here. The log will be prefixed with a hard coded string saying something like:
[i]IXXX have s used Project-GC to see if Ihe/she qualify ies for this challenge and Ihe/she does.[/i]
The log can actually also be filled with data if the given profile name did [b]not[/b] qualify. This can be used by the user to say that he was close if he wants to, logging with a note. In that case the log will be prefixed with:
[i]I have used Project-GC to see if I qualify for this challenge, but I did not.[/i]
[*] [b]html[/b] can be either false or contain a HTML blob that will be given back to the user. It could be more detailed feedback information for example. This blob will most likely not be useful to post in a log entry.
This is an excellent output field to use when the user has not fulfilled the challenge and the script can give some helpful information.
[/list]
[code]return { ok = ok, log = log, html = false }[/code]

[size=large]Enabling/Disabling scripts[/size]
While developing we recommend doing that on a script that is [b]not[/b] enabled. In that way no-one else can find the script and try to execute code that might be faulty.
In fact, the scripts are write protected when they are enabled.

If you need to update an existing script, we suggest that you copy the source code into a new script (fork it) while developing. The old script can then be kept available to everyone while you keep the new one disabled. When you are done you just copy the source back into the original, and optionally delete your temporary script.

If you need to add new tags to a script, you can keep the new tags disabled as well, until you have tested them.

[size=large]Source code template[/size]
When creating a new script, you will get a start of about 10 10-20 lines of skeleton code. It's the basics to retrieve the arguments mentioned above, and a basic return structure.

[size=large]Getting started[/size]
To get started, you are recommended to download the source from some of the current available checkers to see how they are built. Two goodAn extremely simple examples might script would be [url=]http://project-gc.com/Tools/Challenges?ccSearch=lillfilurens%20generic%20checker]lillfilurens generic checker[/url] and [url=http://project-gc.com/Tools/Challenges?ccId=41&ccTagId=42&ccCountry=Denmark]At least 6 cache sizes in a day//19600[/url].

Original Message

Author: magma1447
Date: April 28, 2016 12:40PM

Documentation
[size=large]Introduction[/size]
This far, this page is mostly a placeholder page with short notes. I will try to fix it up some day.

[size=large]Script language[/size]
The script language used is based on LUA, running in a Sandbox. The version of LUA currently is 5.1. You can read more about it in the [url=http://www.lua.org/manual/5.1/]LUA 5.1 manual[/url].

[size=large]LUA Functions[/size]
LUA functions available in the sandbox are listed below. To the left you will find the name you can use it with in the LUA Sandbox. To the right is the official name of the function.
[list]
[*] Next = next
[*] Print = print
[*] OsClock = os.clock
[*] OsTime = os.time
[*] Pairs = pairs
[*] IPairs = ipairs
[*] ToNumber = tonumber
[*] ToString = tostring
[*] Type = type
[*] StringByte = string.byte
[*] StringChar = string.char
[*] StringFind = string.find
[*] StringFormat = string.format
[*] StringGmatch = string.gmatch
[*] StringGsub = string.gsub
[*] StringLen = string.len
[*] StringLower = string.lower
[*] StringMatch = string.match
[*] StringRep = string.rep
[*] StringReverse = string.reverse
[*] StringSub = string.sub
[*] StringUpper = string.upper
[*] TableInsert = table.insert
[*] TableMaxn = table.maxn
[*] TableRemove = table.remove
[*] TableSort = table.sort
[*] TableConcat = table.concat
[*] MathAbs = math.abs
[*] MathAcos = math.acos
[*] MathAsin = math.asin
[*] MathAtan = math.atan
[*] MathAtan2 = math.atan2
[*] MathCeil = math.ceil
[*] MathCos = math.cos
[*] MathCosh = math.cosh
[*] MathDeg = math.deg
[*] MathExp = math.exp
[*] MathFloor = math.floor
[*] MathFmod = math.fmod
[*] MathFrexp = math.frexp
[*] MathHuge = math.huge
[*] MathLdexp = math.ldexp
[*] MathLog = math.log
[*] MathLog10 = math.log10
[*] MathMax = math.max
[*] MathMin = math.min
[*] MathModf = math.modf
[*] MathPi = math.pi
[*] MathPow = math.pow
[*] MathRad = math.rad
[*] MathRandom = math.random
[*] MathRandomseed = math.randomseed
[*] MathSin = math.sin
[*] MathSinh = math.sinh
[*] MathSqrt = math.sqrt
[*] MathTan = math.tan
[*] MathTanh = math.tanh
[*] StringXImport = stringx.import
[*] SetMetaTable = setmetatable
[*] GetMetaTable = getmetatable
[*] Unpack = unpack
[/list]


[size=large]LUA Libraries[/size]
Also the [url=http://stevedonovan.github.io/Penlight/api/modules/pl.Date.html]Date object[/url] from the [url=http://stevedonovan.github.io/Penlight/api/index.html]Penlight library[/url] has been included. The constructor is called [b]Date[/b].
Example:
[code]
local d = Date {year = 2011, month = 3, day = 2 }
d:add { year = 1 }
d:add { day = -3 }
Print(d:year() .. '-' .. d:month() .. '-' .. d:day() .. "\n")
[/code]
Output: [i]2012-2-28[/i]

[size=large]APIs from Project-GC[/size]
To get data from Project-GC there are a few API methods available. They are documented using doxygen [url=http://project-gc.com/doxygen/lua-sandbox/classPGC__LUA__Sandbox.html]here[/url].
The functions have different names in LUA and in the documentation, since they are renamed for the Sandbox environment. For example, if you want to use the function
[code]static PGC_LUA_Sandbox::CreateHTMLTable($data)[/code] from LUA, it's called PGC_CreateHTMLTable($data).

[size=large]Input fields[/size]
This was completely changed in October 2014. Before, the script defined a list of input fields it supported in a comment in the source code.

Now there is only support for one input field, and that is [i]Profile name[/i]. This field is provided for all scripts and both a [i]profile name[/i] and the [i]profile id[/i] will automatically be passed into the script as parameters.

[size=large]Script keywords[/size]
The keywords are used to help others finding your script. This together with the script description is indexed for the search engine.

[size=large]Script description[/size]
Try to describe what your script can do here, without being to long about it. If your script handles different parameters they should be mentioned here. In that way others might find the need for your source code for other challenges as well (see below about Tag config).

[size=large]Tags[/size]
There are two terms to be aware of when creating scripts. [i]Scripts[/i] and [i]Tags[/i]. The scripts are the main part and include the source code itself. But without a [i]tag[/i] it can not be executed. The tag contains information like gccode, configuration and a comment. The comment is mostly used to describe what it does. Maybe the name of the challenge isn't clear enough. Note that even under development you then need to create a tag. You can leave both configuration and the gccode empty meanwhile.

Here is an example
[list]
[*] You write a checker that checks if User X has Y finds in country Z.
[* ]You then create a tag that refers to the GC-code of a challenge that requires the user to have 1000 finds in Sweden. You then create a config that passes the parameter Y = 1000 and Z = Sweden as well (see below for more information about configs).
[/list]
In this way, you can use the same script for many different challenges, since many of them are almost the same.

[size=large]Tag config[/size]
When adding tags to your checker you can also add a json blob of config variables. Very useful if you want to use the same code but need different in-parameters. For example. 1000 finds in country X and 5000 finds in country Y. For that, add a json blob like this one:
[code]{"count":"1000", "country":"Sweden"}[/code]
Your script will then receive this config as an array in its arguments, see below.

[size=large]Predefined arguments to the script[/size]
All scripts will be provided by an array that looks like this:
[code]array(3) {
'profileName' =>
string(3) "foo"
'profileId' =>
string(3) "123"
'config' =>
array(0) {
}
}
[/code]
... where the config array comes from the tag-config. You can retreive the above by using code like this:
[code]local args={...}
conf = args[1].config
profileName = args[1]['profileName']
profileId = args[1]['profileId']
[/code]

[size=large]Return values[/size]
A checker script should end with returning an array of values. The currently supported variables are: ok, log, html.
LUA syntax:
[list]
[*] [b]ok[/b] can be true or false, depending on if the given profile name fulfills the requirement or not.
[*] [b]log[/b] can be either false, or contain a string with a log example. Normally this is filled in if the given profile name fulfills the requirements, and the required data is added here. The log will be prefixed with a hard coded string saying something like:
[i]I have used Project-GC to see if I qualify for this challenge and I do.[/i]
The log can actually also be filled with data if the given profile name did [b]not[/b] qualify. This can be used by the user to say that he was close if he wants to, logging with a note. In that case the log will be prefixed with:
[i]I have used Project-GC to see if I qualify for this challenge, but I did not.[/i]
[*] [b]html[/b] can be either false or contain a HTML blob that will be given back to the user. It could be more detailed feedback information for example. This blob will most likely not be useful to post in a log entry.
[/list]
[code]return { ok = ok, log = log, html = false }[/code]

[size=large]Enabling/Disabling scripts[/size]
While developing we recommend doing that on a script that is [b]not[/b] enabled. In that way no-one else can find the script and try to execute code that might be faulty.

If you need to update an existing script, we suggest that you copy the source code into a new script (fork it) while developing. The old script can then be kept available to everyone while you keep the new one disabled. When you are done you just copy the source back into the original, and optionally delete your temporary script.

If you need to add new tags to a script, you can keep the new tags disabled as well, until you have tested them.

[size=large]Source code template[/size]
When creating a new script, you will get a start of about 10 lines of code. It's the basics to retrieve the arguments mentioned above, and a basic return structure.

[size=large]Getting started[/size]
To get started, you are recommended to download the source from some of the current available checkers to see how they are built. Two good examples might be [url=http://project-gc.com/Tools/Challenges?ccSearch=lillfilurens%20generic%20checker]lillfilurens generic checker[/url] and [url=http://project-gc.com/Tools/Challenges?ccId=41&ccTagId=42&ccCountry=Denmark]At least 6 cache sizes in a day[/url].