/[drupal]/contributions/modules/cck/cck.module
ViewVC logotype

Contents of /contributions/modules/cck/cck.module

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


Revision 1.22 - (show annotations) (download) (as text)
Thu Sep 3 16:15:27 2009 UTC (2 months, 3 weeks ago) by weitzman
Branch: MAIN
Changes since 1.21: +1 -7 lines
File MIME type: text/x-php
Remove devel_generate handling from cck. Now handled by devel_generate.module. Hurrah.
1 <?php
2 // $Id: cck.module,v 1.21 2009/09/03 12:16:23 karens Exp $
3 /**
4 * @file
5 * Allows administrators to associate custom fields to content types.
6 */
7
8 /**
9 * Implementation of hook_help().
10 */
11 function cck_help($path, $arg) {
12 switch ($path) {
13 case 'admin/help#cck':
14 // TODO Rewrite help to refer to only the appropriate functions and files for the new system.
15 return '';
16 case 'admin/build/fields':
17 return t('The list below shows all fields currently in use for easy reference.');
18
19 }
20 }
21
22 /**
23 * Implementation of hook_perm().
24 */
25 function cck_perm() {
26 return array(
27 // TODO : simplify machine name and update existing perms ?
28 'Use PHP input for field settings (dangerous - grant with care)' => array(
29 'title' => t('Use PHP input for field settings'),
30 'description' => t('Enter PHP code in the field for the field settings that allow it. Warning: Give to trusted roles only; this permission has security implications.'),
31 ),
32 );
33 }
34
35 /**
36 * Implementation of hook_init().
37 */
38 function cck_init() {
39 // TODO D7 : be smarter ?
40 drupal_add_css(drupal_get_path('module', 'cck') .'/theme/cck.css');
41 }
42
43 /**
44 * Implementation of hook_menu_alter().
45 */
46 function cck_menu_alter(&$items) {
47 // Customize the content types page with our own callback
48 $items['admin/build/types']['page callback'] = 'cck_types_overview';
49 $items['admin/build/types']['file'] = 'cck.admin.inc';
50 $items['admin/build/types']['file path'] = drupal_get_path('module', 'cck') .'/includes';
51 // TODO : same thing for admin/content/taxonomy
52 }
53
54 /**
55 * Implementation of hook_menu().
56 */
57 function cck_menu() {
58 // Set up menus for both content types and user settings.
59
60 $items = array();
61 $items['admin/build/fields'] = array(
62 'title' => 'Fields',
63 'description' => 'Manage custom fields that have been added to content types or users.',
64 'page callback' => 'cck_fields_list',
65 'access arguments' => array('administer content types'),
66 'type' => MENU_NORMAL_ITEM,
67 );
68 $items['admin/build/fields/list'] = array(
69 'title' => 'Field list',
70 'page callback' => 'cck_fields_list',
71 'access arguments' => array('administer content types'),
72 'type' => MENU_DEFAULT_LOCAL_TASK,
73 'weight' => 1,
74 );
75 // TODO D7 : remove, debug code
76 $items['admin/build/fields/field-info'] = array(
77 'title' => 'Field Info (debug)',
78 'page callback' => 'cck_debug_field_info',
79 'access arguments' => array('administer content types'),
80 'type' => MENU_LOCAL_TASK,
81 'weight' => 2,
82 );
83 $items['admin/build/types/field-info'] = array(
84 'title' => 'Field Info (debug)',
85 'page callback' => 'cck_debug_field_info',
86 'access arguments' => array('administer content types'),
87 'type' => MENU_LOCAL_TASK,
88 'weight' => 2,
89 );
90
91 // Make sure this doesn't fire until field_bundles is working,
92 // and tables are updated, needed to avoid errors on initial installation.
93 if (!defined('MAINTENANCE_MODE')) {
94 // Create tabs for all possible bundles.
95 foreach (field_info_fieldable_types() as $obj_type => $info) {
96 foreach ($info['bundles'] as $bundle_name => $bundle_info) {
97 if (isset($bundle_info['admin'])) {
98 // Extract informations from the bundle description.
99 $path = $bundle_info['admin']['path'];
100 $bundle_arg = isset($bundle_info['admin']['bundle argument']) ? $bundle_info['admin']['bundle argument'] : $bundle_name;
101 $access = array_intersect_key($bundle_info['admin'], drupal_map_assoc(array('access callback', 'access arguments')));
102
103 $items[$path .'/fields'] = array(
104 'title' => 'Manage fields',
105 'page callback' => 'drupal_get_form',
106 'page arguments' => array('cck_field_overview_form', $obj_type, $bundle_arg),
107 'type' => MENU_LOCAL_TASK,
108 'weight' => 1,
109 ) + $access;
110 // A dummy function to trigger a page refresh so that
111 // field menus get rebuilt correctly when new fields are added.
112 $items[$path .'/fields/refresh'] = array(
113 'title' => 'Refresh menu',
114 'page callback' => 'drupal_get_form',
115 'page arguments' => array('cck_field_menu_refresh', $obj_type, $bundle_arg),
116 'type' => MENU_CALLBACK,
117 'weight' => 1,
118 ) + $access;
119 $items[$path .'/display'] = array(
120 'title' => 'Display fields',
121 'page callback' => 'drupal_get_form',
122 'page arguments' => array('cck_display_overview_form', $obj_type, $bundle_arg),
123 'type' => MENU_LOCAL_TASK,
124 'weight' => 2,
125 ) + $access;
126
127 // 'Display fields' tab and context secondary tabs.
128 $tabs = cck_build_modes($obj_type);
129 foreach ($tabs as $key => $tab) {
130 $items[$path .'/display/'. $key] = array(
131 'title' => $tab['title'],
132 'page arguments' => array('cck_display_overview_form', $obj_type, $bundle_arg, $key),
133 'type' => $key == 'basic' ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK,
134 'weight' => $key == 'basic' ? 0 : 1,
135 ) + $access;
136 }
137
138 // Add tabs for any instances that are already created.
139 $instances = field_info_instances($bundle_name);
140 foreach ($instances as $instance) {
141 $field_name = $instance['field_name'];
142 $items[$path .'/fields/'. $field_name] = array(
143 'title' => $instance['label'],
144 'page callback' => 'drupal_get_form',
145 'page arguments' => array('cck_field_edit_form', $obj_type, $bundle_arg, $field_name),
146 'type' => MENU_LOCAL_TASK,
147 ) + $access;
148 $items[$path .'/fields/'. $field_name .'/edit'] = array(
149 'title' => 'Configure instance settings',
150 'page callback' => 'drupal_get_form',
151 'page arguments' => array('cck_field_edit_form', $obj_type, $bundle_arg, $field_name),
152 'type' => MENU_DEFAULT_LOCAL_TASK,
153 ) + $access;
154 $items[$path .'/fields/'. $field_name .'/field-settings'] = array(
155 'title' => 'Configure field settings',
156 'page callback' => 'drupal_get_form',
157 'page arguments' => array('cck_field_settings_form', $obj_type, $bundle_arg, $field_name),
158 'type' => MENU_LOCAL_TASK,
159 ) + $access;
160 $items[$path .'/fields/'. $field_name .'/widget-type'] = array(
161 'title' => 'Change widget type',
162 'page callback' => 'drupal_get_form',
163 'page arguments' => array('cck_widget_type_form', $obj_type, $bundle_arg, $field_name),
164 'type' => MENU_LOCAL_TASK,
165 ) + $access;
166 $items[$path .'/fields/'. $field_name .'/remove'] = array(
167 'title' => 'Remove instance',
168 'page callback' => 'drupal_get_form',
169 'page arguments' => array('cck_field_remove_form', $obj_type, $bundle_arg, $field_name),
170 'type' => MENU_LOCAL_TASK,
171 ) + $access;
172 }
173 }
174 }
175 }
176 }
177 return $items;
178 }
179
180 function cck_debug_field_info() {
181 if (drupal_function_exists('dsm')) {
182 module_load_include('inc', 'field', 'field.info');
183 dsm(_field_info_collate_types());
184 dsm(_field_info_collate_fields());
185 return '';
186 }
187 else {
188 return t('You need to enable devel.module to see this page');
189 }
190 }
191
192 /**
193 * Implementation of hook_theme().
194 */
195 function cck_theme() {
196 $path = drupal_get_path('module', 'cck') .'/theme';
197 require_once "./$path/theme.inc";
198
199 return array(
200 'cck_field_overview_form' => array(
201 'template' => 'cck-admin-field-overview-form',
202 'path' => $path,
203 'arguments' => array('form' => NULL),
204 ),
205 'cck_display_overview_form' => array(
206 'template' => 'cck-admin-display-overview-form',
207 'path' => $path,
208 'arguments' => array('form' => NULL),
209 ),
210 );
211 }
212
213 /**
214 * Implementation of hook_field_attach_form().
215 */
216 function cck_field_attach_form($obj_type, &$object, &$form, &$form_state) {
217 // Add identifier to the object to be used to alter extra fields in the form.
218 list($id, $vid, $bundle) = field_attach_extract_ids($obj_type, $object);
219 $form['#fieldable'] = TRUE;
220 $form['#bundle'] = $bundle;
221 $form['#pre_render'][] = 'cck_alter_extra_weights';
222 $form['#cck_extra_fields'] = cck_extra_field_values($bundle);
223 }
224
225 /**
226 * Implementation of hook_field_attach_view().
227 */
228 function cck_field_attach_view($output, $obj_type, &$object, $teaser) {
229 // Add identifier to the object to be used to alter extra fields in the view.
230 list($id, $vid, $bundle) = field_attach_extract_ids($obj_type, $object);
231 $object->content['#fieldable'] = TRUE;
232 $object->content['#bundle'] = $bundle;
233
234 // TODO : doesn't work for user profiles, because template_preprocess_user_profile()
235 // uses its own hack to generate separate template variables, and never calls
236 // drupal_render() on the whole object. Depending on how this evolves (or not),
237 // we might need to move the #pre_render callback on each separate element.
238 $object->content['#pre_render'][] = 'cck_alter_extra_weights';
239 $object->content['#cck_extra_fields'] = cck_extra_field_values($bundle);
240
241 return $output;
242 }
243
244 /**
245 * Implementation of hook_field_attach_pre_insert().
246 */
247 function cck_field_attach_pre_insert($obj_type, &$object) {
248 // Add identifier to the object to be used to alter extra fields in the view.
249 list($id, $vid, $bundle) = field_attach_extract_ids($obj_type, $object);
250 }
251
252 /**
253 * Pre-render callback to adjust weights of non-CCK fields.
254 */
255 function cck_alter_extra_weights($elements) {
256 if (isset($elements['#cck_extra_fields'])) {
257 foreach ($elements['#cck_extra_fields'] as $key => $value) {
258 // Some core 'fields' use a different key in node forms and in 'view'
259 // render arrays. Check we're not on a form first.
260 if (!isset($elements['#build_id']) && isset($value['view']) && isset($elements[$value['view']])) {
261 $elements[$value['view']]['#weight'] = $value['weight'];
262 }
263 elseif (isset($elements[$key])) {
264 $elements[$key]['#weight'] = $value['weight'];
265 }
266 }
267 }
268 return $elements;
269 }
270
271 /**
272 * Implementation of hook_cck_extra_fields.
273 */
274 function cck_cck_extra_fields($bundle_name) {
275 if ($bundle_name == 'user') {
276 return _cck_user_extra_fields();
277 }
278 // TODO: we'll need to recognize other non single-mundle fieldable types.
279 else {
280 return _cck_node_extra_fields($bundle_name);
281 }
282 }
283
284 // TODO Add other user elements here.
285 // How to do this for users? The form elements are totally different
286 // than the view elements.
287 function _cck_user_extra_fields() {
288 $extra = array();
289 $extra['account'] = array(
290 'label' => 'User name and password',
291 'description' => t('User module form element'),
292 'weight' => -10
293 );
294 $extra['timezone'] = array(
295 'label' => 'Timezone',
296 'description' => t('User module form element.'),
297 'weight' => 6
298 );
299 $extra['summary'] = array(
300 'label' => 'History',
301 'description' => t('User module view element.'),
302 'weight' => 5
303 );
304 return $extra;
305 }
306
307 function _cck_node_extra_fields($type_name) {
308 $extra = array();
309 if ($type = node_type_get_type($type_name)) {
310 if ($type->has_title) {
311 $extra['title'] = array(
312 'label' => $type->title_label,
313 'description' => t('Node module element.'),
314 'weight' => -5
315 );
316 }
317 $extra['revision_information'] = array(
318 'label' => t('Revision information'),
319 'description' => t('Node module form.'),
320 'weight' => 20
321 );
322 $extra['author'] = array(
323 'label' => t('Authoring information'),
324 'description' => t('Node module form.'),
325 'weight' => 20
326 );
327 $extra['options'] = array(
328 'label' => t('Publishing options'),
329 'description' => t('Node module form.'),
330 'weight' => 25
331 );
332 if (module_exists('comment') && variable_get("comment_$type_name", 2) != 0) {
333 $extra['comment_settings'] = array(
334 'label' => t('Comment settings'),
335 'description' => t('Comment module form.'),
336 'weight' => 30
337 );
338 }
339 if (module_exists('locale') && variable_get("language_content_type_$type_name", 0)) {
340 $extra['language'] = array(
341 'label' => t('Language'),
342 'description' => t('Locale module element.'),
343 'weight' => 0
344 );
345 }
346 if (module_exists('menu')) {
347 $extra['menu'] = array(
348 'label' => t('Menu settings'),
349 'description' => t('Menu module element.'),
350 'weight' => -2
351 );
352 }
353 if (module_exists('taxonomy') && taxonomy_get_vocabularies($type_name)) {
354 $extra['taxonomy'] = array(
355 'label' => t('Taxonomy'),
356 'description' => t('Taxonomy module element.'),
357 'weight' => -3
358 );
359 }
360 if (module_exists('book')) {
361 $extra['book'] = array(
362 'label' => t('Book'),
363 'description' => t('Book module element.'),
364 'weight' => 10
365 );
366 }
367 if ($type_name == 'poll' && module_exists('poll')) {
368 $extra['title'] = array(
369 'label' => t('Poll title'),
370 'description' => t('Poll module title.'),
371 'weight' => -5
372 );
373 $extra['choice_wrapper'] = array(
374 'label' => t('Poll choices'),
375 'description' => t('Poll module choices.'),
376 'weight' => -4
377 );
378 $extra['settings'] = array(
379 'label' => t('Poll settings'),
380 'description' => t('Poll module settings.'),
381 'weight' => -3
382 );
383 }
384 if (module_exists('upload') && variable_get("upload_$type_name", TRUE)) {
385 $extra['attachments'] = array(
386 'label' => t('File attachments'),
387 'description' => t('Upload module element.'),
388 'weight' => 30,
389 'view' => 'files'
390 );
391 }
392 }
393
394 return $extra;
395 }
396
397 /**
398 * Retrieve the user-defined weight for non-CCK node 'fields'.
399 *
400 * CCK's 'Manage fields' page lets users reorder node fields, including non-CCK
401 * items (body, taxonomy, other hook_nodeapi-added elements by contrib modules...).
402 * Contrib modules that want to have their 'fields' supported need to expose
403 * them with hook_cck_extra_fields, and use this function to retrieve the
404 * user-defined weight.
405 *
406 * @param $type_name
407 * The content type name.
408 * @param $pseudo_field_name
409 * The name of the 'field'.
410 * @return
411 * The weight for the 'field', respecting the user settings stored
412 * by field.module.
413 */
414 function cck_extra_field_weight($bundle_name, $pseudo_field_name) {
415 $extra = cck_extra_field_values($bundle_name);
416 if (isset($extra[$pseudo_field_name])) {
417 return $extra[$pseudo_field_name]['weight'];
418 }
419 }
420
421 function cck_extra_field_values($bundle_name) {
422 static $info = array();
423
424 if (empty($info)) {
425 $info = array();
426 $bundles = field_info_bundles();
427 foreach ($bundles as $name => $bundle_info) {
428 // Gather information about non-CCK 'fields'.
429 $extra = module_invoke_all('cck_extra_fields', $name);
430 drupal_alter('cck_extra_fields', $extra, $name);
431
432 // Add saved weights.
433 foreach (variable_get('cck_extra_weights_'. $name, array()) as $key => $value) {
434 // Some stored entries might not exist anymore, for instance if uploads
435 // have been disabled, or vocabularies removed...
436 if (isset($extra[$key])) {
437 $extra[$key]['weight'] = $value;
438 }
439 }
440 $info[$name] = $extra;
441 }
442 }
443 if (array_key_exists($bundle_name, $info)) {
444 return $info[$bundle_name];
445 }
446 else {
447 return array();
448 }
449 }
450
451
452 function cck_build_modes($obj_type, $tab_selector = NULL) {
453 static $info;
454
455 if (!isset($info[$obj_type])) {
456 $info[$obj_type] = module_invoke_all('cck_build_modes');
457 // Collect titles, and filter out non active modes.
458 $active_modes = field_build_modes($obj_type);
459 foreach ($info[$obj_type] as $tab => $values) {
460 $modes = array();
461 foreach ($info[$obj_type][$tab]['build modes'] as $mode) {
462 if (isset($active_modes[$mode])) {
463 $modes[$mode] = $active_modes[$mode];
464 }
465 }
466 if ($modes) {
467 $info[$obj_type][$tab]['build modes'] = $modes;
468 }
469 else {
470 unset($info[$obj_type][$tab]);
471 }
472 }
473 }
474 if ($tab_selector) {
475 return isset($info[$obj_type][$tab_selector]) ? $info[$obj_type][$tab_selector]['build modes'] : array();
476 }
477 else {
478 return $info[$obj_type];
479 }
480 }
481
482 /**
483 * Implementation of hook_cck_build_modes(), on behalf of other core modules.
484 *
485 * @return
486 * An array describing the build modes defined by the module, grouped by tabs.
487 *
488 * Expected format:
489 * array(
490 * // A module can add its render modes to a tab defined by another module.
491 * 'tab1' => array(
492 * 'title' => t('The human-readable title of the tab'),
493 * 'build modes' => array('mymodule_mode1', 'mymodule_mode2'),
494 * ),
495 * 'tab2' => array(
496 * // ...
497 * ),
498 * );
499 */
500 function cck_cck_build_modes() {
501 $modes = array(
502 'basic' => array(
503 'title' => t('Basic'),
504 'build modes' => array('teaser', 'full'),
505 ),
506 'rss' => array(
507 'title' => t('RSS'),
508 'build modes' => array('rss'),
509 ),
510 'print' => array(
511 'title' => t('Print'),
512 'build modes' => array('print'),
513 ),
514 'search' => array(
515 'title' => t('Search'),
516 'build modes' => array('search_index', 'search_result'),
517 ),
518 );
519 return $modes;
520 }
521
522 /**
523 * Implementation of hook_node_type().
524 *
525 * TODO D7: This should be done in hook_field_[create|rename|delete]_bundle().
526 */
527 function cck_node_type($op, $info) {
528 switch ($op) {
529 case 'insert':
530 // TODO Fix this.
531 // Trying to get the Manage Fields screen for a new content type to
532 // work immediately after the new type is created. Even this won't do it,
533 // MF screen is still 'Page not found' after the new type is created.
534 menu_rebuild();
535 field_cache_clear();
536 break;
537
538 case 'update':
539 if (isset($info->old_type) && $info->old_type !== $info->type && $extra = variable_get('cck_extra_weights_'. $info->old_type, array())) {
540 variable_set('cck_extra_weights_'. $info->type, $extra);
541 variable_del('cck_extra_weights_'. $info->old_type);
542 }
543 break;
544 case 'delete':
545 variable_del('cck_extra_weights_'. $info->type);
546 break;
547 }
548 }
549
550 /**
551 * Helper function to create the right administration path for a bundle.
552 */
553 function _cck_bundle_admin_path($bundle_name) {
554 $bundles = field_info_bundles();
555 $bundle_info = $bundles[$bundle_name];
556 // The 'admin' key is not always available
557 // on the module update page.
558 if (!array_key_exists('admin', $bundle_info)) {
559 return;
560 }
561 return isset($bundle_info['admin']['real path']) ? $bundle_info['admin']['real path'] : $bundle_info['admin']['path'];
562 }
563
564 /**
565 * We store all settings in a flat text field, but some settings
566 * will be arrays that need to be serialized and unserialized,
567 * like the default_value.
568 */
569 function cck_serialized_settings() {
570 return array('default_value');
571 }
572
573 /**
574 * Helper function to retrieve field settings stored by CCK.
575 *
576 * CCK uses the 'cck_field_settings' table to store custom settings
577 * not used by core.
578 *
579 * Field settings will have no $instance nor a db bundle column.
580 */
581 function cck_field_get_setting($setting, $setting_type, $field, $instance = NULL) {
582 if ($setting_type == 'field' || empty($instance)) {
583 $value = db_select('cck_field_settings', 'fs')->fields('fs', array('setting_option'))
584 ->condition('fs.setting', $setting)
585 ->condition('fs.setting_type', $setting_type)
586 ->condition('fs.field_name', $field['field_name'])
587 ->execute()->fetchField();
588 }
589 else {
590 $value = db_select('cck_field_settings', 'fs')->fields('fs', array('setting_option'))
591 ->condition('fs.setting', $setting)
592 ->condition('fs.setting_type', $setting_type)
593 ->condition('fs.field_name', $field['field_name'])
594 ->condition('fs.bundle', $instance['bundle'])
595 ->execute()->fetchField();
596 }
597
598 if (in_array($setting, cck_serialized_settings())) {
599 $value = unserialize($value);
600 }
601 return $value;
602 }
603
604 /**
605 * Helper function to set field settings stored by CCK.
606 *
607 * CCK uses the 'cck_field_settings' table to store custom settings
608 * not used by core.
609 *
610 * Field settings will have no $instance nor a db bundle column.
611 */
612 function cck_field_set_setting($setting, $setting_type, $value, $field, $instance = NULL) {
613 // Delete any prior values.
614 $bundle = ($setting_type == 'field' || empty($instance)) ? NULL : $instance['bundle'];
615 if ($setting_type == 'field' || empty($instance)) {
616 db_delete('cck_field_settings')
617 ->condition('field_name', $field['field_name'])
618 ->condition('setting', $setting)
619 ->condition('setting_type', $setting_type)
620 ->execute();
621 }
622 else {
623 db_delete('cck_field_settings')
624 ->condition('field_name', $field['field_name'])
625 ->condition('bundle', $bundle)
626 ->condition('setting', $setting)
627 ->condition('setting_type', $setting_type)
628 ->execute();
629 }
630 // Create the new values.
631 if (in_array($setting, cck_serialized_settings())) {
632 $value = serialize($value);
633 }
634 $record = array(
635 'field_name' => $field['field_name'],
636 'bundle' => $bundle,
637 'setting' => $setting,
638 'setting_option' => $value,
639 'setting_type' => $setting_type,
640 );
641 $primary_keys = array();
642 drupal_write_record('cck_field_settings', $record, $primary_keys);
643 }
644
645 /**
646 * Implementation of hook_field_default_value().
647 *
648 * Helper function to return the correct default value for a field
649 * on behalf of fields managed in the CCK UI.
650 *
651 * @param $obj_type
652 * The object type.
653 * @param $object
654 * The object.
655 * @param $field
656 * The field array.
657 * @param $instance
658 * The field array.
659 * @return
660 * The default value for that field.
661 */
662 function cck_field_default_value($obj_type, $object, $field, $instance) {
663 $default_value = array();
664 $default_setting = cck_field_get_setting('default_value', 'instance', $field, $instance);
665 $default_setting_php = cck_field_get_setting('default_value_php', 'instance', $field, $instance);
666 if (!empty($default_setting_php)) {
667 ob_start();
668 $result = eval($default_setting_php);
669 if (is_array($result)) {
670 $default_value = $result;
671 }
672 }
673 elseif (!empty($default_setting)) {
674 $default_value = $default_setting;
675 }
676 return (array) $default_value;
677 }
678
679 /**
680 * Helper function to identify inactive fields.
681 */
682 function cck_inactive_fields($type_name = NULL) {
683 // module_load_include('inc', 'field', 'includes/field.crud');
684 // if (!empty($type_name)) {
685 // $param = array('type_name' => $type_name);
686 // $inactive = array($type_name => array());
687 // }
688 // else {
689 // $param = array();
690 // $inactive = array();
691 // }
692 // $all = field_field_instance_read($param, TRUE);
693 // $active = array_keys(field_fields());
694 // foreach ($all as $field) {
695 // if (!in_array($field['field_name'], $active)) {
696 // $inactive[$field['type_name']][$field['field_name']] = field_field_instance_expand($field);
697 // }
698 // }
699 // if (!empty($type_name)) {
700 // return $inactive[$type_name];
701 // }
702 // return $inactive;
703 }

  ViewVC Help
Powered by ViewVC 1.1.2