![]() |
Frequently Asked Questions v2 |
FAQ Main / Browse by Category |
![]() |
We have slice data and structure exported to AA.XML file and we want to import it back to the AA. The problem is, that the AA.XML file is 24 MB.
The solution:
The problem could be in PHP setting. Here's what I had to change in php.ini file to get it going:
1. post_max_size: increased from 8M to 32M
2. upload_max_filesize: increased from 2M to 32M
Those first two were key -- from the php log the upload was clearly
exceeding both of these parameters. Obviously, if the upload was bigger
than 32M (ours was about 24M) this might need to go even bigger.
I also increased these others. I think the upload wouldn't have
completed in the default times, but I'm not sure which parts of the
operation count towards which of these:
1. max_execution_time: changed from 30 to 120 seconds
2. max_input_time: changed from 30 to 120 seconds
3. memory_limit: changed to 32M
The output generated by AA is controlled by aliases. The aliases are 10
letters long words defined on 'Admin' -> 'Fields' -> 'Edit' page. Aliases
are obviously expanded to the content of some database field or its
modification (like How to use aliases alias). For modification of behavior of the
alias we use alias functions, as described on
http://apc-aa.sourceforge.net/faq/#216.
http://apc-aa.sourceforge.net/faq/#291.
Since the AA version 2.1 there is possibility to use the aliases NESTED,
which means that you can use another alias in the alias definition. For
example this Parameters to f_c alias functions are possible:
!:<img src=":" _#PHOTO_WI _#PHOTO_HE alt="photo">::
which displays image (if it is defined). The aliases _#PHOTO_WI _#PHOTO_HE
must be defined, of course.
You can use there not only the aliases, but it is possible to use any of
database field directly there. Imagine, we store type of record in
switch.........1 field (for example text/audio/video). If we create three
images - icon_text.gif, icon_audio.gif, icon_video.gif, we can add an icon
before each link by the following Parameters to f_m alias function:
<img src="img/icon_{switch.........1}.gif" width="14"> :text...........1::href:class="green10"
The AA version 2.2-pre (04/25/2002) give you new possibilities in alias definition - IN-LINE ALIAS DEFINITION. The parsing of format strings was rewritten, so now you can define aliases not only on 'Admin' -> 'Fields' -> 'Edit' page, but you can define it directly inside the format string (= 'Fulltext HTML code' on 'Design' -> 'Fulltext' page, for example). The new features are 100% backward compatible.
The alias definitions are surrounded by curly braces. There are the
possibilities:
... there is displayed headline: {headline........} <br> Source: ...
{const_name:category.......1}, {const_description:category.......1}, which displays name (description) of constant stored in field category.......1.
const_short_id | short_id |
const_name | name |
const_value | value (the same as {category.......1} ) |
const_pri | priority number |
const_group | name of constant group |
const_class | class (APC parent category) |
const_id | long constant id |
const_description | description (defined on hierarchy editor pages) |
... fields in AA could contain multiple values (categories, ...). It is possible to diesplay it:
The example is
directly in Item Manager of 'Test News' slice. The syntax is:
{@category.......1} | displays list of 'values' - comma separated (comma is default) |
{@category.......1:-} | displays list of 'values' - dash separated (it is usefull for example in display of related items: {view.php3?vid=11&cmd[11]=x-11-{@relation.......1:-}} |
{@category.......1:,:<b>_#1</b>} | displays list of 'values' in bold - comma separated (_#1 is alias for the values) |
{@category.......1:,:<a href="/category.shtm?conds[0][category.......1]=_#1">_#1</a>} | displays list of categories with link to the each category |
{@category.......1(const_name,const_value,const_short_id):,:<a href="/category.shtm?conds[0][category.......1]=_#2">_#3 _#1</a>} | displays list of categories with link to the each category, but the text shows category name (and short_id) instead of value. You can use as many constant translations as you want in the parethes. See 'constant display' for list of possible values in previous paragraph. |
...view.php3?vid=123&als[heading]=My Page
and then ... <h1>{heading}</h1>
... The previous example is good, but sometimes we need to modify the
database field before it is displayed. For example the date field is
displayed as number if seconds since begin of year 1970, which is probably
not exactly what we want to show to user. The solution is to use alias
function modification, which has the following syntax:
alias:<the field>:<alias function>:<parameters>
So, in text (format string) could be the publish date displayed by {alias:publish_date....:f_d:j.n.Y}
. There you can use any alias function
with any parameters.
The parameters could be nested, so inside curly braces you can use any alias (How to use aliases), any other field ({headline........}) or any other in-line alias definition. There is no limit in level of nesting.
For example, conditional display of date could look:
{alias:switch.........1:f_c:text:{alias:publish_date....:f_d:j.n.Y}<!--:-->::}
or if we have 06/19/2002 alias defined:
{alias:switch.........1:f_c:text:06/19/2002<!--:-->::}
Both this constructs displays date only if switch.........1 is equal to 'text'. ...
... as addition to in-line aliases you can {# make comments} which is not displayed in result html code. It could be nested again, so you can {# comment out _#ALIASES_ as well as fields {headline........} or alias definitions } - nothing will be in result HTML code ...
... the really new and very useful construct is switch. Many of us knows
the troubles with conditional expressions, managed so far by f_c function.
Now there is much better solution, which allows more options, regular
expressions, ... The syntax is:
{switch(<condition>)<option1>:<output1>:<option2>:<output2>:...[:<default_output>]}
which we can explain on example:
{switch({number.........1})1:one:2:two:[3-7]:more:too much}.
This construct evaluates the condition, which is the content of the number.........1 field in our case. If content of the field is equal to 1, the 'one' is printed. Because 'options' are regular expression, we can specify the third option as [3-7] which means any number in range between 2 and 7. The default option is 'too much' in our case. The evaluation of options goes from left to right and the output is printed only for the first matching option.
The 'switch' could be used instead of f_c alias function in many cases:
{switch({switch.........1})text:06/19/2002}
This expression could replace the expression in the paragraph 2)
Another example displays text 'Continuos grant', if the field
unspecified....2 is filled by 'yes', 'on', 'true' or '1'. Else it displays
expiry date:
{switch({unspecified....2})yes|on|true|1:Continuos grant::12/11/2007}
Display of phone number, if specified (as obvious, '#:' stands for ':' if
you do not want to use it as argument separator:
{switch({con_phone......1}).+:Tel#:{con_phone......1}}
Last example demonstrates the fact, that there is no limit in <condition>.
There could be not only field (in curly braces), but there could be also
any alias, alias definition or its combination. The level of nesting of
'curly braces expressions' is again unlimited.
{switch({1})[1-9][0-9]*:There is discussion under this item}
{view.php3?vid=123}
Returns content of view 123. View uses the
... Sometimes we need to include some file or output of some script into the
page. Now, there is {include(<file>)}, which will be replaced by the
file. The file is called through HTTP request. No matter if included file is html, shtml, php, ...:
the page was visited {include(cgi/counter.pl?id=222)}
(the result of http://www.example.com/cgi/counter.pl?id=222 will be printed)
APC news: {include(http://apc.org/apps/aa/view.php3?vid=112)}
(the remote view (from APC site) will be printed)
If you want to include other slices, it could be usefull to pass the URL
parameters to the included file. In this case use the special URL_PARAMETERS
constant:
{include(fulltext.shtml?URL_PARAMETERS)}
The limits:
... If you want to compute some walue from datadase field, use the {math..} alias. The syntax is ...:
{math(result_formatting) description1: expression 1: description2: expression2:...:description x : expression x }
where:
result_formatting | has 3 parameters separated by '#' (number of decimals # decimals separator # thousands separator) |
description | can be any text or html and is displayed before result of expression ("#:" mean ":") |
expression | in expression can be used numbers (decimal separator is ".". Aliases can be used of course) and characters: + - / * ^ . ( ) |
<img src="red.gif" height=10 width="{math(0#,#) : {_#ANSVER1_} / ({_#ANSVER1_} + {_#ANSVER2_} + {_#ANSVER3_})* 100}%"> _#ANSVER1_ <br> <img src="blue.gif" height=10 width="{math(0#,#) : {_#ANSVER2_} / ({_#ANSVER1_} + {_#ANSVER2_} + {_#ANSVER3_})* 100}%"> _#ANSVER2_ <br> <img src="green.gif" height=10 width="{math(0#,#) : {_#ANSVER3_} / ({_#ANSVER1_} + {_#ANSVER2_} + {_#ANSVER3_})* 100}%"> _#ANSVER3_ <br>
if _#ANSVER1 = 25, _#ANSVER2 = 50, _#ANSVER3 = 250 result will be:<img src="red.gif" height=10 width="8%"> 25 <br> <img src="blue.gif" height=10 width="15%"> 50 <br> <img src="green.gif" height=10 width="77%"> 250 <br>
{math(2#,# ) <br>mails=:{_#NOOFEMAI}*{_#EMAPRICE}:
<br>web=:{_#WWWPRICE}:
<br>technical support=:{_#NOOFHOUR}*{_#HOURPRIC}:
<br><hr>total={_#NOOFEMAI}*{_#EMAPRICE}+{_#WWWPRICE}+{_#NOOFHOUR}*{_#HOURPRIC}
}
result:
mails=450,00
web=1500,00
technical support=2400,00
----------------------------
total=4350,00
In AA v2.6 is new Reader Management, where you can control access to
directory or file through AA admin interface
(see Reader Management). You
can then display informations about logged user by {user:} construct.
The syntax is following:
{user:} | displays login of current user
(this option do not search in database, so it is quick) You can use this parameter even if you do not use Reader Management slice and you are using standard Apache's password file auth ... |
{user:password} | displays password of current user (in plain text)
(this option also do not looks into database, but into internal server variable, so it is also quick) |
{user:headline........} | displays headline........ field for current user, which is grabbed from
Reader Management
slice. There is no need to specify in which Reader Management slice user
is, because all users are unique in all Reader Management slices.
If the Reader Management slice is protected by password (see 'Slice Admin' -> 'Slice' -> 'Password for Reading'), you have to add slice_pwd parameter to view.php3 (or slice.php3), in which you want to display user's database info. You can of course display any field from Reader Management slice. |
{user:role} | displays user's permission role (author/editor/administrator/super/undefined)
(usefull in AA admin interface when you want to display another informations to authors and editors - use it in switch() - like {switch({user:role})editor:_#POSTED_BY} )
|
Such construct you can use in any view or slice - just like any other aliases.
... If you want to use page scroller (Page 1 | 2 | 3 | ... ) in view , which is part of 'site'! (see site module), the {scroller} syntax construct is the right tool. You just add {scorller} to the view, there you want to usepage scroller - probably in the 'Bottom HTML' fileld of the view:
{scroller:Page ::class="blue"}
The syntax for {scroller} is:
{scroller:begin:end:add:nopage}
where:
begin | text to be shown before page numbers |
end | text to be shown after page numbers |
add | option to be added to page number <a href=".." class="blue10v">1</a> |
nopage | text to be shown wnen there are (yet) no pages (so the scroller is not displayed) |
Then you use quite normal view include using {p} state variable, which stores the page number in the site module's spot:
{view.php3?vid=32&set[]=page-{p},listlen-10}
Because it is sometimes unclear which substitutions are available at a certain point, {debug} will output some hopefully useful information
It depends on Fields - Edit -> Insert' setting. If you set it to 'Text', then the value is stored exactly, how it is send by form checkbox (which means 'on' or nothing). However, default and suggested setting is 'Boolean', which means '0' or '1' is inserted.
There are CSS files in the root directory that you can modify or create a new CSS file and point to it from include/config.php3 (line 139). When you update an item that includes a mutual related link it will update the matching relation field ID in the related slice. Make sure both slices are using the exact same ID and that the input Insert is set to "Item IDs".If you get the error: "No slice found for you" after logging into AA after doing a CVS update, then you may have forgotten to fill in the AA_ID in the config.php3 file
If you were a loser (like I have been) and did back-up your AA_ID, it can be retrieved from the AA database...
Using phpMyAdmin or your excellent MySQL skills:
Look for entries in "perms" table that have aa in "object_type" column, "objectid" is your installation ID.
There are several places where APC-AA sends mail, and it can be confusing, especially since it is really easy to configure them wrongly so they don't work, and little help for figuring out why. Lets consider 4 cases. The Bugs and Weaknesses of each method are shown because they may help pick which method to use, and also help guide as to places for further development.
Use the Email Notification functionality, here you can specify different messages to be sent when messages are added / edited to Active / Hold bins, and different recipient lists, so for example you can create a message to an Editor whenever a new message arrives in a Hold bin, and maybe a different message to the sysadmin when an item is moved into the Active bin (usually by the Editor). The message could be just something like "An item has been posted in Xyz slice" or by using aliases can include any fields of the item posted.
Bug/Weakness: You can't use aliases in Subject line, this might be fixed in
some version (but is unlikely to be a priority!)
Limitation: The members of the list can only be changed by a slice admin, so
don't use this for Alerts ...
Use a reader management slice (see doc/reader.html) in conjunction with Alerts (doc/alerts.html).
Bug/Weakness: its complex to setup, and frequently people don't succeed, if you don't follow the Tutorial Step by Step (in doc/alerts.html) you probably won't get it to work.
Bug/Weakness: In particular it requires creating an anonymous form, which depends very much on the way its being used (e.g. called from something.shtml or site.php3). One possible development fix would be creating a PHP3 script that took the slice-id of an Alerts module as a parameter and did this much more simply.
Bug/Weakness: documentation says 5.3a: View with type "Alerts Digest", when it means "Alerts Selection Set".
Use a Reader Management Slice (see doc/reader.html) in conjunction with Mailman, APC-AA is used to manage the mailman list
Bug/Weakness: you can no longer manage the lists (subscribe/unsubscribe) by email to the Mailman account once you've done this, mailman will almost certainly be sending out email telling the users they can!
Bug/Weakness: You have to understand both apc-aa AND mailman to get this to work since doc/reader.html refers to tasks that require knowing where to find and how to configure mailman.
Bug/Weakness: There is no link between information in a slice, or discussions, and the email discussion, i.e. this is not - like yahoo groups - a web OR mail interface to the same set of data.
Reports of failure (Jason Diceman) partly due to server setup
See "FAQ/Discussions as Mail List", this allows a field in each item to specify a mailing list.
Bug/Weakness: This field has to be added to every item, it can't be specified at the slice level (make the field Required but not Shown and set a default). This is particularly difficult if you want to retrofit discussions to an existing slice, or something coming in over RSS.
Bug/Weakness: This can only go to a single email address, so you have to manage the list somewhere else outside APC-AA (there is no way to for example link it to Alerts).
Bug/Weakness: It doesn't appear to work, sends blank emails.
|
Template for Email | Who gets the email | How sent | Bugs, Limitation and further development |
Notification | Admin -> Slice -> Email Notification | Directly from script updating |
Can't use aliases in Subject line |
|
Alerts | Admin -> Slice -> Views -> Alerts View | Readers from Reader slice, who can choose which to recieve | By Cron | Complex to setup (anon forms) |
Email Discussion | Not applicable - its email to email | Members managed by Reader Management slice | Mailman handles all sending |
Requires understanding mailman to setup, reports of failure partly due to server setup |
Discussion -> Email | Admin -> Slice -> Views -> Discussion to Email | One hard-coded email address | Not sure, probably cron. | Doesn't integrate with Alerts so no recipient management at all Doesn't seem to work (Mitra). Has to be added to each item in slice. |
There is no integration for receiving email, although there has been discussion (where?) about posting articles by mail
In view you can specify "No item found" message, which is displayed if view (due to its current conditions) do not find an item to display.You can enter there:One recomendation is to write something that relates to the slice content, e.g. "No news found" or "No events found", with in visible HTML or a comment tag. This helps with both usability and view development problem solving.
The hit is counted in this cases:
1) with slice.php3
- if you will display an item with x=24425
url parameter
- if you will display an item with
sh_itm=42567a8736342562782abe782c
- if you will use banner url
parameter (banner=2-38)
2) with view.php3
- if you display an item with
cmd[22]=x-22-24425
Note 1: if you use more than one
item with x
command
(like cmd[23]=x-22-24425-24461-23612) only
first
item is counted)
Note 2: if you want to display an
item and do not want to
count
hit for such item, use 'o'
command
(like cmd[23]=o-22-24425), which works exactly in the
same
way as 'x', but it do not count hits.
- if you use random
parameter (ie. set[23]=random-1)
For speedup of database operations we use log table for hits count,
from
which it is time to time copied to item table. You can configure
this
behavior in include/constants.php3:
// CountHit probability - how offen write logged hits to item table
define
("COUNTHIT_PROBABILITY", 50);
This means that after 50 hits (approximately) (in whole AA) the hits
are
written to item table (= displayed to users).
For more info see CountHit() function in include/util.php3
No, it is not possible - at least yet.
There is a problem with characters encoding and different languages. Each language uses its own character encoding (like iso-8859-1 for English and Spanish, iso-8859-2 or windows-1250 for Czech, ...). If you select language for the slice, you also select (implicitly) the character encoding. If we allow users to use different language in the same slice, each item will be in different encoding, ... which means problems.
Abstract
Explains the basic idea, creation and settings of Anonymous forms. The name “anonymous” is in some cases not accurate, as the form is used for reader personal info and the readers must be authorized to edit their own info.
See also: doc/reader.html, doc/alerts.html, doc/script/show_result.php3
Anonymous forms are similar in function and design to the Add / Edit item page. The main difference is they are placed outside of the AA Control Panel and thus do not provide the AA authorization and have a design of their own.
The most common usage is to allow web readers to suggest new content. After filling the Anonymous form it is sent to the Holding Bin and a Thank you page appears. But you can also allow readers to edit items with the Anonymous form.
Two scripts handle the anonymous forms. The first, filler.php3, stores the info coming from the form into the database. It also validates the data and prooves permissions to edit or update the item. The second, fillform.php3, refills the data into the form shown to the reader. It retrieves the data from database or in some special cases directly from filler.
In the previous AA versions until version 2.4, the process of creating Anonymous forms was very simple: Copy the code of the “Add item” page with only a few necessary changes. But as the form now allows to edit items and to use several options for it, a new wizard was created. This wizard creates the HTML code for a complete form with the SSI include of fillform.php3 necessary to edit items. The resulting form differs depending on whether Anonymous editing is allowed or not.
You may change these settings in the wizard or later in hidden fields:
Table 1. Wizard settings
err_url | The URL to which the script filler.php3 jumps when some error occurs. It may be the same page on which the form is shown. |
ok_url | Like err_url, for successful changes. |
show_result | The URL of a PHP script which receives the results from filler.php3. This allows for a completely free design of how the errors are presented to the user. See below. |
If you are interested to know more about what the form contains, here are some remarks:
If you want to edit items with anonymous forms, first you must allow to choose which item to edit. You can create a view and add a link to the headlines, which links to the anonymous form and contains the parameter my_item_id=11a7cc0908d77c22bf2c7ca43cdd8480. Another approach is used in Reader management slices, see below.
You must choose the correct setting in Slice Admin - Settings - Allow anonymous editing of items, which is used by the filler.php3 script on an item update request. The options are:
Table 2. Anonymous editing options
Not allowed | Never allow to update items |
All items | Always allow |
Only items posted anonymously | For items posted anonymously, filler always sets the ITEM_FLAG_ANONYMOUS_EDITABLE flag. By choosing this option you allow only items with this flag set to be edited. |
Only items posted anonymously and not edited in AA | Similar to the previous one, but when you edit the item in the control panel, the flag is cleared and thus the item is no more allowed to be edited anonymously. |
Authorized by a password field | filler looks for a field of type Password (with Id beginning with password....) and requests the password sent by the user to match. The password may be set on item creation. If the field is not flagged required, an empty password may be used. The new Field Input Type, Field Insert Function and Field Validate Functions “Password and Change Password” provide the usual edit boxes for changing, deleting and entering password, which is stored encrypted. The disadvantage is the password must be sent on every update. |
Readers, authorized by HTTP auth | This is a special option, useful only for Reader management slices. The username given to the browser on HTTP authentification is looked for in the database. Each reader may edit only his or her personal info. |
It is possible to send images and other files by the form (unlike the anonymous posting in version prior 1.5)
It is possible to set values to a non-displayed field by just adding a hidden field for such a field:
<input type=hidden name="v696d675f6865696768742e2e2e2e2e2e" value="Anonymous author">
Note: This solution is easy and good working in many cases, but it is by no means secure. Any experienced user can change the values of the hidden fields so do not rely on such data. A better solution is to completely omit such fields from the input form and set the default values for the fields in "Admin" -> "Main setting - Fields" -> "Edit" -> "Default". The values are than set directly from the database. This solution is a little bit more secure.
The inputs are validated as if they were typed in the standard itemedit.php3 form. When there are any invalid data, the whole item is not updated. The javascript validation used in itemedit.php3 is also included in the form created by the wizard
You can disable the standard AA validation by adding a hidden field notvalidate in the form:
<input type=hidden name="notvalidate" value="1">
Be cautious when using two anonymous forms on one page. You must rename the
form and the Javascript variables so that
they do not conflict with each
other.
If your form includes HTMLarea, you will need to include <body onload="HTMLArea.init()"> in your form page.
Each reader has her or his own item in the Reader management slice. Thus the HTTP authentication described above may be used directly to determine which item (reader personal details) to show in the form.
In this case two forms are needed, one being the publicly accessible subscribe form and the second being the HTTP protected “Change personal details” form. Because the fields on both the forms may be the same, you can use one form and include it into two different .shtml pages.
For webs not using Auth we need a way to ensure nobody not only edits but even views the data. This is achieved by assigning a special “Access Code” (see the Reader management documentation) to each reader, which must be added to the URL in order that the data are prefilled. The password authorization described above is than used on item update.
Sending the data to AA results in adding the data into database or in an error. Some of the errors may be excluded in advance by Javascript validation (function proove_fields). But some of them, like a username being already used, can not.
By default, the fillform.php3 script shows standard error messages. They always appear at the place where fillform.php3 is SSI-included in your shtml page.
You may create your own PHP script (see an example in doc/script/show_result.php3) and send its URL as a value of a show_result variable. Add it as a parameter to the fillform.php3 SSI include created by the Wizard, e.g.
<!--#include virtual="/aaa/fillform.php3?show_result=http://ecn.cz/show_result.php3&form=..."-->
An array $result with the results will be sent to the PHP script and you may print appropriate messages, see the example.
The $result array content is created at various places in filler.php3 array. Look there for accurate info. At this moment the messages are:
Table 3. Results from filler.php3
fatal | Fatal error. Several messages related to the slice, not to the particular item. These errors help on creating the web page. |
validate | Array with not validated fields, field_id => message, e.g. headline........ => This username is already used created on field validation. You may create your own messages depending on the field_id. |
permissions | Missing permissions. Depending on the setting for Anonymous editing (see above), this item did not fullfill the requirements. |
store | Some error in StoreItem. Usually this points to an inner AA error. |
success | No error. The operation was successfully done. The value is “insert” or “update” (i.e. $result["success"] == "insert" or $result["success"] == "update" in the show results script). |
email_confirmed | Added by fillform.php3 on Reader management slices: When the reader successfully confirms his or her email by using the URL sent in an email, fillform adds a message “email_confirmed => OK”. This message is added only when the email has not yet been confirmed. |
unsubscribed | Added by fillform.php3 on Reader management slices: When the reader unsubscribes from Alerts (which is achieved by setting How often to an empty value). |
Discussion: A similar result may be achieved by adding several fields to the form, e.g. fields
err_page[validate][username......]="err_username.shtml"
err_page[validate][*]="err_validate.shtml"
err_page[*]="err_unrecognized.shtml"
and by creating the .shtml pages with a static message concerning the particular error. The main advantage of this approach is the web administrator may not know PHP. The disadvantage is the necessity of creating many pages but using SSI includes the pages could look only like:
<!--#include file="err_top.shtml"-->
The username you entered has already been used. Please try another username.
<!--#include file="err_bottom.shtml"-->
If you want to display some view on page, which is stored on site where is not installed AAs, you have three possibilities.
This answer covers point 3) - jsview.php3
The usage is easy. Just replace SSI include in original shtml age with the javascript one. The jsview.php3 takes exactly the same parameters as view.php3.
For example, if the old SSI code in page.shtml was:
<!--#include virtual="/apps/aa/view.php3?&vid=2&cmd[2]=c-1-APC" -->
the new javascript code in page.shtml would be:
<script type="text/javascript" src="http://www.apc.org/apps/aa/jsview.php3?vid=2&cmd[2]=c-1-APC"></script>
Normally you will want either a Item listing, Full text or Static Page view.
Link listing and Category listing views are used for Links module - you can customize the design of links listing and category listing just like jot normal AA items. The usage is analogous to Item listing and is quite simple, but deep documentation of those views wait for someone, who will have resources to document Links module.
Requirements for ActionApps Unix Hosting
Optional:
Please add your comments below about AA installs that have and have not worked for you...
This FAQ interface was developed by Jason at Commons.ca
|
![]() |
APC
ActionApps is a free software content management system initiated by
the Association for Progressive Communications (APC) APC - Internet and ICTs for social justice and development |