/[drupal]/contributions/modules/nf_handshake/README.txt
ViewVC logotype

Contents of /contributions/modules/nf_handshake/README.txt

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.6 - (show annotations) (download)
Thu Nov 29 07:21:32 2007 UTC (23 months, 3 weeks ago) by rconstantine
Branch: MAIN
CVS Tags: HEAD
Changes since 1.5: +0 -0 lines
File MIME type: text/plain
#193325 fixed it so user 1 and other admins can engage in handshakes - i.e. the checkboxes work correctly now

also we now react to user deletion and remove handshakes from our tables - you may need to clean your tables by hand as I didn't include a retroactive cleaning function

added css IDs to inbox and outbox and included a css file

added ability to include email address and picture from standard user profile as exchangable data - this was a pain in the butt! so if anyone wants to add other items from the users table, be my guest to roll a patch.
1 /**
2 * $Id:$
3 * @package Handshake
4 * @category NeighborForge
5 */
6 This module allows users to control just how much of their nodeprofile data is shared
7 with other users on a case-by-case basis.
8
9 Attempting to contact an 'unknown' user will allow them to choose to
10 a) send them a message, or
11 b) initiate a handshake.
12
13 The 'initiator' has the option to select which fields of his/her own to expose.
14
15 The 'acceptor' then has the option of
16 1) rejecting the handshake altogether;
17 2) accepting the handshake after
18 a) checking the fields of theirs they want to share(from the list the first user
19 created),
20 b) selecting a handshake 'duration';
21 3) flagging the request for the admin and writing a note as to why the request may be
22 inappropriate or a violation of the user agreement.
23
24 Whatever fields are deemed 'okay' by the 'acceptor' are exposed to both parties. (See
25 the database table to see what information is tracked to make this possible.) A time
26 limit may be placed on the transaction by either party. A handshake may be revoked at
27 any time. It may be expanded and extended.
28
29 This module can also be considered a 'contacts' module as all users with whom a user
30 has 'shaken hands' can be listed, sorted, etc. More robust contacts tools will be
31 added as time allows. The goal is to eventually be able to add contacts like you would
32 in outlook and import/export to the most popular formats to sync your data. These
33 features will likely end up as part of this project, but as a separate module so as to
34 allow selective use via the admin/build/modules page.
35
36 --CONTENTS--
37 REQUIREMENTS
38 INSTALL
39 SETUP
40 FEATURES
41 UNINSTALL
42 CREDITS
43
44 --REQUIREMENTS--
45 *This module requires the nodeprofile module and Drupal 5.x.
46 [Tested on file version: nodeprofile.module,v 1.7.2.14 2007/04/29 18:34:47]
47
48 *You should also use either the standard contact module, or the privatemsg module so
49 users may communicate with each other [optional].
50
51 --INSTALL--
52 Installation is through the normal Drupal means. Copy the contents to your module
53 folder and enable it at admin/build/modules.
54
55 --SETUP--
56 There are two groups of admin pages. The first deal with setup, the second with flag
57 administration. The first set are covered in this section.
58
59 Go to admin/user/nf_handshake. There you will see four tabs named 'Overview', 'Choose
60 CCK fields', 'Make groupings', and 'Misc settings'.
61
62 Upon first visit, the Overview page will be empty except for some minor instructions.
63 After this is all setup, this page will show you all used nodeprofile CCK fields and
64 their groupings, if you've made any. For now, click on 'Choose CCK fields'.
65
66 At the 'Choose CCK fields' page, you will see a simple drop down listing of all CCK
67 fields from your existing nodeprofile content types. If you have not created any
68 content types and then turned them into lonely nodes by assigning them a population
69 maximum of 1, and then checking the box to make it a nodeprofile type, then this page
70 may take a dump and give you an error.
71
72 If you have created your nodeprofile types correctly, you may select one CCK field at
73 a time and then click the 'Add CCK field' button. The added fields will be presented
74 in a table above the drop down list and will show the content type it came from and
75 the field name.
76
77 If you return to the 'Overview' tab, your selections will now be listed. Next click
78 on the 'Make groupings' tab. Groupings are NOT required. They exist for one purpose
79 only - if you have several content types that contain similar fields and which will
80 not all be used by a given user but one of them will be used by that user and where
81 all content types will be used by at least one user, then you want to make a grouping.
82 Did I lose you there? Let me explain the use case for which this was created and it
83 should become clear.
84
85 If you are using my nf_registration_mod module, then you will be able to create as
86 many 'Membership types' as you like. These membership types collect different info
87 from your users depending on the nodeprofile pageroutes you setup [for more details
88 on this, see the README for the nf_registration_mod module]. In most cases, you
89 will have created several content types that collect similar, but differing info.
90 This may be information that you wish your users to share among themselves. Unless
91 you group these similar-but-different CCK fields on this 'Make groupings' tab, they
92 will not be able to share that information.
93
94 A concrete example - Let's say you have two 'Membership Types'. The first is for
95 users from the U.S. The second is for international users. Then let's say you have
96 used my CCK_address module in creating two content types. The first content type
97 will be used for the U.S. member registration and will use a dropdown of the 50
98 States. This is one kind of CCK_address field. The second content type will be used
99 for the international member registration and all fields will be text fields for
100 their addresses. This is a different kind of CCK_address field. After you add these
101 cck fields using the previous tab, those users who created U.S. registration info
102 will be able to share it with others from the U.S., but not international users.
103
104 SO- on the 'Make groupings' page, you can type into the text field the name you
105 want for the grouping. Continuing our example, you would type 'Address'. Then,
106 expanding the fieldset that is created, you would add the fields you want to group.
107 In this drop down, labeled 'fields:', you will notice that the listing is different
108 from that on the previous tab. In this listing, you have contenttype::fieldname.
109 You would select the US_REG::address field and INT_REG::address field for our
110 example if that is how you named your content types and the fields (machine name)
111 for the addresses. Then, all users with addresses will be able to share their address
112 with other users regardless of which content type they filled out as part of their
113 registration.
114
115 If you do not use the nf_registration_mod module, you probably may not ever need this.
116 However, if you have a case where you want users to expose sets of fields together,
117 you could use this for that I suppose. I can't think of a use case for that.
118
119 Clicking on the last tab, 'Misc settings', you will find four items. The first is the
120 time that an 'acceptor' has to respond to a handshake before it expires. When a
121 handshake is initiated, it is given a flag of 'Pending' which signifies that the
122 'acceptor' has not yet looked at the handshake. The 'acceptor' may then look at that
123 handshake and either respond, or choose to respond later. If they choose to respond
124 later, the flag is changed to 'Reviewed'. Both of these flags mean that no choice has
125 been made. If the time you set for 'Initiation expiration' lapses, then the flag gets
126 changed to 'Expired'. The 'initiator' may then send another request if they so choose.
127 During the time that the flag is set to either 'Pending' or 'Reviewed', the initator
128 cannot initiate another handshake. This is to aid in the prevention of users pestering
129 each other.
130
131 The second setting, 'Rejection expiration' is for how old a 'Rejected' handshake must
132 be before the 'initiator' may reintitiate a handshake. Typically, you will want to set
133 this for some time longer than the 'Initiation expiration' and can be thought of as a
134 means to prevent frequent unwanted contact. The 'Rejection' flag is assigned to a
135 handshake when the 'acceptor' rejects the request, or when they revoke it after having
136 accepted it. The 'initiator' may also revoke the handshake, in which case they become
137 the 'acceptor' and the flag is set to 'Rejected'.
138
139 The third setting is for preventing users from handshaking with user 1. Presumably,
140 user 1 will not be interacting with users in the regular way users do and will not want
141 to be involved in handshakes. User 1 cannot initiate handshakes at all anyway as she/he
142 can always see a user's account page as per the normal Drupal user page. If user 1
143 wants to make handshakes, it is probably best to create and use an alternate account.
144 The default for this setting is checked.
145
146 The fourth setting is to prevent users from shaking hands with users that have been
147 assigned the 'administer handshakes' role. Usually, this will only be user 1 and so this
148 checkbox would be redundant. However, should you have more than one admin, you may
149 prevent users from shaking hands with them as well if they have been assigned this role.
150 The default for this setting is checked. Also note that any user assigned the 'administer
151 users' role cannot initiate handshakes and will see the regular user page as user 1 would.
152
153 One last thing -- THERE ARE PERMISSIONS THAT MUST BE ASSIGNED TO YOUR USERS -- they are
154 called 'initiate handshake', 'accept handshake' and 'view own handshakes'. You will
155 normally assign all three to all users. There are also administrative permissions called
156 'administer handshakes' and 'view handshakes'. The latter is not implemented yet.
157
158 That's it for setup. If you log in as a regular user, and then go to a user's page such as
159 user/5, everything should work. See the FEATURES section for what that should mean.
160
161 --FEATURES--
162 Read the SETUP section above to understand the setup and admin features of this module
163 not covered in the flag administration paragraphs below.
164
165 1) When a user tries to visit another user's profile page for the first time (such as
166 user/5), instead of the normal Drupal profile page, they will be presented with a choice
167 form. Their choices will be to 'Initiate a handshake', 'Contact user' or 'Cancel'.
168
169 a) Initiate a handshake - The user becomes the 'initiator'. If they do not abort the
170 process, two table entries will be made and they will be tracked by their user ID
171 as IUID. On the form they are presented with, they will be shown the fields from
172 their own nodeprofile nodes with a checkbox next to each. Those fields from non-
173 required content types that they have not filled out will be disabled (grayed out)
174 and will note that they haven't filled that data out yet. The user may check those
175 fields that they wish to share and that they hope the other user will agree to share.
176 Above that table, is a text area for the 'initiator' to specify a purpose for the
177 handshake. Submitting the form creates the table entries.
178
179 b) Contact user - This simply links to the site's standard contact method. If both
180 privatemsg and contact modules are enabled, the preference is for privatemsg. Contact
181 module can still be used by clicking the 'contact' tab on the user's profile view or
182 going to user/UID/contact.
183
184 c) Cancel - Returns the user to the site's main page.
185
186 2) A user primarily sees what is going on with their handshakes at
187 user/<THEIR UID>/nf_handshake/inbox. From here, they can see the contents of both their
188 inbox and their outbox. Accepting a handshake is explained below followed by descriptions
189 of the in/outboxes.
190
191 a) Accept a handshake - When a user is sent a handshake, it will show up in their
192 'handshake inbox' and will also show as a number on the 'Handshakes' menu
193 subitem of their 'My account' menu. The menu item will look like this:
194 Handshakes (X)(Y), where X is the number of new/non-reviewed handshakes and/or
195 flagged handshakes (see below) and Y is the number of reviewed handshakes.
196 [The inbox will be described below.]
197 If there are items that would show up in the number counts for X or Y, then a visit
198 to their user/UID/nf_handshake/inbox page will present them with both their in and
199 out boxes and the inbox will be expanded. Cliking on the 'reply' link next to a
200 given request will present the user with a form similar to the one filled out by
201 the 'initiator', but will contain the 'acceptor's' data, and not that of the
202 'initiator' since the handshake has not been finished. Only those fields that the
203 'initiator' selected will be presented as handshakes will go to the lowest common
204 denomination of fields selected.
205
206 The 'acceptor' has three choices and one sub-choice; these are 'Accept handshake',
207 [with or without adjusting the 'Duration'], 'Reject handshake', and 'Flag handshake'.
208
209 I) 'Accept handshake' is the most simple. In this case, after the user selects the
210 fields to share, they simply click this button without changing the default
211 'Duration' of 'Forever' (not really forever, but something like 30 years). This
212 completes the handshake so now when either user visits the other's page, they
213 will see the agreed-upon fields of the other party.
214 II) 'Accept handshake' with 'Duration' adjustment is straight forward. The user
215 simply selects the time unit ('Days', 'Weeks', 'Months' or 'Years') and the
216 number to go with it. The numbers are not currently dynamic, so they range from
217 0 to 31 at present. All numbers are valid even though some make more sense than
218 others depending on the unit choice. This will be changed at a leter date. The
219 result is the same as (I), above, but with an expiration date now set.
220 III) 'Reject handshake' is also simple and requires no other settings. This sets the
221 handshake flag to 'Rejected' and neither user will be able to see the other's
222 data, nor initiate another handshake until the 'Rejection expiration' time has
223 passed -OR- the 'acceptor' changes their mind (see below). This will also change
224 the user's page and will remove the button to initiate a handshake. Contact may
225 still be made through the site's chosen tool (contact or privatemsg).
226 IV) Expanding the 'Flag this request?' fieldset presents the user with a sub-form.
227 The user may choose from several flag options and must then comment as to why
228 they are flagging the handshake for administrative review. Clicking on 'Flag
229 handshake' finishes this process and send the handshake to the review queue.
230
231 b) Handshake inbox - The inbox is perhaps a little complicated, but it is hoped that
232 with regular use, it isn't too bad.
233
234 The inbox is divided into two sections, a top and a bottom. The top and bottom
235 contain those items that are requests for which the user is the 'acceptor'. These
236 are presented in four groups - 'New handshake requests', 'Reviewed handshake
237 requests', 'Flagged requests', and 'Handshake upgrade requests'. The data shown for
238 each of these is 'Status', 'Date initiated', 'From username', 'Stated purpose', and
239 'Operation'.
240
241 The status is the flag such as 'Pending', or 'Unanswered'. If the 'Operation' column
242 is not empty, there will be a text link which will take the user to a page where they
243 can affect the handshake in some way. Usually, new and reviewed handshakes will show
244 a 'reply' link, flags will show a 'reply' link as well, and so will upgrade requests.
245 The link for both new and reviewed handshakes is explained above in 'Accept a handshake'
246 while the others are explained below.
247
248 The bottom section of the inbox is for two groups of items. The first is those for
249 which the other user has requested a handshake 'Duration' extension. The second is for
250 the handshakes the user has rejected, but which have not yet expired and so can be
251 un-rejected. The data shown for each of these is 'Status', 'Expiration date', 'From
252 username', and 'Operation'.
253
254 The subsections are labeled in itallics in both the top and bottom sections. The groups
255 are either listed in the order discussed, or have a note letting the user know there
256 are no outstanding items in that group.
257
258 c) Handshake outbox - The outbox is found on the same page as the inbox and is a separate
259 field group. It looks nearly identical to the inbox, with a couple of exceptions. First,
260 neither new or reviewed handshake requests will have an operation as the ball is now in
261 the 'acceptor's' court for these. They are displayed here so that the user can know
262 whether the user they have initiated with has looked at the request yet or not. Flags
263 will have the same 'reply' option. Upgrade requests will likewise have no operation as
264 again, the ball is in the court of the 'acceptor'.
265
266 The bottom section of the outbox is also similar to that of the inbox, but there are no
267 operations possible for either 'Duration' extension requests or 'rejected' handshakes.
268 In the first case, this is the user that initiated the extension request and so logically
269 can't do another until the first has been responded to. The second case shows handshakes
270 which have been rejected. As only the 'acceptor' can change thier mind at a later date
271 (before expiration), this user can't do anything.
272
273 3) The other main page a user will visit is user/<THEIR UID>/nf_handshake/view_contacts. This
274 is described below under 'Handshake contacts'. Each user's profile page with which a user
275 has shaken hands will also naturally be visited by the user. These URLs look like user/UID.
276 As explained above, once a handshake is complete, the initiation/contact/cancel form is
277 replaced by a presentation of the known data of the user. This is described below as 'User
278 view' and is included in this section because both 'User view' and 'Handshake contacts'
279 share most of their operations. Consequently, these operations are also described in this
280 section.
281
282 a) User view - Once a handshake has been successfully completed (initiated and accepted),
283 users may visit each other's user page and will no longer see the form that makes them
284 choose to initiate a handshake or not. Instead, they will see:
285
286 I) A table of the other user's data with fieldnames on the left and data on the right.
287
288 II) The date the handshake was initiated and the date it will expire.
289
290 III) A listing of links for each operation that may be performed on this handshake.
291 These include 'Send this user a message', 'Revoke this handshake', 'Extend
292 expiration date', 'Request handshake upgrade (expose more fields)', and
293 'Downgrade handshake (hide fields)'. These operations are explained below.
294
295 b) Handshake contacts - This is a tab under the user's 'My account' menu item (i.e. their
296 own user page). This tab presents all of the users with which the user has an existing
297 handshake in a viewable condition (i.e. no problems preventing the viewing such as flags,
298 rejections, and so on). The table lists the 'Username', 'Created' date, 'Expires' date,
299 and 'Operations'. The table can be sorted according to the first three fields. The
300 username is a link to the user's page. The operations listed are- 'Contact' which will
301 send the user to the contact page of the site's messaging system (privatemsg or contact);
302 'Revoke' which will take the user to a confirmation page; either 'Extend expiration' or
303 'Request extension' depending on handshake role in this instance (in the first
304 case, a form for just the duration is shown and the result is ADDED to the existing
305 duarion. In the second case, the request is sent with no further input by the user);
306 'Request upgrade' where the user will be presented with a form similar to the initiation
307 request form; and 'Downgrade' where the user is presented with a form similar to the
308 acceptance form.
309
310 Of these operations (which are the same as those found on the 'User view' but with shorter
311 names) only a few need further explanation. See the following sections:
312
313 * Extend expiration/Extend expiration date
314 * Request upgrade/Request handshake upgrade (expose more fields)
315 * Downgrade/Downgrade handshake (hide fields)
316
317 c) Extend expiration/Extend expiration date - A user gets to this form three ways. First, as
318 an 'acceptor', they can click on either 'Extend expiration' from the 'Handshake contacts'
319 page, or the 'Extend expiration date' from the user of interest's profile page ('User view').
320 Also, there would appear a link in the 'Handshake inbox' labeled 'extend expiration' that
321 could be used as well.
322
323 All that is presented to the user is a small form which is allows them to choose a time unit
324 and a number from 0 to 31 as a multiplier. The result is added to the current expiration date.
325
326 d) Request upgrade/Request handshake upgrade (expose more fields) - This can be arrived at from
327 either the 'Handshake contacts' or the 'User view' pages respectively. This is a modified
328 version of the handshake initiation form. The user must state a purpose for the upgrade request.
329 The current fields are shown checked and disabled. All other available fields are shown. If the
330 user has not filled out all nodeprofile forms completely, some fields may be disabled and the
331 data column will read 'No Value Entered'. Fields which have values and which are not yet part
332 of the handshake will be checkable.
333
334 Submitting this form is similar to a regular handshake request except that the existing data is
335 still viewable to both parties while this request is pending.
336
337 One thing to note is that a request like this may reverse the roles of the users. The original
338 'initiator' will remain the 'initiator' if they are the one to propose this upgrade. However,
339 the original 'acceptor' will become the 'initiator' (which makes the original 'initiator'
340 become the new 'acceptor') if the 'acceptor' makes the request. All privileges of being an
341 'acceptor' are therfore transfered from one user to the other.
342
343 e) Downgrade/Downgrade handshake (hide fields) - This can be arrived at from either the
344 'Handshake contacts' or the 'User view' pages respectively. Either user can do this at any time.
345 The form presented is a simple table showing the user's current handshake fieldnames and their
346 values. A checkbox next to each is initially empty. The user chceks the boxes of those fields
347 to KEEP in the handshake. Empty boxes are for those items to be excluded going forward.
348
349 4) Flag administration is done via admin/user/nf_handshake_flags and is designed to handle users that
350 bother other users. What is there now is a first pass and may be changed in the future if needed.
351 There are three pages that the admin will use. The first I just named and is also the 'Overview'
352 tab. The second is the 'Decisions' tab and then there are the individual flag 'view' pages. All
353 are described in this section.
354
355 Possible user flags are : AGE_INAPPROPRIATE, SPAM, HARASSMENT, QUESTIONABLE_PURPOSE, or OTHER. At
356 a later date, these may be admin-specifiable. For now, they aren't. At almost 3700 lines of code,
357 this is a good enough first version.
358
359 a) Overview - This page shows the flags which have not had a decision pronounced upon them yet by
360 the admin and need to be dealt with. At a later date, a block will be created to allow the admin
361 to see what needs to be done without visiting the page.
362
363 The data is shown in a table. The columns listed are 'IUser', 'AUser', 'Purpose', 'Flag',
364 'Explanation', and 'Operations'. All columns except 'Operations' are sortable. 'IUser' is the
365 initiating user. 'AUser' is the accepting user. 'Purpose' is the purpose listed by the 'IUser'.
366 'Flag' is the flag the 'AUser' used. 'Explanation' is the reason the 'AUser' gave for flagging
367 the handshake request.
368
369 b) Decisions - This page shows the same data as the 'Overview' tab, but for those flagged handshakes
370 where the admin has pronounced a decision. An additional 'Decision' column is placed just before
371 the 'Operations' column and lists the admin flag that was the decision. These flags are described
372 in the next section - 'View'.
373
374 c) View - Currently, the only operation that can be performed on a flagged handshake is to view it.
375 A link in the 'Operations' column on either the 'Overview' or 'Decisions' page will take you to
376 that handshake's flag view page (admin/user/nf_handshake_flags/view/<IUID>/<AUID>). Moving from
377 the top of the display to the bottom, the following items are displayed:
378
379 I) General information - an unlabeled, single row of a table contains the IUser's username, the
380 AUser's username, the date the handshake was initiated, the expiration date, and the initial
381 date that the admin looked at this flag (and acted in some manner).
382
383 II) Purpose - The stated purpose of the IUser is shown.
384
385 III) User flag - The flag that the AUser used is shown.
386
387 IV) User flag explanation - The explanation the AUser gave as to why the handshake was flagged.
388
389 V) A table of the conversation between all parties involved (IUser, AUser, and admin(s)). The
390 table has three columns: 'Datestamp', 'UID', and 'Message'. How a message is created is described
391 below. The admin sees all messages in chronological order.
392
393 VI) Admin flag - The admin can choose between several action and decision flags. The action flags
394 are: 'Further admin review', 'Send to IUID for comment' and 'Send to AUID for comment'. The
395 decision flags are: 'T&S Violation', 'First warning', 'Second warning', 'Suspend user', and
396 'Alert parents'. It is likely that most sites will not have both parents and children on a
397 site and will not have the ability to alert parents of an issue. If that is your case, ignore
398 it. As with the user flags, these will likely become admin-specifiable.
399
400 * Further admin review - You should probably make a note, even if this requires waiting just
401 so you don't forget why you are waiting, or in the case you have multiple admins.
402 * Send to IUID for comment & Send to AUID for comment - You can allow the users to comment
403 regarding the flag. The fact that they have a handshake flagged shows in their in/outbox
404 immediately, so they will likely look for an opportunity to comment when they can. A link
405 will become active for them to click on in their respective in/outbox when you set this flag.
406 The user will only see their own side of the conversation along with the admin's so if there
407 are points the second user makes that you want the first to know about, add them to your note.
408 * T&S Violation - This is for when someone has violated your Terms of Service agreement or other
409 legal docs they agreed to in order to use your site. This is a note to you to follow up
410 according to what was laid down in those documents.
411 * First warning & Second warning - If you want to implement a warning system, you can. These
412 are for your information only. This will be shown to the user in their in/outbox, but no
413 other actions taken.
414 * Alert parents - Again, this for your info only as you will need to handle any parent alerting
415 yourself.
416 * Suspend user - This sets the user account of the 'initiator' to 'blocked'.
417
418 NOTE: Again, in the future, all flags will possibly be setable by admin. If/when that happens,
419 I would also like to provide a bunch of options/actions the admin can choose to happen
420 for each admin flag setting. For example, perhaps a user will not be blocked but could
421 lose the ability to create some kinds of content, send messages via privatemsg, can't
422 comment, or whatever. The admin would then check one or more option for each flag.
423
424 VII) Add a comment - This is where you add your comments regarding this flag issue.
425
426 VIII) Save/Cancel - Add your comment or back out of it.
427
428 d) User responses - Users will ba able to provide responses to questions and comments made to them
429 by the admin. Their 'Respond to flagging' page looks almost identical to the admin's 'View' page
430 as described above. The difference, of course, is that the user doesn't set admin flags or make
431 admin notes. Aside from renaming the fields to be more user friendly, the only difference is the
432 removal of the admin flag drop down list. The 'Message' field remains but is renames to 'Response'
433 The 'Save' and 'Cancel' buttons remain also. The messages that the user sees are only those from
434 the admin and himself/herself.
435
436 5) Privileges - As an 'acceptor', a user has certain privileges that the 'initiator' does not.
437 --The user may extend the duration of the handshake at any time.
438 --The user may un-reject a rejected handshake so long as it hasn't expired yet.
439
440 6) Did I forget something? Let me know. Post a documentation issue on the issue queue.
441
442 --UNINSTALL--
443 Disable and then uninstall via the normal Drupal procedure. This will remove the two
444 database tables and the
445
446 --CREDITS--
447 This module was created by Ryan Constantine (drupal id rconstantine)

  ViewVC Help
Powered by ViewVC 1.1.2